-
Notifications
You must be signed in to change notification settings - Fork 367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft of adding CSRF protection for AJAX requests #1017
Conversation
Added a draft of the CSRF overview section. Need to verify the haddocks look sensible but am otherwise happy with that part. Edit: Have verified Haddocks look correct. |
For CSRF vs XSRF, you are doing it right by picking one and making it configurable |
This current PR also requires manually calling |
Hmm, I would like to turn this into a middleware (at least a yesod middleware). That way enabling it would just mean dropping in a middleware. |
A Yesod middleware seems right for this, sounds good (Wai middleware is doable, but would it need a function passed in to extract the CSRF token from the request; not sure if that's worthwhile). |
You are welcome to use a Yesod middleware. If you went the wai route, you would probably take advantage of the vault parameter for request-local storage rather than passing in a function. |
46421a3
to
91ec997
Compare
Getting pretty close. Added Yesod Middleware and tests. The Yesod Middleware isn't well organized or documented yet, so working on cleaning up that. |
a7fa940
to
d256ead
Compare
This should be ready for review. I'm happy with the explanation of CSRF attacks and the prevention mechanism. The middleware makes CSRF protection very simple to add. I'm not sure how this fits into yesod-form's CSRF protection yet; this middleware could handle that case if you used Javascript to add the CSRF header when a request was made from a form. If you didn't have Javascript enabled, that wouldn't work, though. Maybe on version of the middleware could skip CSRF protection for forms somehow? Anyway, I'm investigating this. |
forms should be sent as form-data. This CSRF protection would then only be on for JSON data (content type of application/json). |
Yeah, it looks like I can't just prevent CSRF protection from applying to I can have it only run CSRF protection on I can also just require users to add the CSRF header to their forms using e.g. jQuery. This makes it take extra work to support users with Javascript disabled, though. Maybe that's ok. |
Doesn't one have to use the existing Yesod forms that inject a hidden attribute to support disabled javascript? |
@gregwebs Yeah the current yesod-forms library works with disabled Javascript, but the middleware will reject the request before the handler can run the form to check the CSRF token. |
@gregwebs @MaxGabriel For the record, this is the prime example of a PR you guys should feel free to move ahead with without my input :) |
I'm not sure what I was thinking before, to handle the case where Javascript was disabled I just needed to check the form parameters for CSRF tokens as well, which I thought would be hard for some reason but was quite easy. I made a few more modifications like using constant time comparison, as yesod-form suggests. Anyway, I think this PR is ready for final review. I know you said to go ahead without your input @snoyberg but since it's a security thing I wouldn't mind more review; for a long time this PR wasn't doing things like constant time comparison. |
LGTM 👍 |
checkCsrfHeaderOrParam headerName paramName = do | ||
validHeader <- hasValidCsrfHeaderNamed headerName | ||
validParam <- hasValidCsrfParamNamed paramName | ||
unless (validHeader || validParam) (permissionDenied "Invalid CSRF token in header.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message here only mentions one case.
looks fantastic! I only had 2 comments for making minor improvements. Looks like this also need to be rebased to the lastest master. |
0a6d2b1
to
132abce
Compare
Cool, I made changes based on @gregwebs's comments and rebased against master. I'll rebase into one commit and merge later tonight. |
After merging
|
132abce
to
33982b2
Compare
Adding CSRF protection for AJAX requests
Cool, I'm adding it to this PR to the yesod-scaffolding yesodweb/yesod-scaffold#76 Working on adding support to yesod-test for using CSRF tokens this way; mostly done with that. |
So based on some testing, it seems like Haven't investigated much; initial ideas are to only use Edit: It looks like the root cause of this is yesod-test adding the "application/x-www-form-urlencoded" Content-Type to requests. |
cf #1016
The code is missing tests and high-level documentation, but should be ready for review otherwise.cc @gregwebs