Comments (57)
Looking at the code of csurf and csrf I see that it expects the token to always contain -
but somehow it doesn't put it in.
from csurf.
the csrf token should be submitted via the post data as _csrf
field, to get that csrf token use req.csrfToken()
. This tests against the csrf cookie that is given to the user.
from csurf.
@gabeio, documentation says the header is also supported
from csurf.
I think you just misunderstand, @arty-name ; the _csrf
cookie header is not the actual CSRF token; it's just the secret for the token. As @gabeio said, you need to use req.csrfToken()
to get the token to use in the X-XSRF-TOKEN
header.
Ex:
var app = require('express')()
app.use(require('cookie-parser')())
app.use(require('csurf')({cookie: true}))
// error handler
app.use(function (err, req, res, next) {
if (err.code !== 'EBADCSRFTOKEN') return next(err)
// handle CSRF token errors here
res.status(403)
res.send('session has expired or form tampered with')
})
app.use(function (req, res, next) {
res.send('your token is: ' + req.csrfToken())
})
require('http').createServer(app).listen(3000);
Now you make a request to that server and you need to echo the Cookie
that was set back, but then you take the token, which I put in the body in my example, and send that value back in the X-XSRF-TOKEN
header.
from csurf.
This looks too complicated. Would be much simpler to follow the path Angular.js proposes: cookie is sent to the browser, both cookie and header are sent to the server.
from csurf.
Then just add this to your code:
app.use(function (req, res, next) {
res.cookie('csrf-token', req.csrfToken())
next()
})
And then you need to read the cookie and send it back somehow; we leave the implementation up to you.
from csurf.
Basically, I believe Angular will read the token out of a cookie for you; you just need to set that cookie yourself from the result of req.csrfToken()
and point Angular to that cookie and everything will work; you're just pointing to the wrong cookie. The purpose of the cookie feature in this module is to enable "double-submit cookie" feature of CSRF protection, removing the need for you to keep a server-side session storage, it doesn't actually send the token as a cookie, you still need to do that.
from csurf.
@dougwilson but what is a SAFE way to get it to angular without being super easy for a user to just find and then abuse? or is this literally just to keep it safe from evil links? I just feel like ie:
/api/get/csrf
is too simple and will get abused...
from csurf.
It doesn't matter if the user can see it; the token just needs to not be accessible by a website at a different origin in one's browser.
from csurf.
good to know!
from csurf.
If it doesn't matter, and the cookie is not reachable, why not to use cookie for both parts?
from csurf.
Because the token must be a part of the submission such that the submitter much know the token; if the token were a cookie, then the submitter doesn't have to know the value, because the browser will automatically send it. I'm sure there are good resources out there to learn about what CSRF is and how they work and what they protect, etc. Better than I can in this issue tracker.
from csurf.
I know. I mean that to send something in a header you can read it from cookie. You yourself proposed to send two cookies. I propose to reduce the number of entities and send both secret and token in one cookie. Frontend will then send it back in both header and a cookie.
from csurf.
Basically I would like to see the exchange I have displayed in the ticket. Same security, less code.
from csurf.
It's not happening. Feel free to use a different module, if you like, though.
from csurf.
Fair enough :)
from csurf.
the cookie is assigned to a specific user. the header is available for things like angular but angular has to change the header itself depending on the request. the idea is that to have both and correctly both they can only be on the page.
from csurf.
most of this is just for assuring the request did not come from a different domain (which will not have the form data to verify with the cookie)
as the server knows what it handed out in the form to what cookie.
from csurf.
The essence of the protection is that if I put a <form action="http://yoursite" method="post">
on my site, it should not be able to work. If the token is stored in a cookie and this module then turns around and reads it from said cookie, then that form would submit just fine. This is why you have to use req.csrfToken()
and pass it back in some way (and yes, passing it back using res.cookie
is fine, since this module won't read from that cookie, since it doesn't know you set it). Angular does this stuff for you by sending it back as the X-XSRF-TOKEN
header, which we read from.
BUT in order for our module to know that the token actually means something, we have to store some state on the server (you can do this using express-session
). We also provide an alternative to this other piece so you don't need the server state: the cookie
option (aka "double-submit cookie" in csrf parlance). This cookie is not the actual token you need to send back in the X-XSRF-TOKEN
header, however.
from csurf.
- I respect your decision "it's not happening" and continue this discussion just to figure out if I'm getting something wrong.
- I assume that you keep in mind more use cases then I do.
- I don't see an attack vector in the case when server requires equal values to be contained in both cookie and header. Only trusted client-side code will be able to read the cookie value and add it to the header. For that the server module can be as minimal as:
a) verify presence of equal cookie and header in non-indempotent requests
b) set a random cookie if it doesn't exist yet
I believe that exactly this approach is described in OWASP section on Double Submit Cookies
from csurf.
Right, but the same article recommends the "Synchronizer Token Pattern" https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet#General_Recommendation%3a_Synchronizer_Token_Pattern
In this pattern, we have two things: a per-session secret and the token, which differs. The secret is what we're storing in the cookie, which is why it's different from the token you need to submit in the header.
It only takes you adding one extra app.use()
call in your code to make this library work the way you want with Angular. I would change this if it was impossible to use with Angular, but it's not: just set a cookie of your choosing to the value of req.csrfToken()
.
from csurf.
We also like the ability to let you call req.csrfToken()
with every request to automatically give you the even better "per-request token", which helps if your site's SSL is susceptible to BEAST and similar attacks due to the cipher settings, since the clear text will keep changing with each request just from the token itself.
from csurf.
I wouldn't really like it:
Implementing this approach results in the generation of per-request tokens as opposed to per-session tokens. Note, however, that this may result in usability concerns. For example, the "Back" button browser capability is often hindered as the previous page may contain a token that is no longer valid.
Another example is two tabs open in parallel.
I'm still reading on the previous comment.
from csurf.
We implement the per-request token approach in such a way so all the different tokens are valid at the same time for the same session. This is why the _csrf
cookie isn't the same as the token.
from csurf.
csrf tokens are never invalid as long as the secret (i.e. what the cookie stores) never changes. there's no issue here with two tabs open in parallel - they'll use two different csrf tokens that will both always be valid.
from csurf.
also, it doesn't matter how you send a csrf token to the client. if you really want, your angular app could use a single csrf throughout the entire session.
from csurf.
It might that some important detail is missing again, but so far I don't see security benefits of per-request tokens when all of them are valid. The BEAST protection is rather far-fetched, and should really be a separate concern. Single-use tokens improve security but destroy usability (as it always happens).
from csurf.
Many, many people use this module with Angular just fine. I'm not sure I understand your issue. The original post was just a question, where you were simply confused thinking that the _csrf
cookie's value was the XSRF token value. I posted the single extra app.use()
call you need to put the actual XSRF token into a cookie for Angular (and it's what all Angular users have been doing for a long time).
from csurf.
The BEAST
stuff is the only reason! as a maintainer, you don't want to ever have an excuse for people to complain about security.
but single-use tokens is a subset of the current solution, so there is no loss in our current implementation except a few more bytes sent down the wire.
from csurf.
Here is a walk-though I found real quick: http://charandeepmatta.com/2014/06/04/csrfxsrf-protection-express-angular/ Since you're not using passport, simply change app.use(csrf());
to app.use(csrf({cookie: true}));
in their example.
Here is a full example for ya:
var app = require('express')()
app.use(require('cookie-parser')())
app.use(require('csurf')({cookie: true}))
// error handler
app.use(function (err, req, res, next) {
if (err.code !== 'EBADCSRFTOKEN') return next(err)
// handle CSRF token errors here
res.status(403)
res.send('session has expired or form tampered with')
})
app.use(function (req, res, next) {
res.cookie('XSRF-TOKEN', req.csrfToken())
next()
})
require('http').createServer(app).listen(3000);
from csurf.
@dougwilson, as I said, I am trying to see if I'm getting something wrong. "It's not happening" is a valid argument for me. However you keep adding other arguments which don't seem reasonable, so I question them.
from csurf.
Sure. So there is a lot of crowding and cross talk above, I agree. Let's start over. Please list out just one question and I'll try to answer just that one question. Once we complete that, then we can move on to a second question. Does that sound fair?
from csurf.
Yes, that sounds fair. Is the _csrf
cookie a poor man's session?
from csurf.
Yes, that sounds fair. Is the _csrf cookie a poor man's session?
Yes, I think that's an accurate description :)
from csurf.
Do sessions (proper or poor man's) rely on a cookie received from a browser, and on unavailability of this cookie to unauthorised code?
from csurf.
Yes, sessions rely on a cookie received from a browser. I'm not 100% sure what you mean by
and on unavailability of this cookie to unauthorised code?
but I can say that all cross domain pages cannot read the value, but they can still send the value.
from csurf.
Does it all boil down to the client sending two values to the server: a cookie and (a header or a body value)?
from csurf.
Essentially, yes. One thing to identify you so we can give tokens to user A that cannot be used by user B. The second, and main piece, is something only the site origin can know, by taking advantage of browser same-origin rules. The important part of the second piece is that it can't be something the browser will automatically send back in a cross domain request.
from csurf.
Does the server then check if one value corresponds to another by equality, or some server-stored mapping aka session, or cryptography?
from csurf.
It checks via cryptography. There is a section in the OWASP article about an encryption implementation ("Encrypted Token Pattern"). I think that pretty well describes what we do, except the secret is per-user instead of per-server.
from csurf.
Do different methods of checking change anything in the context of CSRF prevention?
from csurf.
Hm. Can you give an example of a method of checking? I'm not super familiar with that term, I'm sorry :(
from csurf.
Maybe it's just my poor English. In the context when an attacker must provide a specific value in the forged request, and he has no access to this value (be that enforced by cross site security, or cryptography, or no access to server memory), does it matter how exactly we check that the provided value is correct?
from csurf.
Gotcha. No, I don't think it's from poor English :) I just wanted to go through here slower than earlier and make sure we're on the same grounds as we talk so it doesn't end up all jumbled again :)
does it matter how exactly we check that the provided value is correct?
No, I would say not. It does somewhat depend on how the value is generated, of course. For example, if a site just gave out a static token (as a dumb example), then clearly the attacker can just hard-code the value into their attack site.
from csurf.
Given that and that a session is a cookie, is the following method inferior in some way in the context of CSRF prevention to the method currently employed by csurf? "Require that non-indempotent requests from the browser contain the same random value in a cookie and some custom header".
from csurf.
I'm not 100% sure what you mean. What you put in quotes is the exact description of what this module does (though we let you put the value in the body or query string, in addition to just a custom header).
from csurf.
I disagree. csurf does much more than that. It uses two cookies, signs one cookie with another, checks this signature later. The quoted method uses one cookie and no cryptography. Though I agree that quoted method is inferior in limiting it to custom header. Let my modify my question this way:
Given that and that a session is a cookie, is the following method inferior in some way in the context of CSRF prevention to the method currently employed by csurf? "Require that non-indempotent requests from the browser contain the same random value in a cookie and some custom header or request body".
Query string is bad practice according to this OWASP page, btw.
from csurf.
I'm still not 100% clear, I'm sorry. If you want to make a PR, please feel free and cc some security folks like the ones from the node security project. The existing methods here have already been security audited, so if we're going to change anything, I need it security audited.
from csurf.
csurf does not use two cookies. tokens are not cookies - they are tokens, and you can pass them however you want. csurf only stores the secret as a cookie (or your session), which generates and validates csrf tokens.
from csurf.
@dougwilson, I was hoping you would say something like "the method you propose has a flaw: when attacker does such and such, the protection is circumvented". Or "apparently the complexity of our solution doesn't increase security". Since I don't know any security folks, I'd say let's leave it.
I really appreciate your patience in answering my questions. Thanks!
from csurf.
@jonathanong, you are not really answering my question. Could you answer the last question I have asked here? About how my solution "one cookie and one equal non-cookie value" is flawed and can be exploited in an attack?
from csurf.
I don't know what your solution is nor do I know any potential benefits.
from csurf.
Here it is: "Require that non-indempotent requests from the browser contain the same random value in a cookie and some custom header or request body". Is it flawed and can be exploited in an attack?
from csurf.
So no salted tokens? BREACH. That's it. As long as the cookie is http only.
from csurf.
@jonathanong thank you, this is the kind of answer I was looking for! Shows me I'm out of my depth here :)
from csurf.
@arty-name if you have more questions about CSRF, please open up an issue here: https://github.com/pillarjs/understanding-csrf :) trying to keep the issues here implementation-specific
from csurf.
@jonathanong thank you for the link to this thorough explanation!
from csurf.
Related Issues (20)
- Feature add 'Encrypted Token Pattern' HOT 3
- Add credentials warning to documentation HOT 7
- A way of getting csrfToken through POST request HOT 3
- Cannot validate CSRF token using the example code HOT 4
- Can docs clarify how cookie mode works? HOT 3
- please document the `signed` config option HOT 4
- Disable CSRF checking during tests HOT 1
- previous token still valid HOT 1
- Token Lifetime HOT 2
- Need docs and examples for working with single page application. HOT 3
- BREACH attack mitigation HOT 2
- No regeneration of secret when a valid token is submitted HOT 2
- A cookie secret is not really secret HOT 1
- Upgrade to [email protected] for SameSite=None support HOT 1
- Best practice for the csrf token and secret (signed? httponly?) HOT 1
- User's CSRF Token is invalid but doesn't look like so HOT 7
- New token secret with every request HOT 3
- Update docs to address situations with mixed protection approaches HOT 1
- How I can validate csrf token one time with only a request
- Failed on validation when using with 2 backends
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from csurf.