Correctly set CSP

I am new of CSP: only today I tried to set a CSP for my websites, following (trying to follow :blush:) the tips of a page of sitepoint.
I put this code:

Content-Security-Policy: default-src 'self'; 
script-src 'self' 'sha256-[some-hash]';

adding it to my previous code, so that now the whole header code is:

<!DOCTYPE html>
<html lang="en">
 <head>
 <?php
 header("Access-Control-Allow-Origin: *; Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-[some-hash];");
 ?>

The Measure Page Qualiy (https://web.dev/measure/) keep not seeing this code and saying:

No CSP found in enforcement mode

Where I’m wrong?

Well first of all remember that in order to use the header() function, you can’t send any kind of markup or headers before its use. So for instance you can’t send along the DOCTYPE and then try to use header(). Otherwise you will get a message like “headers already sent”. Try visiting the page directly first before running it through that tool and make sure you are not getting that error.

Try moving the header() call above the rest of the content so that it is the first line of the script and see if that helps.

1 Like

Thank you: I did according to your suggestion

 <?php
 header("Access-Control-Allow-Origin: *; Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-[some-hash];");
 ?>
<!DOCTYPE html>
<html lang="en">
 <head>

but the resulting message of the Measure Page Qualiy was unchanged :frowning:

EDIT

I noticed that a CSP with <meta> tag works. But my jquery js no more :frowning:

I have to add something (nonce=[something]) to every script source.
I will do some other attempts to fine tuning my code.

If you check out the header() function help page, you will notice that you may need to call header() for each separate header, not chain them together in one.

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-[some-hash]'");
?>

I don’t think you can chain them all together in a single call. As for the hash, that is really only used for inline scripts. So unless you have some inline JavaScript, you can probably skip that piece for now. If you have inline scripts, then this article can quickly get you started to show you how to put them in…

I hope this helps! :slight_smile:

1 Like

Yes, it does! :slight_smile:
Now I have:

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Security-Policy: default-src 'self';  
script-src 'self' 
https://ajax.googleapis.com 
https.//cdn.jsdelivr.net 
https://www.paypalobjects.com 
https://www.amazon.it 
'unsafe-inline' https:;");
?>

But it seems that only the first url https://ajax.googleapis.com works: the other not.

You have an error where you have a period instead a colon for cdn.jsdelivr.net.

P.S. I don’t think it really matters, but in case it does, make sure to put all your CSP definitions on the same line.

1 Like

Almost done:

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Security-Policy: default-src 'self'; script-src 'self' https://ajax.googleapis.com https://cdn.jsdelivr.net https://www.amazon.it https://www.paypalobjects.com 'unsafe-inline'; object-src 'self' https://www.amazon.it https://*.amazon*.com https://rcm-eu.amazon-adsystem.com https://www.paypalobjects.com 'unsafe-inline'; img-src 'self' https://[mywebsite] https://www.paypalobjects.com https://www.amazon.it 'unsafe-inline' https:;");
?>

It is almost perfect, except for the GDPR script https://cdn.jsdelivr.net.
The html code is:

<script src="https://cdn.jsdelivr.net/npm/cookie-bar/cookiebar-latest.min.js?forceLang=it&amp;theme=altblack&amp;customize=1&amp;always=1&amp;refreshPage=1&amp;top=1&amp;showNoConsent=1&amp;noConfirm=1&amp;remember=30&amp;privacyPage=https%3A%2F%2F[my.website]%2Fprivacy.php\"></script>

And GDPR is important…

EDIT

Nothing to do with *://*.jsdelivr.net

EDIT

Looking at the browser js console I saw where was the error (other resources). And I fixed it.

While working with CSP I found this Chrome extension very helpful: https://chrome.google.com/webstore/detail/csp-evaluator/fjohamlofnakbnbfjkohkbdigoodcejf

1 Like

Very good! Thank you!
And many thanks you to @Martyr2 as well, of course! :slight_smile:

I have a last (I hope) problem: some scripts don’t work if I remove (from script-src) 'unsafe-inline' https: (as required to avoid a “high severity” risk).
How could I both avoid the risk and keep that (inline) scripts?

You can’t. Inline scripts open you up to Cross Site Scripting which is why it’s highly discouraged.

So either move all JavaScript to separate js files that are included in the HTML, or keep ‘unsafe-inline’ in the CSP. There is no middle ground here.

1 Like

Maybe someone should mention that CSP is a tool to fix failures you have done before. If your code is good you do not need CSP at all. Because you cannot know that your code is 100% secure it may help to use CAP anyways.

But You are trying to use CSP to secure Bad code and that’s not the right attempt

1 Like

That’s like saying if your house is never on fire you don’t need fire insurance.

You can and should still use CSP even if you think your site doesn’t have any flaws. One small flaw is enough to take down the site, so it’s nice to have counter measures in place. Especially when they’re as easy to configure as CSP.

I agree on that. Altough CSP can be a good idea to show you where the pain points are that need to be fixed.

1 Like

Why are you cutting my sentence to write the same what I wrote in the cutted part?

I misread. My bad. We’re indeed saying exactly the same :blush:

Thank you. But do you mean that all code with onclick is a bad (and insecure) code? Because this is my code not working without 'unsafe-inline'.

To be honest when I started developing with PHP (over 15 years ago) I did exactly the same like you do now. I put everything mixed up in one file. Html, javascript, php and sometimes also css. This was the fastest way to create an application which did what I want.
For luck none of these apps were really important and only for my personal use. So it would have been not a big deal if they would have been hacked.

Today developing software is much more strict and therefor much more complicated to learn. But at the end you need to understand how all this is working together and grabbing into each other, without mixing it and have deep dependencies.

So yes, the onClick in the php code is no longer good style. You need a separate JavaScript file which is adding an event handler to the Dom element you want to listen too.

At the end I would also suggest to no longer use PHP as a frontend creater. I would not even suggest to use PHP at all when someone asks me in what language he should write web applications. There are many JavaScript frameworks if you want one (you can also write completly in vanilla JavaScript) for the frontend part and there are many nice backend languages like nodejs, python or even dot.net or spring boot.

Learning PHP nowadays is for me like being on a wrong (dying) horse.

1 Like

The code in and of itself isn’t unsafe. It’s not a good practice, as @Thallius points out, but it’s not inherently unsafe.

What’s unsafe is that in order for it to be usable you need to allow inline scripts on your website. So if someone manages to get their malicious script on your website somehow, e. g., by posting a comment with Javascript in it, or a carefully crafted search, stuff like that, then that code will be executed too, as the browser can’t differentiate between legit and non legit code and will just execute all of it.

If you don’t allow inline scripts than no inline scripts will be executed by the browser at all. So even if someone gets their malicious Javascript on your site, it won’t get executed.

For more info please refer to my link to Cross Site Scripting a few posts above.

2 Likes

Thank you, @Thallius and @rpkamp.
In my websites I don’t have forum, nor comments of readers, or search form.
I will try, any way, to convert that inline js in what you suggest.

1 Like