47

I noticed that GitHub and Facebook are both implementing this policy now, which restricts third party scripts from being run within their experience/site.

Is there a way to detect whether a document is running against CSP using JavaScript? I'm writing a bookmarklet, and want to give the user a message if they're on a site that doesn't support embedding a script tag.

6
  • 1
    You can try to inject a new <script>var test=true;</script> into the document and then check if the variable is set. If CSP is enforced (and your script is not allowed) this code block will not be executed at all. Commented Oct 29, 2013 at 13:31
  • Interesting, will try that Commented Oct 29, 2013 at 16:11
  • Did it work? Just curious :) Commented Nov 4, 2013 at 20:16
  • 2
    Naw :( There's no problem executing JS within Fb or those with content policies. Just in them loading 3rd party, non-whitelisted scripts. I may look into the script onerror event, and see if that can get me anywhere. Commented Nov 4, 2013 at 20:32
  • I tried the onerror method as @onassar suggested and it seems to work, at least in Chrome 40 Commented Oct 1, 2014 at 20:57

7 Answers 7

46

You can try to catch a CSP violation error using an event "securitypolicyviolation"

From: https://developer.mozilla.org/en-US/docs/Web/API/SecurityPolicyViolationEvent

example:

document.addEventListener("securitypolicyviolation", (e) => {
  console.log(e.blockedURI);    
  console.log(e.violatedDirective);    
  console.log(e.originalPolicy);
});
Sign up to request clarification or add additional context in comments.

2 Comments

This is the only method in the list that I found to work successfully.
I find this to be more useful than the actual CSP report information which doesn't capture nearly as much information as the securityPolicyViolationEvent.
9

From https://github.com/angular/angular.js/blob/cf16b241e1c61c22a820ed8211bc2332ede88e62/src/Angular.js#L1150-L1158, function noUnsafeEval

function noUnsafeEval() {
  try {
    /* jshint -W031, -W054 */
    new Function('');
    /* jshint +W031, +W054 */
    return false;
  } catch (e) {
    return true;
  }
}

Comments

8

What about this. For slow connections, the timeout should probably be raised. Onload is what I used to detect it and it seems to work. If it loads then CSP obviously isn't enabled or it is configured improperly.

var CSP = 0;
frame = document.createElement('script');
frame.setAttribute('id', 'theiframe');
frame.setAttribute('src', location.protocol+'//example.com/');
frame.setAttribute('onload', 'CSP=1;');
document.body.appendChild(frame);
setTimeout(function(){if (0 == CSP){alert("CSP IS ENABLED");}}, 250);

8 Comments

Interesting. Anything that would work regardless of the internet speed?
Not that I know of. I played with a lot of different types of mechanisms to detect CSP and none of them worked very well. This is by far the best that I discovered. In practice, I set the timeout fairly high and print a pretty general error message that, if the user gets the message often it may be due to the security settings of the page.
gotcha. would be strange to set a high one, as then i'd have to prevent my app/script from running until that timeout was met. thanks though.
gotcha. dont wanna count on it though. our bookmarklet is used pretty globally :/
Aha. Mine is run in a globally used Bookmarklet too. I agree. My solution isn't great but I played around with a lot of things and this is the only one that works. I don't know what your bookmarklet does, but ours is pretty heavyweight, so this works well. If you do come across something better please let me know! Cheers
|
8

WayBack URL: https://web.archive.org/web/20181005165539/https://hackernoon.com/im-harvesting-credit-card-numbers-and-passwords-from-your-site-here-s-how-9a8cb347c5b5

fetch(document.location.href)
.then(resp => {
  const csp = resp.headers.get('Content-Security-Policy');
  // does this exist? Is is any good?
});

This will fail however with connect-src='none' and be reported.

1 Comment

Also you can set CSP inline not just in the headers?
6

Currently, there is no way to do so in shipping browsers.

However, something such as the following should work, per spec, and does in Chrome with experimental web platform features enabled in chrome://flags/:

function detectCSPInUse() {
  return "securityPolicy" in document ? document.securityPolicy.isActive : false;
}

The SecurityPolicy interface (what you get from document.securityPolicy if it is implemented) has a few attributes that give more detail as to what is currently allowed.

4 Comments

I ran that code in Facebook via the console. Got a false even though they're running one (which prevents inserting script tags)
This feature doesn't look like it's quite ready yet. For example, in all current versions of Chrome, this feature is hidden behind the Enable experimental Web Platform features flag. Your users would have to go to chrome://flags/, turn it on, and restart their browser. However, you can implement it now -- the code above is designed to work if the API is available.
This feature seems to have disappeared from Chrome, even with chrome://flags/#enable-experimental-web-platform-features turned on.
@JeffreyYasskin It would appear the SecurityPolicy interface is no more in the spec.
5

An easy way to detect support for CSP is just by checking if JavaScript's eval()-method can be run without throwing an error, like so:

try {
    eval("return false;");
} catch (e) {
    return true;
}

However, this only works if CSP is actually turned on (obviously), with Content-Security-Policy being set in the response headers the page loaded with, and without 'unsafe-eval' in script-src.

I came here looking for a way to detect CSP support in browsers without CSP actually being turned on. It would seem this is not possible though.

On a side note, IE does not support CSP, only the sandbox directive in IE 10+, which, by looking at the CSP standard, does not make it a conformant web browser.

Comments

0

I am checking onError event in my bookmarklet code and prompt a user to install my extension if script is not loaded.

javascript:(function(){
var s=document.createElement('script');
s.setAttribute('type','text/javascript');
s.setAttribute('src','https://example.ru/bookmarklet?hostname=%27+encodeURIComponent(location.hostname));
s.setAttribute('onerror', 'if(confirm(`Downloading from the site is possible only through the "MyExtensionName" extension. Install extension?`)){window.open("https://chrome.google.com/webstore/detail/myextensionlink");}');
document.body.appendChild(s);})();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.