2016-11-10

I recently decided I wanted to understand better what
Cross-Site Scripting and Cross-Site Request Forgery were,
and how they compared to that
classic vulnerability, SQL Injection.

I also looked into some ways that sites protect against
those attacks.

Vulnerabilities

SQL Injection

SQL Injection is a classic vulnerability. It probably dates
back almost to punch cards.

Suppose a program uses data from a user in a database query.

For example, the company web site lets users enter a name
of an employee, free-form, and the site will search for that
employee and display their contact information.

A naive site might build a SQL query as a string using code like this, including
whatever the user entered as NAME:

If NAME is "John Doe", then we get:

which is fine. But suppose someone types this into the NAME
field:

then the site will end up building this query:

which might delete the whole employee directory. It could instead do
something less obvious but even more destructive in the long run.

This is called a SQL Injection attack, because the attacker
is able to inject whatever they want into a SQL command that the
site then executes.

Cross Site Scripting

Cross Site Scripting, or XSS, is a similar idea. If an attacker
can get their Javascript code embedded into a page on the site,
so that it runs whenever someone visits that page, then the
attacker's code can do anything on that site using the privileges
of the user.

For example, maybe an attacker posts a comment on a page
that looks to users like:

but what they really put in their comment was:

If the site displays comments by just embedding the text of the
comment in the page, then whenever a user views the page, the browser
will run the Javascript - it has no way to know this particular
Javascript on the page was written by an attacker rather than the
people running the site.

This Javascript is running in a page that was served by the site, so
it can do pretty much anything the user who is currently logged in can
do. It can fetch all their data and send it somewhere else, or if the
user is particularly privileged, do something more destructive, or
create a new user with similar privileges and send its credentials
somewhere the bad guy can retrieve them and use them later, even after
the vulnerability has been discovered and fixed.

So, clearly, a site that accepts data uploaded by users, stores it,
and then displays it, needs to be careful of what's in that
data.

But even a site that doesn't store any user data can be vulnerable.
Suppose a site lets users search by going to
http://example.com/search?q=somethingtosearchfor (Google does
something similar to this), and then displays a page showing what
the search string was and what the results were. An attacker can embed
Javascript into the search term part of that link, put that link
somewhere people might click on it, and maybe label it "Cute Kitten
Pictures". When a user clicks the link to see the kittens, her browser
visits the site and tries the search. It'll probably fail, but if the
site embeds the search term in the results page unchanged (which Google
doesn't do), the attacker's code will run.

Why is it called Cross-Site Scripting? Because it allows an attacker
to run their script on a site they don't control.

CSRF

Cross Site Request Forgeries

The essence of a CSRF attack is a malicious site making a request to
another site, the site under attack, using the current user's
permissions.

That last XSS example could also be considered a CSRF attack.

As another, extreme example, suppose a site implemented account
deletion by having a logged-in user visit (GET)
/delete-my-account. Then all a malicious site would have to do is
link to yoursite.com/delete-my-account and if a user who was
logged into yoursite.com clicked the link, they'd make the
/delete-my-account request and their account would be gone.

In a more sophisticated attack, a malicious site can build a form
or make AJAX calls that do a POST or other request to the site under
attack when a user visits the malicious site.

Protecting against vulnerabilities

Protections in the server and application

SQL Injection protection

Django's ORM, and most database interfaces I've seen, provide a way
to specify parameters to queries directly, rather than having the
programmer build the whole query as a string. Then the database API
can do whatever is appropriate to protect against malicious content
in the parameters.

XSS protection

Django templates apply "escaping" to all embedded content by default.
This marks characters that ordinarily would be special to the browser,
like "<", so that the browser will just display the "<" instead of
interpreting it. That means if content includes "<SCRIPT>...</SCRIPT>",
instead of the browser executing the "..." part, the user will just
see "<SCRIPT>...</SCRIPT>" on the page.

CSRF protection

We obviously can't disable links to other sites - that would break
the entire web. So to protect against CSRF, we have to make sure
that another site cannot build any request to our site that would
actually do anything harmful.

The first level of protection is simply making sure that request
methods like GET don't change anything, or display unvalidated
data. That blocks the simplest possible attack, where a simple
link from another site causes harm when followed.

A malicious site can still easily build a form or make AJAX calls that
do a POST or other request to the site under attack, so how do we
protect against that?

Django's protection is to always include a user-specific, unguessable
string as part of such requests, and reject any such request that
doesn't include it. This string is called the CSRF token. Any form on
a Django site that does a POST etc has to include it as one of the
submitted parameters. Since the malicious site doesn't know the token,
it cannot generate a malicious POST request that the Django site will
pay any attention to.

Protections in the browser

Modern browsers implement a number of protections against these
kinds of attacks.

"But wait", I hear you say. "How can I trust browsers to protect my
application, when I have no control over the browser being used?"

I frequently have to remind myself that browser protections are
designed to protect the user sitting in front of the browser, who
for these attacks, is the victim, not the attacker. The user
doesn't want their account hacked on your site any more than you
do, and these browser protections help keep the attacker from
doing that to the user, and incidentally to your site.

Same-origin security policy

All modern browsers implement a form of Same Origin Policy, which I'll
call SOP. In some cases, it prevents a page loaded from one site from
accessing resources on other sites, that is, resources that don't have
the same origin.

The most important thing about SOP is that AJAX calls are restricted
by default. Since an AJAX call can use POST and other data-modifying
HTTP requests, and would send along the user's cookies for the target
site, an AJAX call could do anything it wanted using the user's
permissions on the target site. So browsers don't allow it.

What kind of attack does this prevent? Suppose the attacker sets up a
site with lots of cute kitten pictures, and gets a user victim to
access it. Without SOP, pages on that site could run Javascript that
made AJAX calls (in the background) to the user's bank. Such calls
would send along whatever cookies the user's browser had stored for
the bank site, so the bank would treat them as coming from the user.
But with SOP, the user's browser won't let those AJAX calls to another
site happen. They can only talk to the attacker's own site, which
doesn't do the attacker any good.

CSP

Content Security Policy (CSP)

CSP is a newer mechanism that browsers can use to better
protect from these kinds of attacks.

If a response includes the CSP header, then by default the browser
will not allow any inline javascript, CSS, or use of javascript
"eval" on the page. This blocks many forms of XSS. Even if an
attacker manages to trick the server into including malicious
code on the page, the browser will refuse to execute it.

For example, if someone uploads a comment that includes a
<script> tag with some Javascript, and the site includes that
in the page, the browser just won't run the Javascript.

Conclusion

I've barely touched the surface on these topics here.
Any web developer ought to have at least a general knowledge
of common vulnerabilities, if only to know what areas might
require more research on a given project.

A reasonable place to start is Django's
Security Overview.

The OWASP Top Ten
is a list of ten of the most commonly exploited vulnerabilities, with
links to more information about each. The ones I've described here
are numbers 1, 3, and 8 on the list, so you can see there are many
more to be aware of.

Show more