Defending against XSS with CSP

Learn how to use Content Security Policy (CSP) to prevent the execution of malicious script code in your application.
Read more…

:writing_hand:t2: Brought to you by our Guest Author @PhilippeDeRyck

What’s up Devs! How did you like this post? Please share any comments or feedback with us on this thread

This is a great article. I’m curious how these recommendations for CSP work in tandem with trusted types, which Philippe wrote about previously: Securing SPAs with Trusted Types.

@PhilippeDeRyck would you be able to follow-up on that? Thanks!

Trusted Types targets a specific way to go from text to executable code. CSP covers a similar path, but in a less reliable way. However, CSP covers a lot more ways to load script code (e.g., remote files), so it is more extensive.

In a nutshell, I would see both mechanisms as separate defenses, but use them together as a robust defense strategy against XSS.

2 Likes

That’s great. Thank you for the explanation.

We are here for you!

This topic was automatically closed after 30 days. New replies are no longer allowed.

Finally (after 2 -3 years searching) I have come across a CSP Blog that explains things in a clear, concise and step by step way.
I am a brilliant web/mobile programmer and can make a webpage do backflips, somersaults and a “Happy Dance” if I wanted to,
but when it comes to new technologies like CSP, I’m a visual learner and most blogs are mainly text based…
and this blog was the only one that I could easily understand because of the way
Philippe presented it with text and image examples in a clear, concise way that even a 5 year old child could easily understand.

Simple things like what Philippe presented under the heading “What a modern browser sees”…

A modern browser recognizes the nonce, which causes the ‘unsafe-inline’ keyword to be ignored.
A modern browser recognizes ‘strict-dynamic’, which causes any URL-based expressions (i.e., http: https:) to be ignored.
Safari recognizes the nonce, which causes it to ignore ‘unsafe-inline’.
Safari has no idea what ‘strict-dynamic’ means, so it ignores that value. Instead, it uses the URL-based expressions (i.e., http: https:)

… really help me get the big picture about how old and new browsers recognizes CSP versions 1 - 2 - 3
and the way the fall backs (for e.g ‘unsafe-inline’ http: https:) are handled (utilized or ignored) depending on the browser and its age.

Under the heading “CSP by Example”… building a CSP policy for a sample app…
the step by step method showing the changes in images is a brilliant presentation and was totally easy to understand
without having to read complicated jargon.

I’m up to the “Additional details” heading now… the Final Frontier for me to be a CSP Pro and CSP Nounce Pro.
I need help with how to get the Report-Only mode to send reports back to my website csp-report log.
I understand that a CSP policy can be either “Enforced” or “Report-Only” or “Enforced and Report-uri”.
I found some info and code, but dont know how to implement yet… will share below (if I’m able to add code to this comments section? ).

But firstly, to compliment Philippe’s blog… here is a kick azz CSP that covers:
Google reCaptcha, Tag Manager, Analytics, Ajax, Fonts, Frames, Page ADs, Adsense
Cloudflare cloudflareinsights
gsap ScrollTrigger
Bootstrap (with its theme color-modes.js) and CDN cdn.jsdelivr
jQuery
connect-src "self’ with links to Facebook and Etsy store


If you have enabled Cloudflare web analytics - careful though, it may inject other scripts in your webpage that are not required and stuffs up your CSP
so I dont implement it now and just use Google Analytics).

With Cloudflare… add to your robots.txt file:
User-agent: *
Disallow: /cdn-cgi/

Refer to info:


CSP Policy below - Note that the backslash breaks a command into nicely readable lines which will be removed by Apache later.
But I found that to be buggy and it may not put a space between each directive - in which is very important!
So remove backslashes eventually and check spaces… and make sure the double quotes before default-src and end of Report-To:


<IfModule mod_headers.c>
Header always set Content-Security-Policy-Report-Only:\
  "default-src 'self' https://www.mywebsite.com/ https:; \
  script-src 'self' 'report-sample' 'strict-dynamic' static.cloudflareinsights.com www.google-analytics.com ajax.googleapis.com 'unsafe-inline' https:; \
  script-src-elem 'self' 'report-sample' 'strict-dynamic' 'unsafe-inline' https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.0/gsap.min.js https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.0/ScrollTrigger.min.js https://www.google.com/recaptcha/api.js https://www.gstatic.com/recaptcha/releases/-QbJqHfGOUB8nuVRLvzFLVed/recaptcha__en.js https://www.googletagmanager.com/gtag/js https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js https://pagead2.googlesyndication.com/pagead/managed/js/adsense/m202311090101/show_ads_impl_fy2021.js https://tpc.googlesyndication.com/sodar/sodar2.js https://tpc.googlesyndication.com https://www.google-analytics.com/g/collect https://code.jquery.com/jquery-3.7.1.slim.min.js https://www.mywebsite.com/js/color-modes.js https://www.mywebsite.com/site.webmanifest; \
  style-src 'report-sample' 'self' https://fonts.googleapis.com https://cdn.jsdelivr.net; \
  img-src 'self'  https://www.gstatic.com/recaptcha/ https://www.google-analytics.com; \
  font-src 'self' https://fonts.gstatic.com; \
  object-src 'none'; \
  base-uri 'none'; \
  form-action 'self' https:; \
  frame-ancestors 'none' https://www.google.com/; \
  frame-src 'self' 'unsafe-inline' https://www.google.com/; \
  connect-src 'self' 'unsafe-inline' https://www.facebook.com/MyFacebookProfile https://myetsystore.etsy.com; \
  block-all-mixed-content; \
  upgrade-insecure-requests; \ 
  report-uri https://www.mywebsite.com/csp-report; report-to csp-endpoint;
  Report-To: {"group":"csp-endpoint", "max_age":10886400, "endpoints":[{"url":"https://www.mywebsite.com/csp-report"}]}"
</IfModule>

Ok… I got this from dev.mozilla … but I dont know how to implement it and set it up running.
Do i put this code in the csp-report directory or a Cron Job or a cgi-bin script or ???

Same info - another web link as well:
https://udn.realityripple.com/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri


 <PHP start tag >

    // Start configure
    $log_file = dirname(__FILE__) . '/csp-violations.log';
    $log_file_size_limit = 1000000; // bytes - once exceeded no further entries are added
    $email_address = 'admin@example.com';
    $email_subject = 'Content-Security-Policy violation';
    // End configuration

    $current_domain = preg_replace('/www\./i', '', $_SERVER['SERVER_NAME']);
    $email_subject = $email_subject . ' on ' . $current_domain;

    http_response_code(204); // HTTP 204 No Content

    $json_data = file_get_contents('php://input');

    // We pretty print the JSON before adding it to the log file
    if ($json_data = json_decode($json_data)) {
      $json_data = json_encode($json_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);

      if (!file_exists($log_file)) {
        // Send an email
        $message = "The following Content-Security-Policy violation occurred on " .
          $current_domain . ":\n\n" .
          $json_data .
          "\n\nFurther CPS violations will be logged to the following log file, but no further email notifications will be sent until this log file is deleted:\n\n" .
          $log_file;
        mail($email_address, $email_subject, $message,
             'Content-Type: text/plain;charset=utf-8');
      } else if (filesize($log_file) > $log_file_size_limit) {
        exit(0);
      }

      file_put_contents($log_file, $json_data, FILE_APPEND | LOCK_EX);
    }


<PHP END tag >

Any info or links to the Report-Only blog Greatly Appreciated!
Have a Great Day!
Kind Regards
Rob

Under the heading…"Additonal details…
“We’ll discuss reporting in more depth in a follow-up article”.

Has or is there a Reporting article?

Hey @QuantumMatrix,
Welcome to the Auth0 Community!

I hope that @PhilippeDeRyck has a chance to respond to your request. In the meantime, you can take a look at his guide to CSP, which integrates these blog posts with more insights.

Here you can find a bunch of articles on CSP: Philippe De Ryck

The follow-up one that discusses reporting is right here: From Zero to Hero with CSP

The ebook that @andrea.chiarelli mentions contains all of this content as well.

Good luck!

1 Like