Attacks like CSRF or XSS are still not clear to many of us. It is not because they are super hard to understand, but it requires some basic understanding of concepts like SOP, CORS, CSP, HTTPS. In this series of posts, I’ll try to clear them up one-by-one, and next time you read about attacks, you’ll understand everything.
It is a security measure implemented by most browsers to protect users from the bad guys. It’s meant to keep you secure and it isn’t something new. It dates back to the old Netscape times. What it does is simple, blocks reading resources from other domains, only same-origin is allowed.
The resource here can be the DOM of an iframe you embedded in the page, a JSON response in an http request, or cookies.
Why does it exist? It’s there to keep you secure from the malicious scripts which might be running on the websites you visit. Although you’re visiting evil.com, scripts running on this site can make requests to my-bank.com/get-account-details, or embed an iframe with source my-bank.com/get-account-details and then try to read the response/DOM to access your data. In case you think “it’s fine as they don’t know my credentials”, think twice. Browser will use existing cookies for my-bank.com automatically. It means if you have an active session on my-bank.com, malicious scripts don’t need your credential.
There are also some common misconceptions on SOP. It does not block sending requests to the backend. It only blocks reading the response. “That’s great, let me trigger a call to mybank.com/transfer-money in my malicious script. I just want the request to reach the backend, I don’t care about the response, I’ll see it in my bank account anyways” you might be saying. Not that fast. Of course, from SOP point of view, that’s perfectly fine. But, there are other security measures to prevent that. That’s the most important aspect you should really understand about SOP. Let’s repeat again: you can freely send any request to any domain, SOP does not care about requests, it only blocks reading the response from other domains.
Due to the same reason above, SOP not blocking the requests, it does not help with CSRF attacks. This attack relies on sending the request under the hood with the cookies you already have for that domain . It does not care about the response.
If you’re saying “yes, there is no news here to me”, great! you can stop reading. Otherwise, keep going.
Protocol (http, https) +Host (example.com) +Port (8080)
- http://example.com:8000/abc due to different port
- https://example.com/abc due to different protocol
- http://test.example.com/abc due to different host
Please note that below examples assume there is no additional security checks at the backend and focuses on SOP only.
SOP saves the day and blocks reading the DOM of an iframe which belong to another domain.
I hear some of you saying “I never used iframe, do you have some other example?”. Okay, let’s give the same example without iframes. I own evil.com and you visit it since you don’t know I do evil things. The JS code I added in evil.com sends a GET request to gmail.com/get-all-emails. Do you think I’ll be able to send it?
The answer is yes (what?!). Just to point out again, SOP does not do anything for the requests, it blocks response only. My request will be sent to gmail and browser will get a 200 success. When my script tries to see the response, however, it won’t be able to, neither will you when you check Network/Response tab in Chrome dev tools. Browser will block it as SOP promised. (This can be relaxed using CORS though)
SOP rescues us again and blocks reading the response of an http request from another domain.
Web mostly relies on cookies for authentication. Web server sets some cookies for its domain so that it can identify you when it receives a request from you. To keep things simple, let’s say when you login to gmail.com it sets a cookie username="firstname.lastname@example.org" for domain gmail.com. Whenever there is a request going to gmail.com, your browser will add all your valid cookies belong to that domain. That means, when you call gmail.com/get-all-emails, it will also send username=”email@example.com” without you realising. And Gmail’s web server will see who you are from the cookie and return all the emails you have.
In real world, it’s not that simple. Gmail actually sets something to identify you, but it’s more complex and if anyone changes any part of that string, they would know and refuse to respond to your request.
I think it’s somewhat clear now that whoever has that string can actually get all your emails. So, it’s super important for the browser not to expose cookies from one domain to another one. Again, as being the owner of evil.com, I can send a request to gmail.com on your behalf and browser will include all cookies belong to gmail.com domain. But, the scripts running on evil.com won’t be able to read the cookies and server’s response. Yayy!
Just a small note on this: different protocol and port does not make a resource cross-domain for cookies. For example, http://example.com, https://example.com and https://example.com:7000 are considered as the same-origin.
“What about if I use a form” I hear you ask. Let’s say I did some JS tricks and submitted a form using my malicious code running on evil.com which sends a request to gmail.com/send-email with the payload I provided in the code. Same goes here, browser will send it. But after submitting, browser will take you from evil.com to the action url (ie. gmail.com/send-email), so evil.com couldn’t read the response from other domains as the user is redirected to gmail. Please note, this is not a feature of SOP, just default form behaviour in browsers.
Nope. You can still
- Embed iframes
- Use image, audio, video files
- Import script and css files
- Submit forms
- cannot read the DOM of the iframe you embedded
- cannot read the files/bytes of the image, audio and video files.
- cannot read the content of JS, CSS files you imported
- cannot read the response of the submitted form
In addition to that, there are some techniques for relaxing SOP. You can use Cross-origin Resource Sharing(CORS), JSON with Padding(JSONP), and some others. Please note, this is not something browser can do alone to workaround SOP. Both frontend and backend need to be configured properly to achieve accessing cross-domain resources.
Browsers implement SOP to keep your resources secure since you never now what’s going on behind the scenes when you visit evil.com. SOP does not prevent taking actions(sending requests etc), but makes sure bad guys won’t be able to see the outcome of that action(reading response/cookies/DOM).
It does not block you from using images, videos, scripts, css files from other domains. Long live CDNs! And there are ways to relax SOP by using things like CORS, JSONP.
Hope this post gave you some understanding of Same-origin Policy. Keep reading other unknowns in my other posts to have the full picture. Fell free to leave comments below.