Content-Security-Policy Blocking Whitelisted Domains - http-headers

My site has been running a content-security-policy-report-only header for several months, during which time I have seen a number of violations for a domain which should be whitelisted. The site receives enough traffic and the reports are infrequent enough that it seems as if the policy must be working as intended for most users.
The following report shows both the original policy and the problematic violation:
{"csp-report":{
"document-uri":"https://admin1.sitespect.com/",
"referrer":"https://admin1.sitespect.com/",
"violated-directive":"script-src-elem",
"effective-directive":"script-src-elem",
"original-policy": "
report-uri /log/CSP/PolicyViolations?csptoken=ZTBXXVPXFRBRTETZFOQK;
default-src 'self' 'unsafe-eval' 'unsafe-inline';
frame-src * data:;
img-src * data: blob:;
script-src https://www.google.com https://js.hs-scripts.com https://*.receptive.io https://js.hsadspixel.net https://js.hs-banner.com https://js.hs-analytics.net https://js.hscollectedforms.net https://feedback.pendo.io https://www.googletagmanager.com https://www.googleadservices.com https://googleads.g.doubleclick.net https://forms.hubspot.com https://api.feedback.eu.pendo.io https://js.usemessages.com 'self' 'unsafe-inline' 'unsafe-eval';
script-src-elem https://www.google.com https://js.hs-scripts.com https://*.receptive.io https://js.hsadspixel.net https://js.hs-banner.com https://js.hs-analytics.net https://js.hscollectedforms.net https://feedback.pendo.io https://www.googletagmanager.com https://www.googleadservices.com https://googleads.g.doubleclick.net https://forms.hubspot.com https://api.feedback.eu.pendo.io https://js.usemessages.com 'self' 'unsafe-inline' 'unsafe-eval';
connect-src https://api.feedback.eu.pendo.io https://api.hubapi.com https://forms.hubspot.com https://recs.sitespect.net https://*.receptive.io https://api.hubspot.com 'self';
worker-src 'self' 'unsafe-eval' 'unsafe-inline' blob:;",
"disposition":"report",
"blocked-uri":"https://feedback.pendo.io/js/widget/widget.js",
"status-code":0,
"script-sample":""
}}
Is there something I've missed in my policy? I know that enforcement of the CSP is different across browsers occasionally - the violations from the past month have been from Chrome 87 based on user agents, but I can't guarantee that's the case for all of them.

The answer is in the "status-code":0, string of the violation report. 0 (really it's empty) means no HTTP status code was returned when browser try to load https://feedback.pendo.io/js/widget/widget.js.
It happens because of Ads blokers blocks connection. The pendo.io domain contains in a blacklists for example AdBlock and AdGuard.
Browser can not access such "whitelisted" domain and it do not get any HTTP status code (200 OK, 301/304/403/404/500 etc). Therefore some browsers erroneously treats this as a CSP violation, not as network error.

Related

firefox in centos set csp header not effective

I try to join the csp header for the response of each request accessed by firefox through the proxy, but no csp report send, and try to do same thing in mac firefox(same code), the program runs without problems and i recv csp report,so i think it may be problem of firefox in centos
this is my environment, install firefox by yum, code use selenium operate firefox and use browsermob to add csp header in response, in code result csp header already add in response,firefox in headless mode.
centos 7
firefox.x86_64 68.5.0-2.el7.centos #update
firefox.i686 68.5.0-2.el7.centos update
firefox-noscript.noarch 11.0.3-3.el7 epel
firefox-pkcs11-loader.x86_64 3.13.4-1.el7 epel
this is my csp rule
Content-Security-Policy-Report-Only: script-src 'none'; style-src 'none'; img-src 'none'; font-src 'none'; connect-src 'none'; media-src 'none'; object-src 'none'; child-src 'none'; frame-src 'none'; worker-src 'none'; worker-src 'none'; worker-src 'none'; base-uri 'none'; manifest-src 'none'; report-uri http://www.test.com
I use this to recv csp report and use this report to create csp rule for web
Is there any way to solve this problem
update firefox version, test v74.0 work well
yum version to old, install by this in centos 7
cd /usr/local
wget https://ftp.mozilla.org/pub/firefox/releases/74.0/linux-x86_64/zh-CN/firefox-74.0.tar.bz2
tar xvjf firefox-74.0.tar.bz2
yum -y install gtk3-devel
yum install libXt*
ln -s /usr/local/firefox/firefox /usr/bin/firefox

403 Error when using fetch to call Cloudfront S3 endpoint with custom domain and signed cookies

I'm trying to create a private endpoint for an S3 bucket via Cloudfront using signed cookies. I've been able to successfully create a signed cookie function in Lambda that adds a cookie for my root domain.
However, when I call the Cloudfront endpoint for the S3 file I'm trying to access, I am getting a 403 error. To make things weirder, I'm able to copy & paste the URL into the browser and can access the file.
We'll call my root domain example.com. My cookie domain is .example.com, my development app URL is test.app.example.com and my Cloudfront endpoint URL is tilesets.example.com
Upon inspection of the call, it seems that the cookies aren't being sent. This is strange because my fetch call has credentials: "include" and I'm calling a subdomain of the cookie domain.
Configuration below:
S3:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>https://*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Cloudfront:
Not sure what I could be doing wrong here. It's especially weird that it works when I go directly to the link in the browser but not when I fetch, so guessing that's a CORS issue.
I've been logging the calls to Cloudfront, and as you can see, the cookies aren't being sent when using fetch in my main app:
#Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version fle-status fle-encrypted-fields
2019-09-13 22:38:40 IAD79-C3 369 <IP> GET <CLOUDFRONT ID>.cloudfront.net <PATH URL>/metadata.json 403 https://test.app.<ROOT DOMAIN>/ Mozilla/5.0%2520(Macintosh;%2520Intel%2520Mac%2520OS%2520X%252010_14_6)%2520AppleWebKit/537.36%2520(KHTML,%2520like%2520Gecko)%2520Chrome/76.0.3809.132%2520Safari/537.36 - - Error 5kPxZkH8n8dVO57quWHurLscLDyrOQ0L-M2e0q6X5MOe6K9Hr3wCwQ== tilesets.<ROOT DOMAIN> https 281 0.000 - TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 Error HTTP/2.0 - -
Whereas when I go to the URL directly in the browser:
#Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version fle-status fle-encrypted-fields
2019-09-13 22:32:38 IAD79-C1 250294 <IP> GET <CLOUDFRONT ID>.cloudfront.net <PATH URL>/metadata.json 200 - Mozilla/5.0%2520(Macintosh;%2520Intel%2520Mac%2520OS%2520X%252010_14_6)%2520AppleWebKit/537.36%2520(KHTML,%2520like%2520Gecko)%2520Chrome/76.0.3809.132%2520Safari/537.36 - CloudFront-Signature=<SIGNATURE>;%2520CloudFront-Key-Pair-Id=<KEY PAIR>;%2520CloudFront-Policy=<POLICY> Miss gRkIRkKtVs3WIR-hI1fDSb_kTfwH_S2LsJhv9bmywxm_MhB7E7I8bw== tilesets.<ROOT DOMAIN> https 813 0.060 - TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 Miss HTTP/2.0 - -
Any thoughts?
You have correctly diagnosed that the issue is that your cookies aren't being sent.
A cross-origin request won't include cookies with credentials: "include" unless the origin server also includes permission in its response headers:
Access-Control-Allow-Credentials: true
And the way to get S3 to allow that is not obvious, but I stumbled on the solution following a lead found in this answer.
Modify your bucket's CORS configuration to remove this:
<AllowedOrigin>*</AllowedOrigin>
...and add this, instead, specifically listing the origin you want to allow to access your bucket (from your description, this will be the parent domain):
<AllowedOrigin>https://example.com</AllowedOrigin>
(If you need http, that needs to be listed separately, and each domain you need to allow to access the bucket using CORS needs to be listed.)
This changes S3's behavior to include Access-Control-Allow-Credentials: true. It doesn't appear to be explicitly documented.
Do not use the following alternative, even though it would also work, without understanding the implications.
<AllowedOrigin>https://*</AllowedOrigin>
This also results in Access-Control-Allow-Credentials: true, so it "works" -- but it allows cross-origin from anywhere, which you likely do not want. With that said, do bear in mind that CORS is nothing more than a permissions mechanism that is applicable to well-behaved, non-malicious web browsers, only -- so setting the allowed origin settings to only allow the correct domain is important, but it does not magically secure your content against unauthorized access from elsewhere. I suspect you are aware of this, but it is important to keep in mind.
After these changes, you'll need to clear the browser cache and invalidate the CloudFront cache, and re-test. Once the CORS headers are being set correctly, your browser should send cookies, and the issue should be resolved.

Vue Firebase Verify ID Token CORS issue

I am trying to verify an ID Token using the Firebase Admin SDK as per instructions. My current auth code looks like this (in Vue):
// Auth.vue, inside the firebaseui config callback
signInSuccessWithAuthResult: function(authResult, redirectUrl) {
authResult.user
.getIdToken(/* forceRefresh */ true)
.then(function(idToken) {
// Send token to your backend via HTTPS
// ...
console.log(idToken);
})
.catch(function(error) {
// Handle error
console.log(error);
});
The login works fine and I can get authResult perfectly. However, it seems the function getIdToken is the problem, as I get the following error on my console:
Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource at
https://securetoken.googleapis.com/v1/token?key=AIzaSyApp5yu051vMJlNLoQ1ngVSd-f2k7Pdavc.
(Reason: CORS request did not succeed).
In my request list, the one hanging is an OPTIONS method, with the following headers:
OPTIONS /v1/token?key=AIzaSyApp5yu051vMJlNLoQ1ngVSd-f2k7Pdavc HTTP/1.1
Host: securetoken.googleapis.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.8,pt-BR;q=0.5,de;q=0.3
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: POST
Access-Control-Request-Headers: x-client-version
Origin: http://localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
I am not even sure where the problem lies. Is it coming from the Vue side? I am running it in a dev server (by simple yarn serve, vue cli 3). Would the solution be when I run Vue on a production server where I can actually configure cors?
Any light on the matter is extremely welcome...
Thanks!!
Figured it out.
I was calling it in the wrong place. What helped was this thread, which pointed me out to Preflighted Requests which is what the OPTIONS request is:
"preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data.
So I realized I should not be sending this request within my Post request where I got the authorization in the first place. Moving it to another method made it work.

Cross-Origin Resource Sharing between https and http?

i have a page that is hosted on both HTTP and HTTPS, and it makes a HTTP call with jquery to a local http server on the client computer with the following code:
var url = "http://127.0.0.1:1234/Ping";
var ajaxSettings = {
url: url,
timeout: 1000
};
return $.ajax(ajaxSettings);
the client application has the following headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: Accept, Origin, Content-type
This works great when using http but when using https i get a error.
Is there any way to solve this? (generating a ssl certificate and registering it seems a bit overkill)

CORS complaint on Safari 5.1.7 (windows 7)

A page at http://www4.example.com that tries to an xhr connection to http://www6.example.com/
The browser sends a GET request with this header:
Origin: http://www4.example.com
The www6.example.com server sends back:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://www4.example.com
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/plain
Date: ...
Keep-Alive: timeout=5, max=100
Transfer-Encoding: Identity
Server: Apache/2.2.20 (Ubuntu)
Vary: Accept-Encoding
X-Powered-By: PHP/5.3.6-13ubuntu3.7
And yet I get:
XMLHttpRequest cannot load http://www6.example.com/myscript.php?xhr=1&t=1234333223. Origin http://www4.example.com is not allowed by Access-Control-Allow-Origin.
My code matches my understanding of the CORS standard, and works fine with Chrome, Firefox, Opera, etc. so I'm going to assume this is a Safari 5.1 bug? My question is what do I need to do to work around it?
After a lot of trial and error, and watching network traffic, I think I can self-answer.
The Safari bug is that it sends an OPTIONS pre-flight request first, even though it is a GET request.
To add some extra complexity, it appears to only send this on the 2nd request. (I think this is because my 2nd request sends an extra custom header... but I couldn't actually isolate that, so I think there is something else going on as well - perhaps cache interactions?)
Sending Access-Control-Allow-Headers in the main response does not fix the problem: it does the OPTIONS request first, so never gets that far.
The fix I did was to put this at the very top of the PHP script:
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS'){
header("Access-Control-Allow-Origin: ".#$_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Headers: Last-Event-Id, Origin, X-Requested-With, Content-Type, Accept, Authorization");
exit;
}
Sending back "Access-Control-Allow-Headers: *" did not work. You have to explicitly list the headers you want. I briefly experimented and it appears they are case-insensitive.
Sending back "Access-Control-Allow-Methods: POST, GET, OPTIONS" was not needed.
As an aside, Cookies are sent, but basic auth details are not sent (despite explicitly listing the Authorization header there). This might be a deliberate limitation of the CORS implementation, as of this version of WebKit (534.57.2), not a bug.