Giter Site home page Giter Site logo

Cookie csurf doesn't work about csurf HOT 57 CLOSED

expressjs avatar expressjs commented on April 26, 2024
Cookie csurf doesn't work

from csurf.

Comments (57)

arty-name avatar arty-name commented on April 26, 2024

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.

gabeio avatar gabeio commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

@gabeio, documentation says the header is also supported

from csurf.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

gabeio avatar gabeio commented on April 26, 2024

@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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

gabeio avatar gabeio commented on April 26, 2024

good to know!

from csurf.

arty-name avatar arty-name commented on April 26, 2024

If it doesn't matter, and the cookie is not reachable, why not to use cookie for both parts?

from csurf.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

Basically I would like to see the exchange I have displayed in the ticket. Same security, less code.

from csurf.

dougwilson avatar dougwilson commented on April 26, 2024

It's not happening. Feel free to use a different module, if you like, though.

from csurf.

arty-name avatar arty-name commented on April 26, 2024

Fair enough :)

from csurf.

gabeio avatar gabeio commented on April 26, 2024

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.

gabeio avatar gabeio commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024
  1. I respect your decision "it's not happening" and continue this discussion just to figure out if I'm getting something wrong.
  2. I assume that you keep in mind more use cases then I do.
  3. 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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

jonathanong avatar jonathanong commented on April 26, 2024

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.

jonathanong avatar jonathanong commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

jonathanong avatar jonathanong commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

@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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

Yes, that sounds fair. Is the _csrf cookie a poor man's session?

from csurf.

dougwilson avatar dougwilson commented on April 26, 2024

Yes, that sounds fair. Is the _csrf cookie a poor man's session?

Yes, I think that's an accurate description :)

from csurf.

arty-name avatar arty-name commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

Does the server then check if one value corresponds to another by equality, or some server-stored mapping aka session, or cryptography?

from csurf.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

Do different methods of checking change anything in the context of CSRF prevention?

from csurf.

dougwilson avatar dougwilson commented on April 26, 2024

Hm. Can you give an example of a method of checking? I'm not super familiar with that term, I'm sorry :(

from csurf.

arty-name avatar arty-name commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

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.

dougwilson avatar dougwilson commented on April 26, 2024

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.

jonathanong avatar jonathanong commented on April 26, 2024

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.

arty-name avatar arty-name commented on April 26, 2024

@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.

arty-name avatar arty-name commented on April 26, 2024

@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.

jonathanong avatar jonathanong commented on April 26, 2024

I don't know what your solution is nor do I know any potential benefits.

from csurf.

arty-name avatar arty-name commented on April 26, 2024

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.

jonathanong avatar jonathanong commented on April 26, 2024

So no salted tokens? BREACH. That's it. As long as the cookie is http only.

from csurf.

arty-name avatar arty-name commented on April 26, 2024

@jonathanong thank you, this is the kind of answer I was looking for! Shows me I'm out of my depth here :)

from csurf.

jonathanong avatar jonathanong commented on April 26, 2024

@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.

arty-name avatar arty-name commented on April 26, 2024

@jonathanong thank you for the link to this thorough explanation!

from csurf.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.