2

We had a requirement to permit cross-origin requests provided that the origin was part of the corporate domain. While this question is not C# or Web API specific, the snippets below demonstrate our strategy.

We have a collection of regular expressions defining permitted origins:

    private static readonly Regex[] AllowedOriginPatterns = new[]
    {
        new Regex(@"https?://\w[\w\-\.]*\.company.com",
                  RegexOptions.Compiled | RegexOptions.IgnoreCase)
    };

Later, in our ICorsPolicyProvider attribute, we test the origin. If the origin matches any pattern, we add the origin to the set of allowed origins:

    var requestOrigin = request.GetCorsRequestContext().Origin;
    if (!string.IsNullOrWhiteSpace(requestOrigin) &&
        AllowedOriginPatterns.Any(pattern => pattern.IsMatch(requestOrigin)))
    {
        policy.Origins.Add(requestOrigin);
    }

The perk of this approach is that we can support a large and flexible set of authorized origins, and restrict unauthorized origins, all without placing hundreds of origins in our headers.

We have an issue with HTTP header rewriting on the part of our reverse proxy. Under some circumstances, the reverse proxy replaces the Access-Control-Allow-Origin value with the host. Seems fishy to me, but that is not my question.

It was proposed that we change our code so that if the origin meets our precondition that we return * instead of echoing the origin in the response.

My question is whether we open a potential security vulnerability by returning Access-Control-Allow-Origin: * to origins that match our preconditions. I would hope that browsers check the access control headers with every request. If so, I am not overly concerned. If not, I can imagine an attacker running an untrusted web site taking advantage of browsers that have previously received a * for a trusted origin.

I have read the OWASP article on scrutinizing CORS headers. The article does not reflect any of my concerns, which is reassuring; however, I wanted to inquire of the community before pressing forward.

Update

As it would turn out, this question is not valid. We discovered, after exploring this implementation, that allowing all origins for credentialed requests is disallowed. After troubleshooting our failed implementation, I found two small statements that make this quite clear.

From the W3C Recommendation, Section 6.1:

Note: The string "*" cannot be used for a resource that supports credentials.

From the Mozilla Developer Network:

Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding.

This proved ultimately disappointing in our implementation; however, I imagine the complexity of adequately securing credentialed CORS requests would explain why this is a prohibited scenario.

I appreciate all assistance and consideration rendered.

kbrimington
  • 25,142
  • 5
  • 62
  • 74
  • You might want search on [Information Security](http://security.stackexchange.com/), and maybe this question would be better asked there. – Jonathan Leffler Apr 08 '15 at 23:22
  • Thank you @JonathanLeffler. I hadn't heard of that exchange before. I'll list my question there. – kbrimington Apr 08 '15 at 23:23
  • We'll see how that goes. They do not have a CORS tag, which makes me wonder whether this is a topic of interest in that exchange. http://security.stackexchange.com/questions/85581/is-there-a-security-vulnerability-to-permit-all-cors-origins-if-the-request-orig – kbrimington Apr 08 '15 at 23:28
  • That's why I said 'search on Info.Sec' and 'maybe' ... I know of the site; I occasionally look at it, but I don't follow it in detail and don't know their rules or interests. The good news: the question has already been viewed over there more often than it has over here. – Jonathan Leffler Apr 08 '15 at 23:37

1 Answers1

1

My question is whether we open a potential security vulnerability by returning Access-Control-Allow-Origin: * to origins that match our preconditions.

Potentially, if the browser (or proxy server) caches the response. However, if you are not specifying Access-Control-Allow-Credentials then the risk is minimal.

To mitigate the risk of sending *, make sure you set the appropriate HTTP response headers to prevent caching:

Cache-Control: private, no-cache, no-store, max-age=0, no-transform
Pragma: no-cache
Expires: 0

Note that specifying private is not enough as an attacker could then target someone who has already visited your page and has it in the browser cache.

As an alternative, you might be able to use the Vary: Origin header. However, if some clients don't send the Origin header you might end up with * cached for all requests.

The best approach would be to fix the reverse proxy issue so that your page returns the appropriate Origin as per your code. However, if this is not feasible then * is fine, only if used with an aggressive anti-caching policy. Also, * for all requests may be fine if Access-Control-Allow-Credentials is false or missing - this depends whether your application holds sensitive user based state.

Community
  • 1
  • 1
SilverlightFox
  • 32,436
  • 11
  • 76
  • 145
  • Thank you, @SilverlightFox. I certainly agree that if the RP behavior can be fixed, that is to be preferred. Our situation does, in fact, make use of `Access-Control-Allow-Credentials`. If it matters, our environment makes use of Kerberos authentication. Does the aggressive no-cache policy you propose still mitigate the risks of sending `*` to authorized origins? – kbrimington Apr 09 '15 at 15:26
  • @kbrimington: Yes I believe so. There is a [cache built into the CORS specification](http://www.w3.org/TR/2008/WD-access-control-20080912/#cross-site2), however this is caches the response uniquely per Origin. If all proxies and browsers follow your cache rules, you should be good to go. – SilverlightFox Apr 09 '15 at 15:47
  • Much appreciated. I'll allow the RP admins a few days to scratch their heads on this one and proceed with the cacheless implementation should they come up empty-handed. I'll let this question sit a few more days before accepting; meanwhile, I very much appreciate your insight. – kbrimington Apr 09 '15 at 15:51
  • @kbrimington: How did it go? Did the RP admins come up with anything to solve the issue? – SilverlightFox Apr 21 '15 at 09:58