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

Refactor CSRF protection modules, make sure CSRF tokens can be up-to-date. #19337

Merged
merged 11 commits into from
Apr 8, 2022

Conversation

wxiaoguang
Copy link
Contributor

@wxiaoguang wxiaoguang commented Apr 6, 2022

The CSRF protection modules have been broken for a while. For example, comment said: // Csrfer maps CSRF to each request. If this request is a Get request, it will generate a new token., however, it doesn't!! That's why a lot of users complain about their work lost.

Related issues:

And maybe more.

This PR does a refactoring to the CSRF related code, removes most unnecessary functions.

It introduces ParseCsrfToken to parse the generated token's issue time, and regenerate the token every minute.

And it fixes some incorrect code in old code, for example: ctx.Data["CsrfToken"] = html.EscapeString(ctx.csrf.GetToken()), the EscapeString is incorrect.

The error handling logic in Validate has been simplified, remove many duplicate code.

Totally this PR is +119 −195

@wxiaoguang wxiaoguang added type/bug type/refactoring Existing code has been cleaned up. There should be no new functionality. labels Apr 6, 2022
@wxiaoguang wxiaoguang added this to the 1.17.0 milestone Apr 6, 2022
@wxiaoguang wxiaoguang linked an issue Apr 6, 2022 that may be closed by this pull request
routers/api/v1/api.go Outdated Show resolved Hide resolved
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Apr 6, 2022
modules/web/middleware/cookie.go Show resolved Hide resolved
modules/context/csrf.go Outdated Show resolved Hide resolved
modules/context/csrf.go Outdated Show resolved Hide resolved
modules/context/csrf.go Outdated Show resolved Hide resolved
modules/context/csrf.go Outdated Show resolved Hide resolved
@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Apr 6, 2022
Copy link
Contributor

@zeripath zeripath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would make sense to move this into a separate package?

// It is exported so clients may set cookie timeouts that match generated tokens.
const Timeout = 24 * time.Hour
const CsrfTokenTimeout = 24 * time.Hour
const CsrfTokenRegenerationDuration = 1 * time.Minute
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems far too frequent. Perhaps this should be hourly?

Copy link
Contributor Author

@wxiaoguang wxiaoguang Apr 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems far too frequent. Perhaps this should be hourly?

It doesn't matter, it's just a simple hash when generating the token, doesn't cost more resources than other logic.

And the generated token is valid for the next 24 hours, so there should be no problem.

Indeed we can keep generating new tokens on every request, there will still be no performance problem. I just introduced this mechanism in case someone doesn't like generating the tokens (and sending cookies) again and again.

// If cookie token presents, re-use existing unexpired token, else generate a new one.
if issueTime, ok := ParseCsrfToken(x.Token); ok {
dur := time.Since(issueTime)
if dur >= -CsrfTokenRegenerationDuration && dur <= CsrfTokenRegenerationDuration {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this really be negative?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this really be negative?

For example, the server time changed a lot? Personally I prefer to check the [-duration, duration] range

Copy link
Contributor Author

@wxiaoguang wxiaoguang Apr 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ps: if issueTime can be guaranteed to be a monotonic clock, then we do not check the negative range. Checking the negative is not wrong because the issueTime might come from other packages and be refactored.

If you prefer to remove the negative check, it might can be done. However, I think it requires the code to store the mono clock in token, instead of a simple UnixNano ..... currently, issueTime := time.Unix(0, nanos) is a non-monotonic clock

@wxiaoguang
Copy link
Contributor Author

I wonder if it would make sense to move this into a separate package?

What's the preferred package name and package path?

@codecov-commenter

This comment was marked as off-topic.

@wxiaoguang wxiaoguang requested a review from zeripath April 7, 2022 09:39
@silverwind
Copy link
Member

silverwind commented Apr 7, 2022

What's the preferred package name and package path?

modules/csrf maybe? Not sure if that's what @zeripath means.

@wxiaoguang
Copy link
Contributor Author

What's the preferred package name and package path?

modules/csrf maybe? Not sure if that's what @zeripath means.

I do not think csrf can be a proper package name. CSRF means Cross site request forgery, it's an attack vector/method. The package is protecting against CSRF attack.

@silverwind
Copy link
Member

It's code to handle CSRF, seems pretty clear to me. And a short name is easy to work with.

@wxiaoguang
Copy link
Contributor Author

TBH, I still think the name csrf is not ideal enough.

And this PR has done what it should do. Moving code into a new package is too much for this PR. Reasons:

  1. If we do moving code and changing code at the same time, this PR would become more difficult to be reviewed, and it may introduce potential bugs.
  2. Moving code into a new package is not an easy work at the moment. Because modules/context.go need modules/csrf.go and csrf also needs context. Without more related refactoring, there will be a cycle-import error, the downside of Golang. For reason 1, it's not ideal to make these more argument renaming/changing refactoring into this PR.

@zeripath @silverwind

@wxiaoguang wxiaoguang requested a review from lunny April 8, 2022 02:01
@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Apr 8, 2022
@wxiaoguang wxiaoguang merged commit 84ceaa9 into go-gitea:main Apr 8, 2022
@wxiaoguang wxiaoguang deleted the refactor-csrf branch April 8, 2022 05:21
zjjhot added a commit to zjjhot/gitea that referenced this pull request Apr 11, 2022
* giteaofficial/main: (22 commits)
  Add logic to switch between source/rendered on Markdown (go-gitea#19356)
  Fixed registry host value. (go-gitea#19363)
  [skip ci] Updated translations via Crowdin
  Allow package linking to private repository (go-gitea#19348)
  Use "main" as default branch name (go-gitea#19354)
  Move milestone to models/issues/ (go-gitea#19278)
  Refactor CSRF protection modules, make sure CSRF tokens can be up-to-date. (go-gitea#19337)
  Remove dependent on session auth for api/v1 routers (go-gitea#19321)
  API: Search Issues, dont show 500 if filter result in empty list (go-gitea#19244)
  [skip ci] Updated translations via Crowdin
  Never use /api/v1 from Gitea UI Pages (go-gitea#19318)
  [skip ci] Updated translations via Crowdin
  Show ssh command directly in template instead of i18n translation (go-gitea#19335)
  Package registry changes (go-gitea#19305)
  [skip ci] Updated translations via Crowdin
  Add `ENABLE_SSH_LOG` to debugging problems (go-gitea#19316)
  Warn on SSH connection for incorrect configuration (go-gitea#19317)
  escape fake link
  Allow custom redirect for landing page (go-gitea#19324)
  [skip ci] Updated translations via Crowdin
  ...
AbdulrhmnGhanem pushed a commit to kitspace/gitea that referenced this pull request Aug 24, 2022
…date. (go-gitea#19337)

Do a refactoring to the CSRF related code, remove most unnecessary functions.
Parse the generated token's issue time, regenerate the token every a few minutes.
@go-gitea go-gitea locked and limited conversation to collaborators May 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. type/bug type/refactoring Existing code has been cleaned up. There should be no new functionality.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Invalid CSRF token issues - unable to recover submitted data
8 participants