10

General:

Request URL:x/site.php
Request Method:OPTIONS
Status Code:302 Found
Remote Address:x.x.x.x:80

Response Headers:

view source
Access-Control-Allow-Headers:Content-Type
Access-Control-Allow-Origin:*
Access-Control-Max-Age:300
Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Length:0
Content-Type:text/html; charset=UTF-8
Date:Thu, 02 Mar 2017 14:27:21 GMT
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Location:y
Pragma:no-cache
Server:Apache/2.4.25 (Ubuntu)

Request Headers:

view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
DNT:1
Host:x
Origin:http://127.0.0.1:3000
Pragma:no-cache
Referer:http://127.0.0.1:3000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.90 Safari/537.36

Apache virtualhost config looks as so:

    <IfModule mod_headers.c>
           Header set Access-Control-Allow-Origin "http://127.0.0.1:3000"
           Header set Access-Control-Allow-Origin "http://127.0.0.1"
           Header set Access-Control-Max-Age "300"
           Header set Access-Control-Allow-Credentials "true"
           Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept"
           Header set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, PATCH, OPTIONS"
    </IfModule>

The preflight request is skipping the apache config and hitting my webapp directly, which does a redirect (hence the 302 and the location: y).

I don't know why the preflight request is not being handled by apache?

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
basickarl
  • 37,187
  • 64
  • 214
  • 335

1 Answers1

31

To fully CORS-enable an Apache web server, you need to have it configured to look like this:

Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Headers "Authorization"
Header always set Access-Control-Allow-Methods "GET"
Header always set Access-Control-Expose-Headers "Content-Security-Policy, Location"
Header always set Access-Control-Max-Age "600"

RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

Longer explanation at https://benjaminhorn.io/code/setting-cors-cross-origin-resource-sharing-on-apache-with-correct-response-headers-allowing-everything-through/

Some general notes on what values to set for the various Access-Control- response headers:

  • Access-Control-Allow-Headers: you must set it to include any header names your request sends except    CORS-safelisted header names or so-called “forbidden” header names (names of headers set by the browser that you can’t set in your JavaScript); the spec alternatively allows the * wildcard as its value—so you can try it, though some browsers may not support it yet: Chrome bug, Firefox bug, Safari bug.

  • Access-Control-Allow-Methods: the spec alternatively allows the * wildcard—but again, as with Access-Control-Allow-Headers: *, some browsers may not support it yet.

  • Access-Control-Expose-Headers: set to include any response headers beyond Expires, Cache-Control, Content-Type, Pragma, Last-Modified, and Content-Language that your frontend code needs to read. A lot of people forget to set this and end up baffled about why they can’t read the value of a particular response header). Again the spec alternatively allows the * wildcard here, but some browsers may not support it yet.

  • Access-Control-Max-Age: Chrome has an upper limit of 600 (10 minutes) hardcoded, so there’s no point in setting a higher value for it than that (Chrome will just throttle it down to 10 minutes if you set it higher, and Safari limits it to only 5 minutes).


So then, about the particular request shown in the question, the specific changes and additions that would need to made are these:

  • Use Header always set instead of just Header set.

  • Use mod_rewrite to handle the OPTIONS by just sending back 200 OK with those headers.

  • The request has Access-Control-Request-Headers:authorization so in the Apache config, add Authorization in the Access-Control-Allow-Headers response header too.

  • Origin is a “forbidden” header name set by the browser, and Accept is a CORS-safelisted header name, so no need to include them in Access-Control-Allow-Headers.

  • The request sends no Content-Type, so no need for it in Access-Control-Allow-Headers in the response (and never needed for GET requests and otherwise only needed if the type is not application/x-www-form-urlencoded, text/plain, or multipart/form-data).

  • For Access-Control-Allow-Methods, the request seems to just be a GET, so unless the plan’s to also make POST/PUT/DELETE/PATCH requests, no point in including them.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
  • Thanks for this! First of many posts that worked/made sense for me. – Jon Vote Feb 27 '19 at 19:40
  • 1
    Having `Header always set Access-Control-Allow-Origin "*"` seems to defeat the point of CORS. – Chris Stryczynski Nov 23 '20 at 16:03
  • @ChrisStryczynski See the answer at https://stackoverflow.com/a/43154277/441757. I know there are some guides/sources who assert or imply that the point of CORS is to block other sites from being able to access your content. But that’s not actually the point of CORS at all — instead the point of CORS is to prevent privilege-escalation attacks. See for example the answer at https://stackoverflow.com/a/29167709/441757. And if your site doesn’t use/require credentials for access, then there’s no privilege-escalation attack to prevent — `Access-Control-Allow-Origin: *` is safe to use. – sideshowbarker Nov 23 '20 at 16:48
  • @ChrisStryczynski CORS isn’t actually intended as a way for blocking all access to your content from other sites, and in fact CORS is not at all an effective way to block all access to your content from other sites — because your content is still accessible from servers-side backend code. So for anybody who does actually want to block access, setting up some kind of authentication mechanism is the right way to do that — because that will also block access from server-side backend code too. – sideshowbarker Nov 23 '20 at 16:54
  • Neither the question or answer has stated this wildcard though - so ideally this caveat should be mentioned. – Chris Stryczynski Nov 23 '20 at 18:16
  • I am using pdfjs.js to display PDF from another website and getting ERROR: file origin does not match viewer's. I tried this suggestion and still no result. – WilliamK Aug 20 '21 at 04:30
  • my hero and my life saver – Alireza Seyedzade Jan 15 '22 at 00:35