Skip to content
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

Fix CWE-352 CSRF protection weakness. #1375

Merged
merged 1 commit into from
Jan 25, 2024
Merged

Fix CWE-352 CSRF protection weakness. #1375

merged 1 commit into from
Jan 25, 2024

Conversation

@sengi sengi requested a review from theseanything January 25, 2024 12:09
@theseanything
Copy link
Contributor

thanks!

@sengi sengi merged commit d21e41d into main Jan 25, 2024
12 checks passed
@sengi sengi deleted the sengi/csrf branch January 25, 2024 12:12
@theseanything
Copy link
Contributor

@sengi just been looking at this again - I don't think we memoize session data anywhere and aren't affected by this security issue right now. It's definitely sensible to throw an exception on missing/invalid CSRF token and protects against future code changes. However, this behaviour breaks the deployment API when the request is authenticated via bearer token (because we don't need a CSRF token, but still check for one). To fix that we need implement a way to control the authentication strategies of gds-sso per controller - currently can only disable session authentication for whole Rails app.

I propose we revert this change as to fix the deployment API and allow Release to show up to date deployment information, whilst we work on gds-sso to remove the need for CSRF tokens for the deployment API.

@sengi
Copy link
Contributor Author

sengi commented Jan 31, 2024

No probs, sorry thought this would be an easy win but I was wrong :( Thanks for investigating!

chrisroos added a commit that referenced this pull request Feb 7, 2024
This was previously enabled in PR #1375 but then reverted in PR #1383
when it was discovered that enabling it had silently broken the ability
for Release API clients to create deployment records because they don't
(and shouldn't need to) send the CSRF token in the request.

I'm avoiding the problem seen in PR #1375 by skipping forgery protection
if we detect a Bearer token in the Authorization HTTP Header. I'm doing
this in the same way that GDS::SSO checks whether the `gds_sso` Warden
strategy is valid[2] or whether it needs to use the `gds_bearer_token`
strategy instead[3] so I'm fairly confident this is good enough to
distinguish an API request from a browser request.

One of the two new controller tests should fail if we either:

- remove the `with: :exception` option to `protect_from_forgery`
- require the CSRF token when an API client authenticates using a Bearer
  token and creates a deployment

Note that I'm assuming that `Deployments#create` is the only API
endpoint. If it turns out there are more API endpoints then we'll need
to make the same change to those.

I was interested to learn that raising an exception is the default
behaviour in new Rails apps[3] but that we were overriding that default
with our explicit call to `protect_from_forgery` without any arguments.
Adding `protect_from_forgery with: :exception` is the same as removing
`protect_from_forgery` entirely, although I think the former is more
explicit.

[1]: https://github.com/alphagov/gds-sso/blob/8cc1427bfcd3cbfa24904040c8eaccff45434322/lib/gds-sso/warden_config.rb#L38
[2]: https://github.com/alphagov/gds-sso/blob/8cc1427bfcd3cbfa24904040c8eaccff45434322/lib/gds-sso/warden_config.rb#L64
[3]: https://guides.rubyonrails.org/security.html#required-security-token
chrisroos added a commit that referenced this pull request Feb 7, 2024
This was previously enabled in PR #1375 but then reverted in PR #1383
when it was discovered that enabling it had silently broken the ability
for Release API clients to create deployment records because they don't
(and shouldn't need to) send the CSRF token in the request.

I'm avoiding the problem seen in PR #1375 by skipping forgery protection
if we detect a Bearer token in the Authorization HTTP Header. I'm doing
this in the same way that GDS::SSO checks whether the `gds_sso` Warden
strategy is valid[1] or whether it needs to use the `gds_bearer_token`
strategy instead[2] so I'm fairly confident this is good enough to
distinguish an API request from a browser request.

One of the two new controller tests should fail if we either:

- remove the `with: :exception` option to `protect_from_forgery`
- require the CSRF token when an API client authenticates using a Bearer
  token and creates a deployment

Note that I'm assuming that `Deployments#create` is the only API
endpoint. If it turns out there are more API endpoints then we'll need
to make the same change to those.

I was interested to learn that raising an exception is the default
behaviour in new Rails apps[3] but that we were overriding that default
with our explicit call to `protect_from_forgery` without any arguments.
Adding `protect_from_forgery with: :exception` is the same as removing
`protect_from_forgery` entirely, although I think the former is more
explicit.

[1]: https://github.com/alphagov/gds-sso/blob/8cc1427bfcd3cbfa24904040c8eaccff45434322/lib/gds-sso/warden_config.rb#L38
[2]: https://github.com/alphagov/gds-sso/blob/8cc1427bfcd3cbfa24904040c8eaccff45434322/lib/gds-sso/warden_config.rb#L64
[3]: https://guides.rubyonrails.org/security.html#required-security-token
AgaDufrat pushed a commit that referenced this pull request May 17, 2024
This was previously enabled in PR #1375 but then reverted in PR #1383
when it was discovered that enabling it had silently broken the ability
for Release API clients to create deployment records because they don't
(and shouldn't need to) send the CSRF token in the request.

I'm avoiding the problem seen in PR #1375 by skipping forgery protection
if we detect a Bearer token in the Authorization HTTP Header. I'm doing
this in the same way that GDS::SSO checks whether the `gds_sso` Warden
strategy is valid[1] or whether it needs to use the `gds_bearer_token`
strategy instead[2] so I'm fairly confident this is good enough to
distinguish an API request from a browser request.

One of the two new controller tests should fail if we either:

- remove the `with: :exception` option to `protect_from_forgery`
- require the CSRF token when an API client authenticates using a Bearer
  token and creates a deployment

Note that I'm assuming that `Deployments#create` is the only API
endpoint. If it turns out there are more API endpoints then we'll need
to make the same change to those.

I was interested to learn that raising an exception is the default
behaviour in new Rails apps[3] but that we were overriding that default
with our explicit call to `protect_from_forgery` without any arguments.
Adding `protect_from_forgery with: :exception` is the same as removing
`protect_from_forgery` entirely, although I think the former is more
explicit.

[1]: https://github.com/alphagov/gds-sso/blob/8cc1427bfcd3cbfa24904040c8eaccff45434322/lib/gds-sso/warden_config.rb#L38
[2]: https://github.com/alphagov/gds-sso/blob/8cc1427bfcd3cbfa24904040c8eaccff45434322/lib/gds-sso/warden_config.rb#L64
[3]: https://guides.rubyonrails.org/security.html#required-security-token
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants