Intended Audience
This article is written by a software developer for anyone who is interested in the technical aspects of modern web browsers. To understand this article, readers need to know the overview of browser's policies. Here is the article on the browser-policies-part-1-technical-overview-of-browser-policies.
Content
- Introduction
- Why we need Content Security Policy?
- Default behaviour of Content Security Policy?
- Exclusions from Content Security Policy?
- How to enable Content Security Policy?
- How to write the "Policy" for CSP?
- How to relax Content Security Policy?
- Attacks prevented by Content Security Policy?
- Conclusion
Introduction
Content Security Policy is also one of the browser's policies that make browsers a safe place to browse the Internet.
This policy enables a browser to allow or block a content (any file like .css, .js, .jpeg, .ttf, and many more) requested by current origin to be downloaded from any other origin. We can use a shopping cart for an analogy, where we can decide which item to add in the cart. Similarly, browsers have the decision power to allow or block particular types of content from specific origin.
Why we need Content Security Policy?
The need of Content Security Policy (CSP) comes, when we want to overcome the limitations of Same-Origin-Policy (SOP). Because, only SOP is not enough to protect an origin from certain attacks such as Cross-Site Scripting (XSS) and data injection attacks. This is due to the fact that SOP only applies to the code written inside the script, not from where we loaded the script using html tags.
Since, SOP does not care about what content and from where we are downloading it, using any html tags, therefore it opens a gateway for attackers. To prevent this browsers somehow need to control how and from where we are downloading content.
This is the reason browsers provide a mechanism called Content Security Policy that enables developers to decide which content and origin they want to allow or block.
Default behaviour of Content Security Policy
By default, CSP is disabled. In order to activate the CSP, the server needs to implement either of two methods, HTTP header Content-Security-Policy or the meta tag
<meta http-equiv="Content-Security-Policy" content="default-src 'self';">The policy behaviour is controlled by the content. If the expected behaviour defined in the content is violated by an origin, the browser will throw an error in the console:
Exclusions from Content Security Policy
Currently, there is no escape from CSP. Once it is defined by the server, browsers must obey it. There are chrome extensions which bypass the CSP, but that is not the intention of this article.
How to enable Content Security Policy?
Once the header or meta tag is set by the server, CSP is enable by the browser automatically. But its behaviour is defined in the value of the header or content attribute of the meta tag. The server has full control on this behaviour.
HTTP header
Content-Security-Policy: policyHTML meta tag
<meta http-equiv="Content-Security-Policy" content="policy">The behaviour is controlled by the policy. The policy can be set of one or more policy directives defined by the W3C standards.
How to write the "Policy" for CSP?
There are four main type of policy directives: Fetch, Document, Navigation & Reporting
Content-Security-Policy: <directive> <source>
Fetch Directive
Controls location from which resources needs to be loaded.
This is the most commonly used directive.
iframe-src, worker-src
It controls nested javascript instances sources such as iframes and workers.
Content-Security-Policy: frame-src 'self' https://example.com;This only allows iframes from its own origin or example.com. Therfore, if you have something like <iframe src="https://not-example.com"></iframe>, the browser will throw error.
script-src, img-src, font-src, media-src, object-src & style-src
This fetch directive controls src (source) attributes of tags such as <script>, <img>, <font>, <audio/video>, <object> & <style> respectively. For example:
Content-Security-Policy: script-src 'self' https://example.com;This only allows scripts to be loaded from its own origin or example.com.
connect-src
After loading content from trusted sources, the content may contain code that connects with another origin via api call or html anchor tag. This directive controls that connection. For example:
Content-Security-Policy: connect-src 'self' https://example.com;This allows following browser apis to only connect to its own origin or example.com.
<a> ping, fetch(), XMLHttpRequest, WebSocket, EventSource, and Navigator.sendBeacon().
default-src
This is a fallback for rest of the fetch directives. If the browser does not find any of the fetch directive, the browser looks for default-src for its value. For example:
Content-Security-Policy: default-src 'self'; script-src https://example.comis same as:
Content-Security-Policy: connect-src 'self'; font-src 'self'; frame-src 'self'; img-src 'self'; media-src 'self'; object-src 'self'; script-src https://example.com; style-src 'self'; worker-src 'self'
Document Directive
Controls attributes of nested javascript instances.
It is used to control behaviour of document, iframe or workers.
base-uri
Controls which origin is allowed in documen's html <base> tag.
sandbox
Enables a sandbox for the requested resource similar to the <iframe>'s sandbox attribute.
Navigation Directive
Controls navigation on an origin.
It control to which origin a user is allowed to navigate using different means, such as <form>, <a>, <window.location>, <window.open> or <iframe>
form-action
When we submit a form, it gets submitted to the url specified in the action attribute. This directive controls which origin is allowed in that attribute.
Content-Security-Policy: form-action 'self' https://example.com; <form action="https://example.com">
frame-ancestors
Controls the iframe's ancestors in which the origin is allowed to be embedded.
//origin source: https://not-example.com Content-Security-Policy: frame-ancestors 'self' https://example.com; //origin target: https://example.com <html> <iframe src="https://not-example.com"> </html>
navigate-to
Similar to connect-src. Restricts the URLs to which a document can initiate navigation by any means, including <form>(if form-action is not specified), <a>, <window.location>, <window.open> or <iframe>.
Reporting Directive
This is used to specify reporting location.
When CSP in a violation, browser has a mechanism to report that error via http post method or in browser event.
report-to
This directive controls to which origin we need to log the error. For example:
Content-Security-Policy: report-to https://report.example.com;This allows browser to send a POST request with JSON data about the error to https://report.example.com.
The browser also fires a javascript event named as SecurityPolicyViolationEvent, which we can listen to and act accordingly.
document.addEventListener("securitypolicyviolation", (e) => { console.log(e.blockedURI); console.log(e.violatedDirective); console.log(e.originalPolicy); });
How to "relax" Content Security Policy?
CSP is an amazingly strong policy a browser has in place. There is no straightforward way to relax or bypass the policy. It is designed in such a way that any addition to the policy only tightens it.
We can have some hacks such as MITM, chrome extentions, etc but those are not the purpose of this article. We can explore it in later articles.
Attacks prevented by Content Security Policy?
It mitigates threats such as cross-site scripting (XSS), Packet sniffing, etc.
Conclusion
Since SOP alone is not sufficient to protect us from the attacks, CSP is an added layer on top of SOP to protect and manage what content and from where, any origin is allowed to download or connect.
Links & References
- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
- https://web.dev/csp/
- https://www.w3.org/TR/CSP3/#framework-directives
- https://developer.mozilla.org/en-US/docs/Web/API/SecurityPolicyViolationEvent
About Author
I love to shape my ideas into a reality. You can find me either working on a project or having a beer with my close friend. :-)