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

Automatically set cookie secure attribute, remove COOKIE_SECURE option #26953

Closed
wants to merge 7 commits into from

Conversation

silverwind
Copy link
Member

@silverwind silverwind commented Sep 6, 2023

The idea is to automatically set cookie Secure flag based on proxy headers or the connection, making it unnecessary to configure it by hand via previous COOKIE_SECURE option.

⚠️ BREAKING ⚠️

Gitea now requires a properly configured X-Forwarded-Proto header from reverse proxies, which should be set at the first user-facing reverse proxy and not be changed by any additional proxies in the chain.

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Sep 6, 2023
@pull-request-size pull-request-size bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Sep 6, 2023
@silverwind silverwind marked this pull request as draft September 6, 2023 22:49
@silverwind silverwind added the type/enhancement An improvement of existing functionality label Sep 6, 2023
})
handler(next).ServeHTTP(resp, req)
})
}
Copy link
Member Author

@silverwind silverwind Sep 6, 2023

Choose a reason for hiding this comment

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

Not 100% sure this usage is correct, but it appears to work.

Copy link
Contributor

@wxiaoguang wxiaoguang Sep 7, 2023

Choose a reason for hiding this comment

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

The "next" call is right, but the Sessioner is not designed to be used like this. eg: It starts a GC goroutine for every session.Sessioner() call.

The sessioner expects there should be only one instance for all requests.

Copy link
Member Author

@silverwind silverwind Sep 8, 2023

Choose a reason for hiding this comment

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

If this is suboptimal, I think the only other option is to let sessioner accept a func for the Secure attribute as well, or add a autoSecure option. Or look for alternative sessioners that are more flexible.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's not only suboptimal, it breaks the Sessioner's design and would cause bugs. The Sessioner also has many internal states, it expects the only one instance do "Init" (eg: connect to redis) and do session management (eg: Lock, GC).

Although we could make some changes to make a Sessioner work with dynamic Cookie Secure option, but I think it's too complex to do that, and "dynamic Cookie Secure" doesn't seem really bring enough benefit.

The mentioned "AppURL + COOKIE_SECURE option" should be simple enough and I don't see any problem by doing that.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not just cookie secure. If the backend wants for example to reconstruct the original URL a client used (for example for audit log), XFP is required for that as well.

Maybe I'll look into sessioner accepting a function (typecheck with Reflect), that seems the simplest option.

Copy link
Contributor

Choose a reason for hiding this comment

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

If the backend wants for example to reconstruct the original URL a client used (for example for audit log), XFP is required for that as well.

Just use AppURL, in many cases, the backend doesn't have the HTTP request context.

So, AppURL should always be correct.

Copy link
Member Author

Choose a reason for hiding this comment

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

Unless the app runs on multiple URLs :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Unless the app runs on multiple URLs :)

Yup, but the AppURL should also be correct in this case, otherwise the nofication/mail/webhook would stop working.

As long as the AppURL should be always right, then just use it.

Copy link
Member Author

Choose a reason for hiding this comment

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

@silverwind
Copy link
Member Author

Can confirm on a instance behind reverse proxy that all cookies now have the Secure attribute. I do see some duplicate set-cookie headers for session and csrf, need to check whether this is a regression from this PR.

@silverwind silverwind marked this pull request as ready for review September 6, 2023 23:40
@silverwind silverwind marked this pull request as draft September 6, 2023 23:41
Comment on lines +35 to +42
// GetCookieSecure returns whether the "Secure" attribute on a cookie should be set
func GetCookieSecure(req *http.Request) bool {
forwardedProto := strings.ToLower(req.Header.Get("x-forwarded-proto"))
if forwardedProto != "" {
return forwardedProto == "https" || forwardedProto == "wss"
}
return req.TLS != nil
}
Copy link
Contributor

@wxiaoguang wxiaoguang Sep 7, 2023

Choose a reason for hiding this comment

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

Sorry but it's not right.

Many users might not pass these header when they use Gitea behind a reverse proxy.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can just parse setting.AppURL.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we can just parse setting.AppURL.

Yes. And:

  1. Keep the COOKIE_SECURE option, in case some people really would like to run Gitea on different domains
    • COOKIE_SECURE should be default to true if AppURL is "https"
  2. Show a frontend warning if the "http" doesn't match COOKIE_SECURE=true, to tell users that "you might not be able to login"

Copy link
Member Author

Choose a reason for hiding this comment

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

Many users might not pass these header when they use Gitea behind a reverse proxy.

At least for nginx, we have been documenting for a long time to configure that header.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, only "At least". None of others are documented.

And even there is a document, many users do not follow that, they just like to write the config by their experiences.

Copy link
Member Author

Choose a reason for hiding this comment

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

I would call it out in changelog and be done with it. It's the right way to check if connection is secure imho.

Copy link
Member Author

@silverwind silverwind Sep 7, 2023

Choose a reason for hiding this comment

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

Thought I do see parsing AppURL as the more forgiving option. In an application that does not have such a setting, the current method is the only one that can work, but given that we have AppURL we might as well use it.

What only works with my method is to host the application on multiple domains and/or mixed http/https but I guess that is a seldomly used configuration.

Copy link
Contributor

@wxiaoguang wxiaoguang Sep 7, 2023

Choose a reason for hiding this comment

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

I prefer the solution in comment #26953 (comment) .

According to MDN, the X-Forwarded-Proto is not standard and there are many alternatives (Front-End-Https / X-Forwarded-Protocol / X-Forwarded-Ssl / X-Url-Scheme). IMO using the strong assumption with X-Forwarded-Proto might cause many users unable to login and fail silently. Gitea should be able to be easy to setup and use out-of-box.


My suggestion also works well with "host the application on multiple domains and/or mixed http/https", the site admin could set COOKIE_SECURE=false in their config, keep trusted HTTP requests and redirect untrusted HTTP requests to HTTPS, still no security risk.

Copy link
Member Author

Choose a reason for hiding this comment

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

So in summary: Keep COOKIE_SECURE but the AppUrl is https, switch it to true? I'm not sure such "magic" is good to do. Maybe I should just scrap the entire PR.

@silverwind
Copy link
Member Author

silverwind commented Sep 8, 2023

So unless we agree on taking this up as an acceptable change and likely break a few setups with misconfigured reverse proxies, I won't continue here. I still think it's right to require a properly configured X-Forwarded-Proto header from reverse proxies.

@silverwind silverwind added the pr/breaking Merging this PR means builds will break. Needs a description what exactly breaks, and how to fix it! label Sep 8, 2023
@silverwind
Copy link
Member Author

Breaking label added.

@silverwind
Copy link
Member Author

Actually I think it's non-breaking for the most common setup where Gitea is running on http with a reverse proxy terminating https. The Secure attribute will be absent in such a case, but users will still be able to login, just their cookie could be possibly transmitted over http as well.

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Sep 8, 2023

Actually I think it's non-breaking for the most common setup where Gitea is running on http with a reverse proxy terminating https. The Secure attribute will be absent in such a case, but users will still be able to login, just their cookie could be possibly transmitted over http as well.

It is breaking (see update below) for all instances which haven't set the "X-Forwarded-Proto" properly. And the Sessioner is another blocker.


Update: I mean, the users who do not have proper "X-Forwarded-Proto" header is under the risk of not having "secure cookie", but they couldn't know it. It leaves a new security problem.

@silverwind
Copy link
Member Author

Yes, the sessioner topic needs to be properly fixed first: https://gitea.com/go-chi/session/issues/7.

@silverwind
Copy link
Member Author

silverwind commented Sep 9, 2023

I lost motivation here, if someone wants to do the AppURL parsing, please raise a separate PR, I'm not really interested in doing that.

@silverwind silverwind closed this Sep 9, 2023
@silverwind silverwind deleted the autosecure branch September 9, 2023 14:26
@wxiaoguang
Copy link
Contributor

-> Use secure cookie for HTTPS sites #26999

@go-gitea go-gitea locked as resolved and limited conversation to collaborators Dec 8, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. pr/breaking Merging this PR means builds will break. Needs a description what exactly breaks, and how to fix it! size/L Denotes a PR that changes 100-499 lines, ignoring generated files. type/enhancement An improvement of existing functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants