Can I use CSP to limit requests to both https: AND 'self'? - security

I originally had this in my CSP header: default-src 'self';, which limits sources to only my domain, but it says nothing about the scheme/protocol. From what I can gather, this will allow sources to be loaded over http if the page itself was loaded over http. I'm using HSTS and CDN redirects to try to keep all traffic on https, but I want to cover this case off anyway. (In truth, I'm trying to make this header checker give me all green ticks.) Edit: srcclr will happily give all green ticks when using 'self'. I just had to fix some typos.
Anyway, I tried changing the CSP directive to be default-src https: 'self';, but it would seem that adding the scheme allows resources to be loaded from any domain, as long as it's over https. I.e, if either of the rules (https or 'self') matches, then the request is allowed. I tested this by playing around with URLs in the chrome dev tools.
Is there a way to indicate:
All resources should be loaded over https; AND
Resources should only come from the original domain?
Something like default-src https://'self';, but I don't think that's valid, is it?
One solution is to hardcode the domain name, but I'd like to use 'self' if it's possible.

According to https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives, the 'self' content source keyword:
Refers to the origin from which the protected document is being served, including the same URL scheme and port number.
If you serve the web page over https, then self only allow https request to the same domain.
The CSP2 specification http://www.w3.org/TR/CSP2/#match-source-expression says the same thing:
If the source expression is a case insensitive match for 'self' (including the quotation marks), then:
Return does match if the origin of url matches the origin of protected resource’s URL.

Related

HSTS preload Meaning

In MDN HTTP Strict Transport Security (HSTS), it has an example of HSTS settings as below
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
where I can find the corresponding mean of max-age and includeSubDomains in RFC 6979, but it does not have the meaning of preload.
I have tested in latest Chrome and Firefox, and it seems that preload does not do anything at all. With and without preload, on requesting http request, both trials if using Chrome, can find 307 Internal Redirect made by Chrome browser without requesting to the server, which is what HSTS expect.
So what is the purpose of preload?
In addition, even if I add HSTS header, it will still have a chance to be attacked, on the first time the user visit the website with HTTP. How can we mitigate from this risk? That is, how can we tell the browser to add the domain to HSTS list before any request are sent to the server?
P.S.
I have found https://hstspreload.org/, which if I need to register the domain, requires me to add max-age and preload directive. Is it the reason why preload is necessary? And this should be the page where I should add my domain to ensure new user are safe from SSL Stripping Attack?
Preload is a big commitment. It will effectively be hardcoded into a browser’s code. Given it takes several months at a minimum to roll out new version, it’s basically irreversible.
Also as it’s down at the domain level, mistakes have been made. For example preloading domain.com but covering that blog.domain.com, or intranet.domain.com have not been upgraded to HTTPS. At this point your options are 1) upgrade side to HTTPS and live with zero users to the site until the or 2) reverse the preload and wait the months for that to roll out to all browsers and deal with zero users until then.
HTTPS is much more common now, so the risks are reduced but when HSTS preload first came out, these were real risks.
Therefore the preload attribute was a signal that the site owner was ready for that commitment. It also prevent someone else submitting a site that wasn’t using this header (whether maliciously or with good, but misguided, intentions).
You are correct in that it doesn’t “do” anything in the browser.
There was also talk of checking if the preload header was still being sent, and if not removing the preload but not sure if that’s done.

content-security-policy doesn't work; I want to have my website load in an iFrame on ONE other website only

How do you do this? I want only one other website to be able to load my main website in an iFrame but nothing is working.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors
Apparently as I understand it the protocol you set in .htaccess is this
So far I've tried:
1.
Header set Content-Security-Policy "frame-ancestors 'self' https://example.subdomain.co;"
2.
Header always set Content-Security-Policy "frame-ancestors 'self' 'https://example.subdomain.co';"
3.
Header set Content-Security-Policy "frame-ancestors 'self' 'https://example.subdomain.co';"
None of these work. When I try to load an iframe of example.com inside https://example.subdomain.co I get the following error:
Refused to display 'https://example.com/' in a frame because it set
'X-Frame-Options' to 'sameorigin'.
And then I get more confused because apparently you can only do DENY and SAMEORIGIN with this.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
The X-Frame-Options HTTP response header can be used to indicate
whether or not a browser should be allowed to render a page in a
<frame>, <iframe>, <embed> or <object>. Sites can use this to avoid
click-jacking attacks, by ensuring that their content is not embedded into other sites.
The added security is provided only if the user accessing the document
is using a browser that supports X-Frame-Options.
The one I would have wanted is ALLOW FROM but
ALLOW-FROM uri This is an obsolete directive that no longer works in
modern browsers. Don't use it. In supporting legacy browsers, a page
can be displayed in a frame only on the specified origin uri. Note
that in the legacy Firefox implementation this still suffered from the
same problem as SAMEORIGIN did — it doesn't check the frame ancestors
to see if they are in the same origin. The Content-Security-Policy
HTTP header has a frame-ancestors directive which you can use instead.
It's deprecated and it doesn't work.
Refused to display in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'
This answer doesn't help because they don't talk about what I want to do, they just explain what it is.
How to set 'X-Frame-Options' on iframe?
Again, not helpful because it's explaining to OP that the header is set on the website in the iframe source.
Is there a way to set it X-Frame-Options for frame-ancestors somehow to make this work so that I can load an iframe of my website on one other specific website? Or is this not possible?
When you set frame-ancestors correctly all browsers that understand it will disregard X-Frame-Options. This means that you can set both headers and use ALLOW-FROM as you will then server X-Frame-Options to IE and frame-ancestors to other browsers.
Have you checked if your Content-Security-Policy is present as a response header? Your first version is the most correct one, but you can drop the scheme as such: "frame-ancestors 'self' example.subdomain.co;", there should not be any single quotes around hosts in sources.

content security policy frame-ancestors

I'm trying to load my content into an IFrame, so I implemented the Content-Security-Policy header: Content-Security-Policy: frame-ancestors http://*.example.com/abc.html.
I am able to load the content on iframe when I give the header as
Content-Security-Policy: frame-ancestors http://*.example.com/.
But when I change the header to:
Content-Security-Policy: frame-ancestors self http://*.example.com/abc.html.
then the content on iframe is getting loaded for the first time but gives below error when I refresh the web page
Refused to display 'https://....' in a frame because an ancestor violates the following Content Security Policy directive: frame-ancestors self http://*.example.com/abc.html.
Can anyone tell why its giving error on refreshing the page.
Also does frame-ancestors considerers the full url (http://.example.com/abc.html) or only the hostname like http://.example.com?
Chrome browser has a bug - it's not support paths in the frame-ancestors directive. Safari nas the same bug, and only lasets Firefox supports paths in this directive.
So for frame-ancestors instead of http://.example.com/abc.html you have to use http://.example.com host-source.
For other directives you can use paths and filenames.
Without a working example it is hard to know exactly what the problem is. But based on the specification, https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors, some adjustments to your CSP can be advised:
Remove the path, it is not according to the specification to use more than the scheme, host and port.
Use the expected scheme (http/https) or remove the scheme.
Use wildcard https://*.example.com, not just https://.example.com
Use 'self', not self

Content-Security-Policy (CSP) URL doesn't seem to have any effect. Still reporting a violation

I have a CSP with the following line in it:
script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http: https://static.cloudflareinsights.com https://mydomain.app/cdn-cgi/scripts/6c4dd986/cloudflare-static/email-decode.min.js;
and I can see that the CSP is correct in the response header for the page.
I am still getting a [Report Only] Refused to load the script https://mydomain.app/cdn-cgi/scripts/6c4dd986/cloudflare-static/email-decode.min.js error.
Cloudflare is auto-injecting this script tag and so I cannot rely on the strict-dynamic property to cover it for me, nor can I add a nonce.
Is this failing because of scrict-dynamic overriding the fixed url in the CSP? We need strict-dynamic within the app, but we also need to allow a custom whitelist url for these situations.
Any ideas?
Edit: Specifically I think the issue is cloudflare here. How is it possible to allow cloudflare to inject scripts, while at the same time having strict-dynamic set? You cannot give cloudflare a nonce, and strict-dynamic will not let you white-list so how is it possible to overcome this?
If you use strict-dynamic, it ignores the allow-listed domain. That's why that approach isn't working.
BTW, you can't use a full URL like http: https://static.cloudflareinsights.com https://mydomain.app/cdn-cgi/scripts/6c4dd986/cloudflare-static/email-decode.min.js anyway. You can only use https://static.cloudflareinsights.com https://mydomain.app/cdn-cgi/scripts/6c4dd986/cloudflare-static/.
BTW, you may find https://csp-evaluator.withgoogle.com/ helpful for finding problems like that in your CSP. (I'm not affiliated with them. I just think it's useful.)
At the end of the day, Cloudflare is going to need to fix this on their side. They see your CSP in your response. They need to make use of your nonce. They do this sometimes. If you read https://developers.cloudflare.com/bots/reference/javascript-detections/, it says, "If your CSP uses a nonce for script tags, Cloudflare will add these nonces to the scripts it injects by parsing your CSP response header."

Do I need to enable HSTS in addition to forcing HTTPS in .htaccess?

I know nothing about this stuff so please ELI5 in your replies.
Following the instructions from my provider, Dreamhost, I installed an SSL certificate and then added these lines to my .htaccess file to force HTTP requests to be rewritten to HTTPS requests.
# Redirect http requests to https
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Everything seems to be working correctly, ie: every time I try to access a page under that domain with HTTP, it is rewritten to HTTPS and the "Secure" icon shows in the address bar.
My question is, do I need to also enable HSTS? Reading about it, it seems to do the exact same thing as the previous changes to the .htaccess file. Here's an excerpt from A2 Hosting (not my provider):
Enabling HSTS
When HSTS is enabled for a site, web browsers automatically change any
insecure requests (http://) to secure requests (https://). All you
need to do to enable HSTS is add a header to your site's .htaccess
file. Web browsers recognize this header, and then take care of the
rest without any further intervention on your part.
They suggest adding this to .htaccess:
Header set Strict-Transport-Security "max-age=31536000" env=HTTPS
Another tutorial, this time specific to Dreamhost, says to enable HSTS along with forcing HTTPS in the .htaccess file, but doesn't really say why. This page suggests something slightly different:
Header set Strict-Transport-Security "max-age=31415926; includeSubDomains; preload" env=HTTPS
Do I need the "https rewrite" code snippet AND HSTS? Or is having only the "https rewrite" code snippet good enough? Do I need the HSTS code at all, and if so, what's the difference between the two lines of HSTS code in my post?
HSTS lets the browser know to only connect over https by default but each one of the different flags does something a bit different:
includeSubdomains
That means that if your site is on mydomain.com, the policy will apply to all subdomains (i.e. foo.mydomain.com, bar.mydomain.com, etc). Without this included. the policy only applies for the exact domain in question.
preload
While HSTS is great conceptually, the first time someone types mydomain.com the browser will try to contact your site on http scheme since it doesn't know that you have your site on https which gives a MITM attacker room to serve you malicious version of the site (aka TOFU problem).
To work around this, there is a centralized list for browsers for sites that should be contacted on https by default but to be able to get yourself on that list, you have to have the preload flag in that header. You can see more about this here.
The default, if a scheme (http or https) is not explicitly specified, is http.
Therefore a redirect is necessary to redirect it to your preferred https version since most visitors who type the URL will not include the scheme and so go to http version.
HTTP Strict-Transport-Security (HSTS) is a security method, to ensure you always stay on https. It is not really intended to do away with the need for the redirect. In particular HSTS works by sending your web browser a message (using a HTTP response header) to say "please only use https for this site, for the next X amount of time". This message should only be sent when visiting the site over https. Therefore if you do not redirect in the first place, then a lot of visitors may not even realise you have a https site and so will not get the HSTS instruction.
HSTS is mostly used as a way to change the default of a website to https, and to prevent man in the middle (MITM) attacks which might attempt to keep you on http: e.g. if you connect to a hacker's wifi network and go to your bank website, they will not be able to hijack this connection if it's done over https but will be able to if it's done over http, so attackers will intercept the http request and stop the redirect happening, to keep you on http and intercept all messages to and from your bank.
You can "preload" the HSTS instruction in web browser's code, which gives even more security, as you don't need to visit the site over https first to get the HSTS instruction. This should be caveated that there is basically no way back from this and this should only be considered if you really understand HSTS. There are many, many, many requests to remove sites from Preload list which takes a minimum of 3 months for Chrome (no guarantees for other browsers) and makes your site completely inaccessible during that time if you are not on https. So there is a real danger here! Particularly if some of your site is served over https (e.g. www.example.com) but some of it is not (e.g. intranet.example.com). This is a danger of HSTS as well but even more dangerous with preloading.
The other point to note is that many web agents will not use HSTS and especially not preload lists (e.g. Search Engine Crawlers, older browsers... etc). So again HSTS should be used on top of, instead of as a replacement to, a redirect.
HSTS is a great security measure and should be used by all sites (once they have stopped using http completely) but, like most security measures, does come with its own risks. So make sure you understand it before deploying it. I hate sites and tutorials that say turn it on without explaining it and the risks. In theory a site using HSTS may no longer need to redirect, but in practice it still will need to for the first visit and agents that don't understand or implement HSTS.
To summarise:
Always use redirects.
Strongly consider HSTS, but read up on it first, and start with a low max-age, and without includesubdomains and preload - until you truly understand what they mean.
if running a high risk site, then consider submitting your site to HSTS preload list as a high level of security, but again be aware of risks here. Only do this if you really understand HSTS and feel like you need this level of security.

Resources