2

A simple same origin fetch("fetch.xml") fails here with the console error message

Access to fetch at 'http://127.0.0.1:8000/fetch.xml' from origin 'null' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://127.0.0.1:8000' that is not equal to the supplied origin. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

The corresponding network headers are

General
Request URL: http://127.0.0.1:8000/fetch.xml
Referrer Policy: origin

Response Headers
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Origin: http://127.0.0.1:8000
Access-Control-Max-Age: 86400
Content-Security-Policy: sandbox allow-scripts
Content-Type: text/xml
Date: Sun, 16 Aug 2020 06:20:43 GMT
Referrer-Policy: origin
Server: SimpleHTTP/0.6 Python/3.8.5

Request Headers
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
DNT: 1
Host: 127.0.0.1:8000
Origin: null
Pragma: no-cache
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36

As you can see the browser (here Chrome) says Origin = null, although the origin is the same origin. I can also reproduce this with a real domain instead of the ip address, the origin of the fetch is always null according to the browser.

If I change the fetch statement to fetch("fetch.xml", { mode: "same-origin" }) the browser still assumes null to be the origin, but the error message changes to

Fetch API cannot load http://127.0.0.1:8000/fetch.xml. Request mode is "same-origin" but the URL's origin is not same as the request origin null.

How can I get the browser to work with the right origin and not null for the fetch statement? I played around with the referrer-policy as you can see. I do not want Access-Control-Allow-Origin to include null or *, as this seems too open (basically disabling CORS).

Remark: I am not accessing the files by file:// URLs! This is a real web server and the origin is still null! So this question is not the same as the duplicate stackoverflow has linked to.



Minimum Reproducing Example

Simple server including everything if you want to test it quickly (simply run it with python3):

#!/usr/bin/env python3

from http.server import HTTPServer, HTTPStatus, SimpleHTTPRequestHandler, test
import sys
from urllib.parse import urlparse
import os

class TestRequestHandler (SimpleHTTPRequestHandler):
    def do_GET(self):
        """Serve a GET request."""
        url = urlparse(self.path)
        if url.path == '/' or url.path == '/index.html': # index.html
            f = self.send_head('text/html')
            self.wfile.write('''<!DOCTYPE html>
                            <html>
                            <head>
                                <title>Test</title>
                                <script type="text/javascript" src="control.js"></script>
                            </head>
                            <body>
                            </body>
                            </html>'''.encode('utf-8'))
        elif url.path == '/control.js': # control.js will try to fetch the fetch.xml
            f = self.send_head('application/javascript')
            self.wfile.write('''function init() {
                    fetch("fetch.xml", { mode: "same-origin" }).then(r => r.text()).then(t => console.log(t));
                }
                window.addEventListener("load", init);'''.encode('utf-8'))
        elif url.path == '/fetch.xml': # fetch.xml
            f = self.send_head('text/xml')
            self.wfile.write('''<?xml version="1.0" encoding="UTF-8"?>
                            <root>
                                <test>Hi</test>
                            </root>'''.encode('utf-8'))


    def send_head(self, ctype):
        self.send_response(HTTPStatus.OK)
        self.send_header('Content-Type', ctype)
        self.send_header('Access-Control-Allow-Origin', 'http://127.0.0.1:8000')
        self.send_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
        self.send_header('Access-Control-Max-Age', 86400)
        self.send_header('Referrer-Policy', 'origin')
        self.send_header('Content-Security-Policy', 'sandbox allow-scripts')
        SimpleHTTPRequestHandler.end_headers(self)

if __name__ == '__main__':
    test(TestRequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000)

If you prefer to put it on your own server with different files:

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
    <script type="text/javascript" src="control.js"></script>
</head>
<body>
</body>
</html>

control.js

function init() {
    fetch("fetch.xml", { mode: "same-origin" }).then(r => r.text()).then(t => console.log(t));
}
window.addEventListener("load", init);

fetch.xml

<?xml version="1.0" encoding="UTF-8"?>
<root><test>Hello</test></root>

The server should be set up to send the following headers (adapt the ip/domain):

Access-Control-Allow-Origin: http://127.0.0.1:8000
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Max-Age: 86400
Referrer-Policy: origin
Content-Security-Policy: sandbox allow-scripts
DanielB
  • 369
  • 4
  • 15
  • Thats why I included a webserver. It isn't working with a webserver. Even if the webserver is not locally. – DanielB Aug 16 '20 at 07:20

1 Answers1

2

This is your problem:

Content-Security-Policy: sandbox allow-scripts

See the documentation.

You didn't enable this directive:

allow-same-origin

Allows the content to be treated as being from its normal origin. If this keyword is not used, the embedded content is treated as being from a unique origin.

… so http://localhost:8000/ and http://localhost:8000/fetch.xml are treated as different, unique origins.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • Thank you very much :-) . I've already tried to remove the CSP relevant header entirely, which didn't help and I tried default-src etc., so I thought this wouldn't change anything. I didn't think of such a flag being existent. – DanielB Aug 16 '20 at 07:58