0

in the AMP Docs, the following snippet is given:

If the Origin header is set:

  1. If the origin does not match one of the following values, stop and return an error response:

    • <publisher's domain>.cdn.ampproject.org

    • the publisher's origin (aka yours)

      where * represents a wildcard match, and not an actual asterisk ( * ).

  2. Otherwise, process the request.

If the Origin header is NOT set:

  1. Verify that the request contains the AMP-Same-Origin: true header. If the request does not contain this header, stop and return an error response.
  2. Otherwise, process the request.

What I don't understand is how the AMP-Same-Origin header provides a form of security.

TLDR:

Couldn't anyone provide an AMP-Same-Origin: true header in a browser missing the Origin header and skip CSRF protection even if it's not on a trusted AMP CDN?

2 Answers2

1

It adds security for "simple" CORS requests that would otherwise not require an OPTIONS intermediate request. By requiring the AMP-Same-Origin when the Origin header is not set, you can fail all requests that would otherwise cause side effects, even if they weren't viewable at the endpoint, because they would not fail until they came back to the browser


It is not possible to add the AMP-Same-Origin header on a cross origin request if CORS isn't explicitly allowed. Thus, you do not need to add a random string like you usually would with a csrf token. Check this related question about it

Simply checking the value is sufficient at the moment, but future technologies and attacks may be leveraged to break your protection.

Simply checking for a custom header is sufficient for now. However, this is not the best practice and for additional defense in depth it is normally recommanded to have additional security in depth as per MDN

To prevent cross-origin writes, check an unguessable token in the request — known as a Cross-Site Request Forgery (CSRF) token. You must prevent cross-origin reads of pages that require this token.

You could also ask yourself (or not if you're already aware of it), why don't they just set the Origin header instead of setting an additional header ? Well, the Origin header is a forbidden header and cannot be set programmatically (MDN).

Xavier59
  • 2,874
  • 3
  • 17
  • 34
  • "Well, the Origin header is a forbidden header and cannot be set programmatically (MDN)." That's exactly the point of my question. If you're checking for a header that *can* be set programmatically, how does that even remotely change anything? the attacker can just set the `AMP-Same-Origin` header on a request using a browser they know doesn't sent the `Origin` header. At the least, the docs saying to respond with the source origin if `AMP-Same-Origin` is there, but I don't see the point of even checking a header that *anyone* can add just to respond with same-origin as the response anyways – Sampson Crowley Aug 24 '20 at 22:35
  • The reason it still provides protection is that the servers are told to only respond to same-origin requests if given `AMP-Same-Origin` and no `Origin` is given; so I don't see what the point is of even checking for the header instead of just responding to the request with your origin set as the "allow" value and letting it fail on its own; since the requests will fail CORS checks anyways if it's not from the same origin – Sampson Crowley Aug 24 '20 at 22:59
  • is it to guarantee that the request **is** an XHR request? – Sampson Crowley Aug 24 '20 at 23:12
  • If you are on `evil.com` and make a xhr request on `*.cdn.ampproject.org` and considering that ampproject.org doesn't have a CORS policy (aka `Access-Control-Allow-Origin: *` *and* `Access-Control-Allow-Headers: AMP-Same-Origin`), then you cannot set the `AMP-Same-Origin` header. The browser will forbid it when you will try to send the request. – Xavier59 Aug 25 '20 at 10:06
  • You cannot send a xhr request at all if it is not the same origin and `*.cdn.ampproject.org` doesn't send back the header `Access-Control-Allow-Origin: *`. The only thing you can do is make a `GET` or `POST` request via an image or a form. But you cannot trick the browser into adding `AMP-Same-Origin` – Xavier59 Aug 25 '20 at 10:09
  • `Access-Control-Allow-Origin` is a *response* header, it has absolutely nothing to do with the CDN servers for the AMP project. the `Origin` header allows your server to *respond* to `*.cdn.ampproject.org` safely; the instructions for `AMP-Same-Origin` tell you only to respond to *your own* origin. So again, I don't see the point of looking for the header when you're not responding with `Access-Control-Allow-Origin: *`, you're responding with `Access-Control-Allow-Origin: mydomain.com` – Sampson Crowley Aug 25 '20 at 15:46
  • "If you're checking for a header that can be set programmatically, how does that even remotely change anything? ". You're assemption is wrong. You cannot set programmatically the header `AMP-Same-Origin` if AMP doesn't send you the *response* headers I mentionned. I am not sure to get what you fail to understand here and I'd like to help. Come over to chat https://chat.stackexchange.com/rooms/112273/csrf – Xavier59 Aug 25 '20 at 19:10
  • you seem to be confused about *what* the AMP project is. no one is making *any* requests *to* `cdn.ampproject.org`. `cdn.ampproject.org` is a CDN that serves static caches of pre-rendered pages for instant delivery on mobile devices. it is the *`Origin`* not the endpoint/source server – Sampson Crowley Aug 25 '20 at 20:51
0

Couldn't anyone provide an AMP-Same-Origin: true header in a browser missing the Origin header and skip CSRF protection even if it's not on a trusted AMP CDN?

No, because if the request is cross-origin and sent with a custom header, it must send the Origin header.

This answer explains when the Origin header must be sent, and how the spec changed in 2016-12-09 and now all POST requests must send Origin.

But even before that, it notes that:

  • previously no Origin was sent for a same-origin POST
  • previously no Origin was sent for cross-origin POST from a (without CORS)

Therefore, even before 2016-12-09, a POST request without Origin and with a custom header set could only have been sent from the same origin.

A fetch request with method POST can be sent with mode no-cors, but then it won't send custom headers.