The labs on this site need JavaScript to run. The same content is written out below.
Fundamentals › Security
What is an origin, and why does the browser tell different origins apart?
An origin is the combination of three parts at the start of an address (URL): the scheme (https or http), the host (the site name), and the port (a number). If any one of the three differs, it is a different origin, and the path and query that come after are not part of the origin. The browser blocks a script running inside a page from reading the response to a request sent to another origin. This rule is the same-origin policy. In this lab, the code box lists the address of the page that is open and the address that the script of that page requests. You change the requested address one part at a time and see whether the browser treats the origin as the same, whether the request arrives at the server, and whether the script reads the response. The code box is not a program but two addresses. The way a server allows reading (CORS) is not covered in this lab.
Partly checked against real execution · The origins of the five addresses were calculated with Node.js 24.18.0 URL, and whether the response is read and whether the request arrives at the server were checked on the PC used to write this lab with Chrome (run without a window) and a 127.0.0.1 test server, with differences made in port, host, and scheme. The shop.example addresses on the screen themselves and all the rules of the browser's decisions were not run and were checked against the documentation
# The page that is open now https://shop.example/cart # The address that the script of that page requests https://shop.example/api/items
The code box is not a program that was run. It lists the address of the page that is open and the address that the script requests, and shop.example is a reserved example domain, so there is no real server behind it. So we checked in two layers. First, we calculated the origins of the six addresses on the screen (one page and five requested addresses) with the URL standard implementation of Node.js 24.18.0 (new URL(...).origin), and checked against the model whether they are the same origin and which of the scheme, host, and port differs. The same calculation also showed that the origin of https://shop.example:443/x comes out as https://shop.example, the same as for an address with no port written (the default port is left out), and that addresses with a different path and query have the same origin. Second, whether the browser hands the response to the script was checked by running Chrome 155 (HeadlessChrome) on the PC used to write this lab without a window (--headless=new --dump-dom). We started a test server on 127.0.0.1 that adds no CORS headers (on a free port), and made the script of the page that the server sent request the addresses below with fetch and write the result into the page. For the same origin, we requested /api/items of the same server; for only the path and query differing, /other?x=1 of the same server; for a different host, the name localhost on the same computer and the same port (the page was on 127.0.0.1); for a different port, a server on another port; and for a different scheme, we made an https request (with a self-signed certificate) to a server that takes http and https separately on the same port. In all five combinations the request arrived at the server; for the two same-origin ones the script read the status 200 and the body, and for the other three the script received a TypeError (Failed to fetch) and could not read it. The addresses in this experiment made the same differences as the addresses on the screen, but they are not the addresses on the screen themselves. The scheme experiment requested an https address from an http page, which is the opposite direction of the example on the screen (an http address from an https page), so we also ran the same direction as the screen (an http address from an https page) separately and confirmed that the script could not read it and that the request arrived at the server. The scheme example on the screen differs in the port too (80 for http, 443 for https) along with the scheme, but the Chrome experiment made only the scheme differ. A request to the same origin had no Origin header, and a request to another origin had an Origin header, but the screen does not cover this. When we requested a port where the server was off, the error the script received was the same TypeError (Failed to fetch) as in the blocked case, and when the server of the other origin wrote the origin of the page in Access-Control-Allow-Origin in its response, the script read the body. These are behaviors observed in this Chrome version, and we did not run other browsers or other versions. What we checked against the documentation is sections 3.2, 4, 5, and 6 of RFC 6454 (an origin is three values, the scheme, host, and port; if there is no port, the default port of the scheme is used; two origins are the same only when all three values are the same; and when an origin is written down, the default port is left out), sections 4.2, 4.4, and 4.7 of the WHATWG URL Standard (the default ports of http and https are 80 and 443, a default port is stored as null in a URL, and the origin of an http or https URL is a value made of the scheme, host, and port), the page Same-origin policy of MDN (addresses that differ only in the path are the same origin, reading from another origin is mostly blocked, the way to allow reading is CORS, and the purpose is to keep a script of a malicious page from reading the content of webmail you are logged in to), and the page Using the Fetch API of MDN (if the server of another origin does not send the allowing header, the browser does not share the response with the caller). The order in which the browser checks the allowing mark after receiving the response of the server, and the purpose of "protecting the content of other sites you are logged in to", follow the explanation in the documentation, and we did not run whether cookies actually go along. What the screen leaves out is the process of getting the page, the headers of the request and the response, and the interpretation of the response body. We covered only one ordinary GET request with no special headers. The case where the browser first asks the server before sending the request (a preflight request), requests that carry cookies, and the way a server allows reading (CORS) are covered in the in-depth lab "CORS", attacks aimed at origins in the in-depth lab "Three web attacks", and putting a page of another site into a frame in the in-depth lab "Clickjacking and open redirects". We also did not cover the fact that loading images and script files from another origin (embedding) is usually allowed, or the remaining origin rules (cookies, storage, and so on).
Previous lab: Encryption · Next lab: Input and injection
Struck-through text was removed from the first version of the code; highlighted text was added.