In my last TIL I talked about how to set additional security headers for Gitlab. But I also had to do this for other applications I was supporting, where it was more straight-forward to do it (meaning: with code).
I needed to set the access-control-allow-origin
header in the other applications. This header tells the browser from which origins the website is allowed to download resources.
This is relevant in web apps that run on webapp-frontend.example.com
and want to use data from webapp-backend.example.com
.
To allow the browser to access webapp-backend.example.com
, the frontend application needs to allow it in its access-control-allow-origin
header, like this:
access-control-allow-origin: https://webapp-backend.example.com
So I set this in the frontend-application and wanted to test it from the command line.
Here’s how I did it:
curl -v --request OPTIONS 'https://webapp-frontend.example.com' -H 'Origin: https://webapp-backend.example.com' -H 'Access-Control-Request-Method: POST'
Of course I used curl for testing. To check if access-control-allow-origin
works, you send a OPTIONS
-request to check what methods are allowed by the application.
The header 'Access-Control-Request-Method: POST'
informs the application that I want to do a POST
-request (I guess that’s not strictly necessary to test the allow-origin header).
Now to finally test it, I deactivated the access-control-allow-origin
header, to see what will happen. Here’s the result:
> curl -v --request OPTIONS 'https://webapp-frontend.example.com' -H 'Origin: https://webapp-backend.example.com' -H 'Access-Control-Request-Method: POST'
* Trying 127.0.0.1:8000...
* Connected to 127.0.0.1 (127.0.0.1) port 8000
> OPTIONS /healthz HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/8.7.1
> Accept: */*
> Origin: https://webapp-backend.example.com
> Access-Control-Request-Method: POST
>
* Request completely sent off
< HTTP/1.1 400 Bad Request
< date: Fri, 06 Sep 2024 11:44:27 GMT
< server: uvicorn
< vary: Origin
< access-control-allow-methods: GET, POST
< access-control-max-age: 600
< access-control-allow-headers: Accept, Accept-Language, Content-Language, Content-Type
< content-length: 22
< content-type: text/plain; charset=utf-8
< content-security-policy: base-uri 'self'; connect-src 'self'; script-src; script-src-attr; frame-src; object-src 'none'; img-src; style-src; font-src; manifest-src; media-src; default-src
< referrer-policy: no-referrer
< x-frame-options: DENY
< x-content-type-options: nosniff
< cross-origin-embedder-policy: require-corp
< cross-origin-opener-policy: same-origin
< cross-origin-resource-policy: same-origin
<
* Connection #0 to host 127.0.0.1 left intact
Disallowed CORS origin
The last line tells you that my request was denied. You can also see that there are three access-control headers in the response (access-control-allow-methods
, access-control-max-age
, access-control-allow-headers
), but no access-control-allow-origin
.
Now I activate the header in the application and re-run the curl command:
> curl -v --request OPTIONS 'https://webapp-frontend.example.com' -H 'Origin: https://webapp-backend.example.com' -H 'Access-Control-Request-Method: POST'
* Trying 127.0.0.1:8000...
* Connected to 127.0.0.1 (127.0.0.1) port 8000
> OPTIONS /healthz HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/8.7.1
> Accept: */
> Origin: https://webapp-backend.example.com
> Access-Control-Request-Method: POST
>
* Request completely sent off
< HTTP/1.1 200 OK
< date: Fri, 06 Sep 2024 11:44:07 GMT
< server: uvicorn
< vary: Origin
< access-control-allow-methods: GET, POST
< access-control-max-age: 600
< access-control-allow-headers: Accept, Accept-Language, Content-Language, Content-Type
< access-control-allow-origin: https://webapp-backend.example.com
< content-length: 2
< content-type: text/plain; charset=utf-8
< content-security-policy: base-uri 'self'; connect-src 'self'; script-src; script-src-attr; frame-src; object-src 'none'; img-src; style-src; font-src; manifest-src; media-src; default-src
< referrer-policy: no-referrer
< x-frame-options: DENY
< x-content-type-options: nosniff
< cross-origin-embedder-policy: require-corp
< cross-origin-opener-policy: same-origin
< cross-origin-resource-policy: same-origin
<
* Connection #0 to host 127.0.0.1 left intact
OK
Now two things have changed:
- I get back a
OK
-response indicating that my request ist allowed. - There’s now a header in the response:
access-control-allow-origin: https://webapp-backend.example.com
And that’s it. With this simple method you can test on the command-line if your access-control-allow-origin
works.