ModSecurity Advanced Topic of the Week: Mitigating XSS Vulnerabilities Using Targeted CSP Enforcement
Content Security Policy (CSP) Implementation Challenges
CSP is an extremely powerful tool for mitigating Cross-site Scripting (XSS) vulerabilities. The main challenge that organizations run into is that actual site-wide implementation is a daunting task. As the image on the right indicates, implementing CSP site-wide is a bit like eating an elephant. Where do you start? In this blog post, I will highlight how to use ModSecurity WAF to virtually patch identified XSS vulnerabilities by enforcing targeted CSP policies.
Site-wide CSP Development
The biggest challenge associated with developing proper CSP policies for resources is the need to remove all inline JS code from the HTML page. When presenting this task to the developers, they might not be that receptive...
Security Reactions: You want to deploy CSP Site-wide?!?!?
In order to implement CSP, there many steps that must be completed (List developed by Colin Watson) -
- Choose one pilot web application and a single functional area with greater security assurance requirements (e.g. payment, checkout, order submission, authentication)
- Create a change request for deployment to production and assess the risks
- Attempt to remove all inline JavaScript, all inline styles and as much third-party content as possible from the functional area
- Create an initial Content-Security-Policy header in development, test locally and apply to staging/test systems
- Undertake existing unit tests for the functional area using the latest, recent and legacy web browsers
- Make changes to code and/or the policy to determine what can be achieved
- Build a mechanism to collect the violation reports, ensuring all data is treated as untrusted and is correctly encoded when utilised, and add a report-uri directive to the header to verify the mechanism
- In production, add the directives as a Content-Security-Policy-Report-Only header to the functional area (i.e. not as a Content-Security-Policy header)
- Monitor and assess the violation reports
- Adjust the policy as necessary and re-test, and re-deploy
- Once approved, change the header from Content-Security-Policy-Report-Only to an enforced Content-Security-Policy header for a test group of users
- Monitor and update the policy as necessary, and re-test/re-deploy
- Gradually extend to all users
- Update coding standards so that future development is compatible with the CSP
- Repeat for other functional areas
- Apply CSP policies to the remainder of the web application (with differing policies as necessary).
These are excellent steps to follow. The problem is that this all takes a large investment of time/resouces to complete. Let's focus in on the bolded first item.
Using CSP for Virtual Patching
What resource(s) should you choose to first implement CSP? How about those resources that have been confirmed to be vulnerable to XSS through some type of penetration test or assessment? Prioritizing these resources has the dual advantage of making CSP deployment consumable and reducing risk for a known vulnerability.
Example Vulnerability (xssed.com)
NOTE - although xssed.com lists the vulnerability on the pastebin. mozilla.com as "UNFIXED" it is in fact fixed.
When this page was vulnerable, the issue was that the "goprivate" QUERY_STRING data was populated into a FORM field without proper output encoding/escaping:
Here is the actual HTML with the XSS payload:
The JS code at yourjavascript.com will then over-write DOM elements -
The end result is that the webpage appears to be defaced:
Mitigating XSS with CSP
We will now discuss how to mitigate this particular vulnerability using ModSecurity WAF to add CSP policies for this page.
Analyzing Current Page Construction
You must review the current construction of the page to see if/when/where/how code is being used within the page. A great tool to aid in this effort is call CSP Bookmarklet by Brandon Sterne. Essentially, you create a bookmark with the supplied code and then when are viewing the webpage of interest, you just click on the bookmarklet. It will then analyze the page elements and issue a JS alert popup box where it will provide a recommended initial CSP policy, as well as, notify you of any current violations.
As you can see from CSP bookmarlet popup, there is a recommended policy as well as an alert for an Inline Script Violation.
Removing Inline JS Code
When you encounter inline JS code violations, this is when you should consult with the proper Developer to assist with the process of externalizing this code. In this case, the CSP alert identified the "initPastebin()" function call -
This "onload" event is not allowed per CSP and mut be externalized. One method to do this would be to add an "id" element to the <body> block to reference the initPastebin() call. Then in the pastebin.js file, you could add code similar to the following that would still initate the proper function call when the DOM page loads:
// Add event listeners once the DOM has fully loaded by listening for the// `DOMContentLoaded` event on the document, and adding your listeners to// specific elements when it triggers.document.addEventListener('DOMContentLoaded', function () { initPastebin();});
Using ModSecurity to Dynamically Add CSP
This is there the virtual patching comes in :) You can implement ModSecurity rules to dynamically add in proper CSP enforcement for this resource. The current CSP spec 1.1 allows the use of the "meta" HTML block to add CSP data. With this capability, we could use the following ModSecurity rule which will modify the outbound HTML using the @rsub operator to inject our CSP policy data.
SecContentInjection OnSecStreamOutBodyInspection OnSecRule REQUEST_FILENAME "@streq /" "chain,phase:request,t:none,nolog,pass" SecRule &ARGS "@eg 1" "chain" SecRule STREAM_OUTPUT_BODY "@rsub s/<head>/<head>|00|<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; script-src http:\/\/pastebin.mozilla.org\/; style-src http:\/\/pastebin.mozilla.org\/; report-uri http:\/\/www.modsecurity.org/csp_violation_report\"<\/>/"
The resulting HTML would look like this -
It is also possible to have ModSecurity set Apache environmental variables and conditionally set HTTP Response headers for the CSP policy as well. This may be necessary if you are using older browsers.
This CSP policy would then instruct Chrome browser to block the XSS payload as we are disallowing inline JS. In the Developer console in Chrome, this event would be generated -
CSP Violation Reporting
One of the features I like best about using CSP enforcement is that you are able to gain insight into violations by using the report-uri directive. Here is a screenshot of the violation report sent from the browser:
In this case, we can alert ModSecurity when a violation occurs by adding the following rule:
## Check the REQUEST_BODY for CSP Violation Report data and generate an Alert#SecRule REQUEST_BODY "({\"csp-report\":{\"document-uri\":\"(.*?)\".*?violated-directive\":\"(.*?)\".*?blocked-uri\":\"(.*?)\")" "chain,phase:2,id:'960001',capture,t:none,log,pass,msg:'Content Security Policy (CSP) Violation for Vulnerable Resource',logdata:'blocked-uri:%{tx.4} violated-directive:%{tx.3}',tag:'OWASP_AppSensor/RP3',tag:'https://www.owasp.org/index.php/AppSensor_DetectionPoints#RP3:_Suspicious_Client-Side_Behavior'" SecRule TX:2 "@streq file://localhost/Users/rbarnett%201/Desktop/XSS%20Defacement%20By%20Atm0n3r.html"
This rule inspects the CSP JSON body content of the request and parses out important data. It then checks to the document-uri element to see if it was our vulnerable resource. If it was, it generates this alert message:
[Mon Jul 15 16:23:57 2013] [error] [client 72.192.214.223] ModSecurity: Warning. String match "file://localhost/Users/rbarnett%201/Desktop/XSS%20Defacement%20By%20Atm0n3r.html" at TX:2. [file "/etc/httpd/modsecurity.d/crs/base_rules/modsecurity_crs_42_csp_enforcement.conf"] [line "33"] [id "960001"] [msg "Content Security Policy (CSP) Violation for Vulnerable Resource"] [data "blocked-uri:http://yourjavascript.com violated-directive:script-src http://pastebin.mozilla.org/"] [tag "OWASP_AppSensor/RP3"] [tag "https://www.owasp.org/index.php/AppSensor_DetectionPoints#RP3:_Suspicious_Client-Side_Behavior"] [hostname "www.modsecurity.org"] [uri "/csp_violation_report"] [unique_id "enUZ5cCo8AoAACw8BQ8AAAAP"]
Conclusion
Hopefully this blog post has provided a pragmatic approach for implementing CSP within your site. By focusing and prioritizing resources that have been identified as vulnerable to XSS, it allows your organization to take a smaller tactical approach vs. the enormous task of site-wide CSP development.
Credits
I wanted to thank two people with whom I discussed this CSP use-case and content:
- Neil Matatall who works at Twitter and has does a number of recent blog posts/presentations around CSP.
- Michael Coates who works at Mozilla and is an OWASP Board Member.
ABOUT TRUSTWAVE
Trustwave is a globally recognized cybersecurity leader that reduces cyber risk and fortifies organizations against disruptive and damaging cyber threats. Our comprehensive offensive and defensive cybersecurity portfolio detects what others cannot, responds with greater speed and effectiveness, optimizes client investment, and improves security resilience. Learn more about us.