cors: Leaking headers?

Let me preface this by saying that this module works great and seems generally well-thought-out, and it’s not at all clear to me what the best practice for exposing Access-Control-* headers is in every situation (or even if there is a consensus on best practice), but it seems to me that the code leaks information in a couple of ways:

  1. If the origin setting is set to a string (a “fixed” origin), then the Access-Control-Allow-Origin header is always returned with that value, regardless of the request origin.
  2. All of the other Access-Control-* headers are always returned regardless of whether the request origin is in the whitelist.

I’m fairly certain that an AJAX request from a non-whitelisted origin will not have access to these headers (that is, the browser will not provide them in the response), but you can still see them by, for example, looking in the “Network” tab of the Chrome developer console.

I don’t see the rationale for exposing the criteria for acceptance to a requestor that doesn’t meet those criteria. For example, if you had an admin app on some subdomain (“xyzadmin.myapp.com”) that you didn’t want to be made public, and you have your main app (“myapp.com”) accepting cross-origin requests only from that domain, it doesn’t seem right that by making an AJAX request to myapp.com from any random domain you could get the Access-Control-Allow-Origin header with the value xyzadmin.myapp.com and thus learn about that existence of the admin server. Similarly, if someone made an AJAX PUT request to some route and it was rejected for not matching the whitelist of available methods, why would you want that person to be given the list of available methods that are allowed?

What’s even more curious to me is that in this module’s implementation, specifying the origin setting as an array always does what I would consider the best behavior, which is to not send the Access-Control-Allow-Origin header at all if the requesting origin doesn’t match the whitelist. It does this even if the array only has one item.

Absent a good reason to send back all this information, I’d propose that any request whose origin doesn’t match the whitelist should be responded to without any Access-Control-* headers at all, and I’d be happy to submit a patch to make things work that way. I’d even go so far as to say that requests that do match the origin whitelist should only be given as much information as is necessary to satisfy the browser (that is, instead of Access-Control-Allow-Methods showing all the allowable methods, only reflect the one that was actually used in the request), but I’m not quite as bullish on that point.

I’m also fully prepared to hear that I don’t know what I’m talking about and that there is a perfectly reasonable explanation for the current behavior. I wouldn’t be surprised if it’s hidden in the W3C CORS spec, clear as mud.

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Reactions: 6
  • Comments: 18 (6 by maintainers)

Most upvoted comments

Wow, time flies. I actually got the code for this done pretty quick, but ran out of gas re-working all the tests. Plugging away…

Thanks for the bump y’all. Will revisit this week. Again, the delay was in getting all the tests in order.

Yes, if this is operating contary to the CORS spec, then it should be changed. If the CORS spec says the way this works now it should not change. If the CORS spec does not say either way, add it as an optional behavior change.

I haven’t really studied how this module is working specifically, which is what I was going to look into. Just back up the pull request with a reference to what the spec says is all.

I hope that makes sense.