Realtime XSS Detection using Content Security Policy

5 years ago

Stuart Larsen #article


Content Security Policy can be used to detect XSS's in realtime.

To me this is one of the most underappreciated aspects of Content Security Policy. Normally the discussion of Content Security Policy is geared towards blocking XSS's. But it's also a fantastic tool to learn about vulnerabilities in realtime on your website.

Background

The following is a quick introduction to XSS's and CSP. If you're very familiar with both the topics, I'd suggest you jump down to the demo.

Cross Site Scripting (XSS)

Cross Site Scripting is a prolific vulnerability where an attacker injects javascript into a web page and that webpage is then viewed by a victim.

This is bad because the attacker's javascript allows the attacker to do nasty things in the web page under the victim's session. The javascript can steal information from the page (like banking information, see Magecart), perform actions as the user (such as deleting their account, or transferring funds), or defacing the website.

There's a couple of types of XSS (generally called stored, reflected and DOM). But they all involve exploiting a vulnerability where an attacker is able to trick the website into accepting the attacker's javascript.

Content Security Policy (CSP)

Content Security Policy is a security mechanism built into all browsers that helps protect against XSS.

It's a defense in depth protection. Normally you'd prefer for your website not to have an XSS vulnerabilities. But sometimes vulnerabilities are accidentally introduced, or included through third part code, etc.

Content Security Policy requires the website owner to create a whitelist of valid javascript. It can be complex to setup (although there are automatic tools to do some of it).

So in the event an attacker does find a potential place to inject their javascript, it's not "valid javascript" in the eyes of the policy and so it won't be executed by the browser.

There's a feature of Content Security Policy called "report-uri" that tells the browser to send a JSON report whenever something is blocked by the policy.

Realtime XSS Detection Demo

The following gif is a demonstration of a realtime XSS detection:

realtime xss detection

Realtime XSS Detection using Content Security Policy

Setup

The website on the right is a fake blog with a comment section. It has Content Security Policy enabled and an XSS vulnerability in the comment field. The XSS is abused with the following payload:

<img src="x" onerror="alert(1)">

The website on the left is Csper's Realtime panel. It accepts Content Security Policy violation alerts (report-uri), and then displays the reports in real time.

How it works

XSS exploited

Using the blog's comment form, an XSS is injected into a comment. Normally a comment would look something like this:

<div style="border: 1px solid">
  <p><strong>Stuart</strong></p>
  <p>Nice article!</p>
</div>

But the attacker is able to inject arbitrary HTML, so they can include an XSS:

<div style="border: 1px solid">
  <p><strong>Stuart</strong></p>
  <img src="x" onerror="alert(1)"/>
</div>

The XSS is the image tag with an onerror. Normally the XSS would actually do something malicious.

CSP violation report

As the XSS is being injected into the DOM, Content Security Policy will see that it's violating the policy:

(The XSS is an inline resource, and we're not using unsafe-inline.)

Content Security Policy will fire a violation report to the endpoint specified by the policy. (https://realtime-demo.endpoint.csper.io).

The violation report looks like this:

{
  "csp-report": {
    "document-uri": "http://localhost:8080/comments",
    "referrer": "",
    "violated-directive": "script-src-attr",
    "effective-directive": "script-src-attr",
    "original-policy": "default-src 'none'; script-src 'self' 'report-sample';  report-uri https://realtime-demo.endpoint.csper.io;",
    "disposition": "enforce",
    "blocked-uri": "inline",
    "line-number": 17,
    "source-file": "http://localhost:8080/comments",
    "status-code": 200,
    "script-sample": "alert(1)"
  }
}

There's some pretty amazing information in the violation report.

  • We can see that the XSS happened on line 17 of web page.
  • We know it was an HTML attribute that caused the alert.
  • The XSS that fired the alert was alert(1)

report-uri ingestion

The report is ingested by the report-uri endpoint. It's then parsed, tagged, classified, and then sent over websockets to the realtime panel.

Issue fixed

Using the above information we can now easily identify the XSS injection spot (/comments:17), and fix the underlying issue.

If the issue is systemic we might be able to identify multiple vulnerabilities at the same time!

(In this demo case I was using innerHTML instead of createTextNode or any of the safe alternatives.)

fixed xss innerHTML

Comment is properly encoded, preventing XSS

Alerting on XSS

Obviously we wouldn't want to spend all day watching a realtime chart, so we make computers do it for us!

You'll need to filter the report-uri reports, since there's probably a lot of garbage. Here's a guide to get started filtering CSP reports.

But if properly filtered, you can take the incoming reports, ignore the browser extensions, unactionable alerts, non-xss-able directives, already known reports, etc, and then fire an email or webhook to your alerts dashboard and respond.

(If you don't want to build all that yourself, Csper handles all of the realtime collecting and alerting for you.

Conclusion

I hope this article was enlightening on how to use CSP for realtime xss monitoring!

If you have any questions or comments, I would love to chat. stuart at csper.io.

Looking for tools to make CSP easier?

Csper has the tools to help you understand, deploy and manage your content security policy. Get started in minutes. Report aggregations, classification, analysis, alerting, realtime and more. Free 14 day trial.