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
[Feature] Enhance Security Middleware #1029
Comments
Interesting, that could indeed be an easy win. It would be great to initialize this with some "works out-of-the-box" configuration, like setting allowed domains to |
Word of caution: The |
That's the trade off for these headers. Browsers are typically fine with implementing them correctly, but other software - such as LBs, client libs, sdks, sometimes even proxies - do not always adhere to those as most HTTP servers are very forgiving wrt to headers. I am thus also a bit hesitant on my decision. On the one hand, we do have TLS and CORS support in the server, but is it really supposed to be there? Shouldn't that be something a global proxy handles for all of the application? Then again, some custom logic is required, for example for client-specific cors handling. If we add every feature above (and make it configurable) to the stack, we will end up with a ton of options for configuration. I always knew that this would happen in the end but I really want to avoid configuration nightmares that are e.g. apache configs. Any ideas? |
I think we should put some easy-win security headers in hydra - given that hydra's function is explicit to a certain purpose and is supposed to be hardened, some headers such as the XSS, No Sniff, CSP (dynamic for frame-ancestors?) should be set without question (e.g. not user configurable). I think adding a HSTS option should be quick/useful given there is already so many controls around TLS (I'd suggest to make this automatic as well but it can have lasting effects on a users domain that may be unintended). CORS in hydra needs to be revisited in general - we can leave that for the other ticket. Users don't always have control over load balancer's/reverse proxies that sit in front of hydra, or may have to setup one for adding such headers. Overall, I think if hydra is billed as a hardened security appliance it should put some default, hard-coded headers in place as appropriate for its function, leaving the rest to user's where deployment specifics may warrant tweaks (e.g. forwarding TLS requests over HTTP, CORS, HSTS, etc.) With cobra/viper in hydra, config can be as easy as a YAML file - though I know there are a lot of options already. Sensible defaults are already provided and I think it's great hydra gives advanced control over its operation for advanced deployment scenarios. |
Ok, that makes sense to me. Would you be open to tackle this? |
Yes I can tackle this. Just so we're on the same page, here is what I'd plan to do:
Although the middleware does overlap in terms of enforcing HTTPS connections, it doesn't have a health check bypass or IP enforcement check like hydra gives options for so I think it's best to leave those as-is. I could complicate the middleware to bypass the secure middleware on health checks and still keep an IP check middleware somewhere after this one - what do you think? As for CSP - I think this should be set statically here, but only have we introduce dynamic CSP options on a per-client basis. This can be done by auto-whitelisting redirect URIs like some providers do or introduce a CSP Referrer option to clients like there are for CORS. I can open a new issue to track this. |
Sounds good.
Here is where I'm a bit confused. HSTS is a useful technology, but I don't see the use for it in Hydra. Hydra runs only in two modes - HTTPS or HTTP. If HTTPS is enabled, no HTTP can be exposed. As such, it's not possible to "accidentally" connect to HTTP instead of HTTPS in Hydra. If we do have some proxy magic (with potential TLS term / http & https) going on, wouldn't that imply that we want to solve HSTS for the whole domain in the proxy?
Per-client CORS is already enabled, it's the |
HSTS will ensure no MITM attacks are possible - e.g. ALWAYS disallow HTTP at the client level, it doesn't matter if hydra is configured to only accept HTTPS, but HSTS explicitly forbids HTTP. This will make it so a client (e.g. a web browser) won't accidentally connect to a HTTP server if a MITM attack occurs. Not all Load Balancers support adding headers on responses (e.g. Google's cloud load balancer) so adding the option in hydra would make sense. It's up to the user to understand the ramifications of enabling this feature if the domain is shared with other services - I personally deploy hydra in a dedicated host with a dedicated subdomain. Re CORS vs CSP: I understand Per-client CORS is already enabled, I was asking if we should do the same for CSP headers. My idea is to explicitly disallow everything via CSP by default and only enable domains on a per-client basis as we do CORS. |
Ok, let's add it then. However, will this be disabled in https / ALLOW_TLS_TERMINATION_FROM mode? Or should we deploy this independently from that? In either case, I think configuring this with env vars is an option.
What attack surface does hydra offer for CSP-relevant issues? The only endpoint that could potentially be vulnerable is the Therefore, because we do not actually serve any HTML, CSP could be simply |
I think HSTS is independent of the other HTTP settings - regardless of whether or not hydra is running with its own cert, behind a secure proxy, or in HTTP mode; if the user enables the option(s) then it should be used. It's only possibly incorrect to enable the feature if running in HTTP-only mode so we could add a check in for that to warn the user. I think we should still discuss the flexibility of the HSTS options though - should it be a single option with sensible defaults, a single option which passes the header through (e.g. the user passes in the header's value as an option), or break each part into separate options for the user to configure and we assemble the header in code (e.g. preload, subdomain, age). I think we're on the same page for CSP - nothing in hydra should load anything external so by default the value you gave should be used ( |
And disable/warn if we're running on localhost? I think sensible defaults are good for now. If people complain we can update it. I'd set a long max-age and would not include subdomains as it doesn't make sense for hydra to control this.
Hm I don't think it adds any value to let clients configure Frame Ancestors. If I can do bad stuff with an iframe I can bypass your CSP policy by registering a client and whitelisting the frame, right? |
On second thought, I don't think restricting the frames makes a lot of sense. It's actually by design allowed. This is definitely different for the login and consent page which should set those headers as you want to disallow messing with that. |
I think it should only be allowed on whitelisted domains? Here were my thoughts on it:
Regarding the login/consent pages within the iframe - yes the developer will need to figure this out on their own. There is a section from the spec that discourages the use of iframes completely. Some providers allow it (e.g. Google) and some don't (Fitbit, Intuit). For silent refresh to work in the background, I think hydra must allow it. Additionally, since I think you have a much better understanding of all this so if you think we should just leave it be in hydra, I'd be happy to oblige - we can at least set the default CSP to |
Yeah, I think we should go with |
Regarding disabling iframe alltogether..well..openid connect is "special" here, they rely on iframes for things like silent refresh. I think FitBit is doing the right thing by disabling this. IMO silent refresh is obselete anyways because we have PKCE flows which give you refresh tokens. |
Regarding PKCE + Silent Refresh - there is no way to secure data in the browser, and since PKCE was written with "apps" in mind - not necessarily all public clients such as a web browser, I don't think there is a good way to use refresh tokens with PKCE in the browser. That said, refresh tokens should be avoided in the browser and mechanisms such as silent refresh should instead be used IMHO. I think it's a defense-in-depth mechanism to only allow the auth handler in an iframe from a whitelist - let the developer decide if it's ok to embed the authorization handler as an iframe, and only on trusted domains. |
Point made, point taken. The question for me is if it's less secure to keep secrets in the browser (like refresh tokens) or to enable iframes (and clickjacking) in ORY Hydra. I'm not sure which one's which, but attacking one specific app that keeps the secret in the browser (using XSS to extract the refresh token) has less impact then clickjacking with an iframe which is for the whole domain. I'm really not sure what's best here.
I think
As the authorization server owner, allowing iframes globally is as secure as allowing iframes per client. I hope it's possible to follow me here. |
I think I follow and I guess most situations are avoidable as long as the login, consent, and actual app correctly have CSP headers in place to prevent framing them. The auth handler will always redirect to one of these, all of them being whitelisted (hopefully HTTPS) destinations. I think the RFC assumes that the authorization server's The attack also assumes that the owner of the hydra server is allowing public or otherwise non-vetted clients to register, thus allowing a malicious actor access to carry out such an act (this goes to your second point). For users of hydra where clients are more strictly created, allowing per-client CSP options may be valuable but I guess arguably not necessary. I'll get a PR together. To re-cap:
|
Awesome! Yeah let's disable HSTS preloading for now. |
Closing due to lack of public interest. |
Just flagging that I hit a production use case for being able to have out of the box support for HSTS headers in case interest returns. ty! |
Hi, I also have a need to add HSTS headers to Hydra, so just dropping a message here to show interest for this :) |
I think there may be room to increase security of Hydra with some simple headers. I suggest possibly integrating https://github.com/unrolled/secure as a middleware. Some suggested headers to allow configuration for:
frame-ancestors
option to only whitelisted domains (and maybe X-Frame-Options as well?)/.well-known/
path)?The text was updated successfully, but these errors were encountered: