In web applications, if you are using cookies for storing authentication state, you should be worrying about Cross Site Request Forgery (CSRF). In short, when using cookies, other sites can create an HTML form that submits to your backend. When your browser submits that form, it will attach any cookies it has that are associated with the URL that the form is submitted to. Without any steps taken to mitigate this, a malicious third party could create a form on their site that performs an action on application, maybe as harmless as following them on a site, or as malicious as deleting your account or transferring funds. OWASP has more details on CSRF attacks as well.
Typical CSRF prevention
The way that most applications mitigate CSRF attacks is by utilizing a synchronizer CSRF token that is stored in a hidden HTML input in the form which matches a token in the current user’s session. In short, malicious forms will be lacking this token and will be rejected. More details on token based mitigation are covered in this OWASP page.
What about Single Page applications? Is a JSON only API vulnerable?
CSRF tokens work well for server side rendered applications (SSR), since the HTML generated on the server can securely include the token that is in the session cookie. But what about single page application like Ember? Can you craft an HTML form to submit a valid request to a JSON based API? The answer is yes it is possible.
Ok, so how can we secure this API backend without a CSRF token?
Enter Referer/Origin header verification
With the exception of
GET requests, when your browser submits a
request, it attaches both a
Referer (that typo is historical) and
Origin header. The
Origin header is a bit newer, it was originally
introduced for Cross Origin Resource Sharing (CORS), but has been
repurposed for CSRF mitigation as well. We can use the
Origin header to verify that the request originated from the domain we
expect. In this case, I prefer the
Origin header. When a request
originates at an HTTPS page and is made against an HTTP page, the
Referer header is dropped, while the
Origin header will continue to
be sent. Both OWASP and Mozilla talk
about the validity of using the
Origin header as a way to mitigate
Places where CSRF prevention fails
No matter how good your CSRF prevention is, there are other vectors that
will open your application to malicious requests. If your session cookie
execute on your site, you have a couple of problems. When not using
your session cookies. At that point, this third party could forge any
header it needs to, and then include the session cookie to automate requests
against your server, so it could bypass the
Origin check. They could
also replace the cookie in their browser with another person’s cookie
that they stole, and use your site as that user, bypassing CSRF Tokens.
If your cookie is marked as
HTTPOnly, they can still use malicious
with either the necessary CSRF token or
Ok, so why all this information about CSRF mitigation?
At DockYard, we produce Ember applications for our clients. Since Ember
is a single page application,
Origin header checking is the best way
we can protect any backends we produce. To the end, I recently published
Plug you can add to your applications pipeline to only
allow requests from
Origins you expect:
plug VerifyOrigin, ["https://example.com"]
The plug expects a list of valid
Origin URLs. If the request does not
Origin header that matches your list, then it returns a
400 Bad Request response to the client. Simple CSRF mitigation for your
Phoenix app is at your fingertips!
A special thanks to Craig Ingram, who I consulted with multiple times when coming up with this plug!