How do I implement CSRF protection using built-in Express middleware for HTTP GET requests?
For instance, user logout often made via GET request and actually change state of web application so it should be protected against CSRF.
Unfortunately, CSRF middleware ignores HTTP GET and doesn't export helpers to manually check token.
BTW, they now expose the way of explicitly setting which methods to ignore
app.use(csurf({ignoreMethods: ['HEAD', 'OPTIONS']}))
You could create a custom fork of the Connect CSRF middleware that would not ignore GET requests. The line that does so is here: https://github.com/senchalabs/connect/blob/master/lib/middleware/csrf.js#L76
However, don't do it. GET requests are safe and idempotent: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
In other words, no one is worried that a malicious web script might log them out from a site. The worry is that it could post spam in your name or transfer money out of your bank account. That's what you need CSRF to protect against. Lots more info here: http://en.wikipedia.org/wiki/Csrf
Related
I was reading up on CSRF and came across this question: https://security.stackexchange.com/questions/36671/csrf-token-in-get-request
Multiple people online have also seem to indicate that one should not protect GET requests against CSRF. However, I am confused by why.
If your GET request contains sensitive information (like say personal info for a user), then you would want to protect it against CSRF right? Otherwise an attacker can steal personal info.
I get that you shouldn't include the token in the GET URL because those may be logged. However, can't you just include them in a custom header?
CRSF attacks are blind. They typically send a request without being able to read the result of the action. The reason here is the Same Origin Policy.
SOP prevents you from reading RESPONSES received by other origins, meaning that you can't access the private stuff anyways.
CRSF protection instead protects REQUESTS in the sense that it adds a token which symbolizes that the request is started by the web app itself
Is it possible to apply CSRF token check selectively on certain requests/routes? If I want to apply for 4 out of 6 post requests used in my application, will it be possible? Has CSRF token any relevance for GET request? As reference document for sailsjs says "When CSRF protection is enabled, all non-GET requests to the Sails server must be accompanied by a special token, identified by either a header or a parameter in the query string or HTTP body." Is it same for normal expressjs based app?
The only option I found regarding "selectively" enabling / disabling CSRF tokens was at this documentation, which allows a kind of "blacklist" csrf will be disabled for. So your csrf.js in the config folder would look like this:
module.exports.csrf = {
// it says comma delimited list in the docs, but not sure if it has to look exactly like this,
// the docs seem to be a bit unclear
routesDisabled: "POST /model,DELETE /model/:id"
};
CSRF has usually no relevance for GET requests, as these should be without any side effects (if REST conform). CSRF tokens are an authenticity token to proof to the web server / backend on a modifying request (i.e. post, put delete) that you (the visitor / user) were not fooled by someone else with an evil intention (e.g. like a faked form for a simple renaming action, which in turn tries to delete your account behind the scenes).
So the csrf token proofs that the form was generated by the server / backend you want to make the request to.
I'm not so sure about the csrf token regarding express.js apps.
But since sails.js is based on express.js, it could be the same mechanism.
i have implemented the tokken based authentication in my project instead of the cookie-session based authentication. So, in jwt(jason-web-tokkens), every time is send req to server,I in headers attach the tokken and send it to server which validate it against the secret is used in generation the tokkkne in the first time and send me the response. Now, i have concern about it, first the tokken is saved in the local storage in browser.although the tokken is hashed but what if the hacker just take that tokken from storage and use it?
can anyone tell me how it stop the CORS attack?
I'm confused and cannot find any reliable answer online.
By CORS I think you are referring to XSS attacks? If so, the best way to prevent XSS is to secure your app against untrusted input. That is easier said than done, here is some information on that:
https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
The easier way to prevent XSS is to store the token in a Secure, HTTP only cookie. This means that the Javascript environment cannot touch it, and it will only be sent over secure channels.
Nothing comes for free though :) If you put the token in a cookie, you will also need to setup a CSRF prevention strategy:
https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet
This can be a lot to take in!
I work at Stormpath and I recently wrote this blog post that covers these topics: Token Based Authentication for Single Page Apps (SPAs)
Suppose I have the following URL route:
app.post('upvote', function(req, res) {
// make a database a call to increase vote count
});
What can I do to prevent others from opening up a console and sending AJAX POST request on www.mysite.com/upvote? I'd like it so that only www.mysite.com is allowed to make that POST request and no one else.
What can I do to prevent others from opening up a console and sending AJAX POST request
Who is "others"?
If others==users of the site... there is nothing you can do to stop them sending whatever requests they like, using the JavaScript console or any other means. You can't trust the client, so you have to have server-side authorisation: requiring that the user be logged into an account, and registering that the account has upvoted so can't vote again.
If others==admins of other sites (by serving script to their users that causes submissions to your site)... it isn't possible for JavaScript on another site to cause an AJAX POST request, or at least not unless you deliberately opt into that using CORS. But it's quite possible for them to cause a POST by simply creating a <form> pointing to your address and submitting it.
This is a classic Cross Site Request Forgery problem. The widely-accepted solution to XSRF issues is to include a secret token as a parameter in each POST (form or AJAX) submission. That secret token is associated with the logged-in state of the user, either by being stored in the server-side session, or replicated in a client-side cookie. Either way an attacker from another site isn't capable of getting hold of a token that is valid for the logged-in user, so they can't fake the request.
You need XSRF protection on all actions that have a direct effect, whether AJAX or form-based POSTs.
I agree with bobince. others is a very general term.
If others belong to other sites (malicious sites on net).
express has csrf middleware to protect from Cross Site Request
Forgery. You can use it to prevent such a scenario. See the API docs
here.
If others are users of your own site
then that is an authentication issue. Every request must be
checked before serving / executing it. You should implement a user
authentication to prevent this situation. I use passport, and
ensure that user is authenticated before I actually run app.post
handler.
Is CSRF possible with PUT or DELETE methods? Or does the use of PUT or DELETE prevent CSRF?
Great question!
In a perfect world, I can't think of a way to perform a CSRF attack.
You cannot make PUT or DELETE requests using HTML forms.
Images, Script tags, CSS Links etc all send GET requests to the server.
XmlHttpRequest and browser plugins such as Flash/Silverlight/Applets will block cross-domain requests.
So, in general, it shouldn't be possible to make a CSRF attack to a resource that supports PUT/DELETE verbs.
That said, the world isn't perfect. There may be several ways in which such an attack can be made possible :
Web Frameworks such as Rails have support for "pseudo method". If you put a hidden field called _method, set its value to PUT or DELETE, and then submit a GET or POST request, it will override the HTTP Verb. This is a way to support PUT or DELETE from browser forms. If you are using such a framework, you will have to protect yourself from CSRF using standard techniques
You may accidentally setup a lax response headers for CORS on your server. This would allow arbitrary websites to make PUT and DELETE requests.
At some point, HTML5 had planned to include support for PUT and DELETE in HTML Forms. But later, they removed that support. There is no guarantee that it won't be added later. Some browsers may actually have support for these verbs, and that can work against you.
There may just be a bug in some browser plugin that could allow the attacker to make PUT/DELETE requests.
In short, I would recommend protecting your resources even if they only support PUT and DELETE methods.
Yes, CSRF is possible with the PUT and DELETE methods, but only with CORS enabled with an unrestrictive policy.
I disagree with Sripathi Krishnan's answer:
XmlHttpRequest and browser plugins such as Flash/Silverlight/Applets
will block cross-domain requests
Nothing stops the browser from making a cross-domain request. The Same Origin Policy does not prevent a request from being made - all it does is prevent the request from being read by the browser.
If the server is not opting into CORS, this will cause a preflight request to be made. This is the mechanism that will prevent a PUT or DELETE from being used, because it is not a simple request (the method needs to be HEAD, GET or POST). Assuming a properly locked down CORS policy of course (or none at all which is secure by default).
No. Relying on an HTTP verb is not a way to prevent a CSRF attack. It's all in how your site is created. You can use PUTs as POSTs and DELETEs as GETs - it doesn't really matter.
To prevent CSRF, take some of the steps outlined here:
Web sites have various CSRF countermeasures available:
Requiring a secret, user-specific token in all form submissions and side-effect URLs prevents CSRF; the attacker's site cannot put the
right token in its submissions1
Requiring the client to provide authentication data in the same HTTP Request used to perform any operation with security
implications (money transfer, etc.)
Limiting the lifetime of session cookies Checking the HTTP Referer header or(and)
Checking the HTTP Origin header[16]
Ensuring that there is no clientaccesspolicy.xml file granting unintended access to Silverlight controls[17]
Ensuring that there is no crossdomain.xml file granting unintended access to Flash movies[18]
Verifying that the request's header contains a X-Requested-With. Used by Ruby on Rails (before v2.0) and Django (before v1.2.5).
This protection has been proven unsecure[19] under a combination of
browser plugins and redirects which can allow an attacker to
provide custom HTTP headers on a request to any website, hence
allow a forged request.
In theory it should not be possible as there is no way to initiate a cross-domain PUT or DELETE request (except for CORS, but that needs a preflight request and thus the target site's cooperation). In practice I would not rely on that - many systems have been bitten by e.g. assuming that a CSRF file upload attack was not possible (it should not be, but certain browser bugs made it possible).
CSRF is indeed possible with PUT and DELETE depending on the configuration of your server.
The easiest way to think about CSRF is to think of having two tabs open in your browser, one open to your application with your user authenticated, and the other tab open to a malicious website.
If the malicious website makes a javascript request to your application, the browser will send the standard cookies with the request, thus allowing the malicious website to 'forge' the request using the already authenticated session. That website can do any type of request that it wants to, including GET, PUT, POST, DELETE, etc.
The standard way to defend against CSFR is to send something along with the request that the malicious website cannot know. This can be as simple as the contents of one of the cookies. While the request from the malicious site will have the cookies sent with it, it cannot actually access the cookies because it is being served by a different domain and browser security prevents it from accessing the cookies for another domain.
Call the cookie content a 'token'. You can send the token along with requests, and on the server, make sure the 'token' has been correctly provided before proceeding with the request.
The next question is how do you send that value with all the different requests, with DELETE specifically difficult since it is not designed to have any kind of payload. In my opinion, the cleanest way is to specify a request header with the token. Something like this x-security-token = token. That way, you can look at the headers of incoming requests, and reject any that are missing the token.
In the past, standard ajax security restricted what could be done via ajax on the malicious server, however, now-a-days, the vulnerability depends on how you have your server set up with regards to accees-control configurations. Some people open up their server to make it easier to make cross domain calls or for users to make their own RESTful clients or the like, but that also makes it easier for a malicious site to take advantage unless CSRF prevention methods like the ones above are put in place.