Skip to content

Instantly share code, notes, and snippets.

@aleph-naught2tog
Last active February 14, 2019 06:20
Show Gist options
  • Select an option

  • Save aleph-naught2tog/ade6da8c0b93c9ef822188f2cd413c16 to your computer and use it in GitHub Desktop.

Select an option

Save aleph-naught2tog/ade6da8c0b93c9ef822188f2cd413c16 to your computer and use it in GitHub Desktop.
CORS notes

CORS wtf

preflight

tl;dr

  • yes, cross-origin includes different port numbers. to the IT students everyone pulling their hair out because two localhosts on your machine can't talk to each other: we salute you.
  • what is a simple request?
    • one of [GET, HEAD, POST] -- no side effects.
    • the ONLY manual (ie, not added by the browser) headers allowed are:
      • Accept
      • Accept-Language
      • Content-Language
      • Content-Type
      • Last-Event_id
      • DPR
      • Save-Data
      • Viewport-Width
      • Width
    • Content-Type : one of [application/x-www-form-urlencoded, multipart/form-data, text/plain]
    • MUST NOT
      • have a listener on the XMLHttpRequest.upload
      • be a ReadableStream
  • at minimum:
    • a preflight will have:
      • Origin: http://some.origin:maybe_port
      • Access-Control-Request-Method: POST
      • Access-Control-Request-Headers: Content-Type, X-Custom-Fancy-Header
    • a successful response will have:
      • a response code of 200-something
      • Access-Control-Allow-Origin: http://some.origin:maybe_port (or a wildcard which the URL passes)
      • Access-Control-Allow-Methods: POST and maybe other methods
      • Access-Control-Allow-Headers: Content-Type, X-Custom-Fancy-Header and once again maybe others

If the preflight fails, the request WILL NOT BE SENT. If the response headers do not have those, the request WILL NOT BE SENT. If the server responds with something that is NOT a 200 to the OPTIONS header, the request WILL NOT BE SENT.

preflight: when a pre-emptive HTTP request is made of type OPTIONS -- direction: the REQUESTER makes a preemptive OPTIONS request to the target resource, the server.

the BROWSER -- client -- determines whether it should send a preflight request.

the client sends an initial request of OPTIONS, which includes the headers it plans on sending (as labels) and the method

  • Access-Control-Request-Method: what the upcoming method will be
  • Access-Control-Request-Headers: custom if any headers

the server responds if this is okay -- and responds with usually

  • Access-Control-Allow-Origin: allowed host
  • Access-Control-Allow-Methods: a list of allowed methods
  • Access-Control-Allow-Headers: a list of acceptable headers
  • Access-Control-Max-Age: how long this preflight request may be cached for

when do browsers preflight

  • authorization header
  • application/json
  • any of the following methods: PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
  • any headers which ARE NOT in this list:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • Last-Event_id
    • DPR
    • Save-Data
    • Viewport-Width
    • Width

credentials

  • XMLHttpRequest, Fetch, Request will not send cookies by default
  • .withCredentials will send the cookies
  • if the client says "hey, I'm sending credentials":
    • and the server does NOT respond with Access-Control-Allow-Credentials: true -- the response will be ignored by the browser
    • and the server DOES respond with Access-Control-Allow-Credentials: true -- the response will be accepted by the browser
  • the server must specify an Access-Control-Allow-Origin whose value is NOT a wildcard for credentialed requests
  • to repeat: if you need cookies OR Http Auth, a cross-site response MAY NOT Allow-Access-Control-Origin: *

Response Headers

What returned resource, from the server, would send back.

think like radioing a tower -- 'access control, allow origin http://some_url.org'

Access-Control-Allow-Origin

  • `Access-Control-Allow-Origin: | * | null
  • what URI origin is allowed

Access-Control-Expose-Headers

  • Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
  • which RESPONSE headers may be exposed in the response

Access-Control-Max-Age

  • how long, in seconds, a result may be cached

Access-Control-Allow-Credentials

  • in preflight, says whether the real request may have credentials
  • GET does not get preflighted by default, so if you GET with credentials and the server does not explicitly allow it, it will fail

Access-Control-Allow-Methods

  • allowed method(s) in the actual request

Access-Control-Allow-Headers

  • allowed headers in the actual request

REQUEST headers

These are set by the user-agent.

Origin

Access-Control-Request-Method

Access-Control-Request-Headers

User-Agent Only Headers

user-agent : usually the browser -- what makes the request on behalf of the user. These headers may only be set by the user-agent so they can remain in control of the request.

  • Accept-Charset
  • Accept-Encoding
  • Access-Control-Request-Headers
  • Access-Control-Request-Method
  • Connection
  • Content-Length
  • Cookie
  • Cookie2
  • Date
  • DNT
  • Expect
  • Keep-Alive
  • Origin
  • Referer [sic]
  • TE
  • Trailer
  • Transfer-Encoding
  • Upgrade
  • Via

sources:

cors proxy

make a filter!

  • hit the endpoint first of the proxy by literally gluing the urls together
  • proxy_url/original_url as your endpoint
  • the proxy send the request to original_url
  • the proxy gets the response
  • the proxy adds Access-Control-Allow-Origin: original_url
  • the proxy passes that response back

for credential issues

  • if you control the server -- make the Access-Control-Allow-Origin value be that of the Origin
@JoshCheek

Copy link
Copy Markdown

one of [GET, HEAD, POST] -- no side effects

POST is expected to have side effects, I'm guessing the reason it chooses these is that there's some way to send these without using JS? Maybe they can all be specified as a form's method or something?

  • XMLHttpRequest, Fetch, Request will not send cookies by default
  • .withCredentials will send the cookies
  • if the client says "hey, I'm sending credentials":
    • and the server does NOT respond with Access-Control-Allow-Credentials: true -- the response will be ignored by the browser
    • and the server DOES respond with Access-Control-Allow-Credentials: true -- the response will be accepted by the browser
  • the server must specify an Access-Control-Allow-Origin whose value is NOT a wildcard for credentialed requests
  • to repeat: if you need cookies OR Http Auth, a cross-site response MAY NOT Allow-Access-Control-Origin: *

Oh, super glad I read this, there's like 3 huge landmines in here that I'm pretty sure I'd have stepped on.

Access-Control-Allow-Origin: <origin>[, <origin>]* | *

Not sure I understand the notation here, does the first star mean "0 or more" (a Kleene star) and the second one mean "wildcard" or "all domains"?

Hmmmmmm... 🤔 the star seems more sensible given that multiple origins are allowed. I didn't realize this was the case, where did you find this? The one I'm looking at (https://fetch.spec.whatwg.org/#http-new-header-syntax) makes it seem like I can only have a single origin.

Okay, I looked at the MDN resource you linked, and it also says this: (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin)

But I'm like 90% confident that I have seen a site send down a giant list of origins. I specifically remember going to some website and pasting in a giant list of domains and it parsed them for me, and I submitted that in a bug report, pointing out that the broken domain wasn't in the list. But I can't remember how long ago it was or what site it was or...

Figured it out! It was the content security policy header:

$ curl -I 'https://www.customink.com/fundraising'

So then I think this one can only have a single origin.

cors proxy*

Interesting! This is to get visibility into the requests and responses?

for credential issues

  • if you control the server -- make the Access-Control-Allow-Origin value be that of the Origin

Yeah, good call, I'm going to have to check mine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment