In the not so recent past, I thought it would be cool to try to spin up a SPA with no backend that could do a couple of simple things.
- Play a song in mp3 format from a local folder
- Make GET requests to a CDN that hosts song files, find a song url, and then embed the song’s source url in an audio tag for playback on the SPA
Pretty Simple right?
Well part one isn’t so difficult, but part two is where you begin to see something interesting. We’ll be looking at the example code to make it easier to follow along.
The index page has a link to a relative path that contains the song. Playing that is as simple as loading up the web page and clicking on the play button.
In the ‘index.js’ script there is a function that makes a get request to a url that serves as a download link for an mp3 somewhere on the internet.
So if we load the page and click the button that says “Get and Load Song” we would theoretically be able to take that songs url, and set it as the ‘src’ attribute for an audio tag we have embedded on the page. The audio should play once that src attribute has been set. Let’s see what happens if we try to do this.
So what happened? Well a lot of things actually, but it really boils down to one thing…CORS
CORS stands for Cross Origin Resource Sharing. Even the words in the acronym need some unpacking before any of this makes sense.
an Origin consists of three things:
This sounds confusing but its just a way of breaking down what most of us would consider to be parts of a URL.
The scheme is the protocol part —> http, https, ftp, …
The Host is the name of website or endpoint — -> example.com
And the port is where the server of the website is listening to incoming requests — -> “80”, “3000”, …
A Resource would be any content that the host could potentially serve up to a client that requests it, it could be anything from files, to video, to audio …
CORS in a nutshell is like a protocol that servers can implement to control access to WHICH domains can access specific content that they are hosting. It operates on what’s known as the “Same Origin Policy”, meaning, that content that is allowed to be accessed by any given domain, has to have the same origin in order for its access privilege to be maintained. If the protocol, host, or port of an origin are in any way changed or are different than what the server has specified it needs to have in order to access content, that client will be denied access. In the example case here, my domain is my IP address, and I’m trying to get content that is hosted on a server which has implemented CORS restrictions. Since my domain was not specified by the server as having any permissions to access that content, my get request was denied.
How this works is that when I send a request to get that mp3 from a website. The CORS protocol on their server sends back a response to my fetch request which contains information about whether or not my domain is allowed to access the content I’m trying to get. This comes in the form of a special kind of header
The address specified in the domain part of this header indicates which clients would be able to access the content. The most open way of implementing CORS (and most counterintuitive) would be to send back and attach a header to my request with an
This would mean any domain can access the content. This opens up problems regarding data security for clients and servers, but more on that later
This header may also specify which domains are able to access the content. Like so
Permissions may also be granted to a client by use of credentials, which can take the form of session data or cookies. These would have to be specified in a fetch request, and if authentication passes, the requested content can be served to the client.
So why is this a thing?
Authentication checks exist for a reason. You wouldn’t want to live in a world where people with ill-intent could make a request to, let’s say, a social media profile that houses your personal information, or an online banking portal that has your very sensitive financial information. Ideally browsers prevent anyone from accessing that content. CORS is a way of handling correct and incorrect responses coming from clients to access information. A common scenario where data can be compromised is a Cross-Site-Scripting attack. CSS attacks involve injecting scripts into elements on an HTML page through some vulnerability on a given element. These scripts can collect sensitive information like usernames and passwords, which if accessed can render CORS restrictions obsolete.
Not trying to scare anyone, but I was pretty confused the first time I came across this error for something that I thought was pretty innocuous. But when it comes to the internet, you can never be too careful…