How do I fix an error 403 when loading Fathom Analytics’ script.js with CSP in place? - apache

I have a strict CSP (Content-Security-Policy) in place, allowing the Fathom Analytics script.js to be loaded from a custom domain.
In the .htaccess on Apache:
script-src 'self' 'nonce-%{UNIQUE_ID}e' my-custom-domain.example.com;
Application layer:
<script src="https://my-custom-domain.example.com/script.js" data-site="ABCDEFGH" defer nonce="<?php echo $_SERVER['UNIQUE_ID']; ?>"></script>
It always returns “loading failed” with an error 403 in the console.
The nonce was introduced for testing, as I thought, that might solve the problem. It doesn’t. (I know, I know, this is not the most secure method to use a nonce.)
I have tried variants of the custom domain, too (with protocol, without protocol, wildcard subdomain, …).
Turning off the CSP “fixes” the issue. Meaning, the 403 only kicks in, when the CSP is active.
I am relatively new to CSPs and don’t know, how to proceed.
Any suggestions are appreciated.

Right after reaching out publicly I found the solution:
I had to get rid of the “Referrer-Policy” directive—or rather provide an empty one like so: Header always set Referrer-Policy "".
After doing that, make sure to employing rel="no-referrer" on all external links instead.
Also I had to add the custom domain to the img-src directive (on top of the script-src one).
The nonce is not necessary to make this work.

Related

I want to add the ID in the API [duplicate]

I am working on an app using Vue js.
According to my setting I need to pass to a variable to my URL when setting change.
<!-- language: lang-js -->
$.get('http://172.16.1.157:8002/firstcolumn/' + c1v + '/' + c1b, function (data) {
// some code...
});
But when my app hit on URL, it shows the following message.
Failed to load http://172.16.1.157:8002/firstcolumn/2017-03-01/2017-10-26: Redirect from 'http://172.16.1.157:8002/firstcolumn/2017-03-01/2017-10-26' to 'http://172.16.1.157:8002/firstcolumn/2017-03-01/2017-10-26/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
In addition to what awd mentioned about getting the person responsible for the server to reconfigure (an impractical solution for local development) I use a change-origin chrome plugin like this:
Moesif Orign & CORS Changer (use to be free but now wants a work email address >_>)
Allow CORS: Access-Control-Allow-Origin
You can make your local dev server (ex: localhost:8080) to appear to be coming from 172.16.1.157:8002 or any other domain.
In case the 2nd plugin link breaks in the future or the plugin writer decides to capitalize off the fame of this thread, open your browser's
plugin marketplace and search "allow cors", there's going to be a
bunch of them.
Thanks all, I solved by this extension on chrome.
Allow CORS: Access-Control-Allow-Origin
If you have control over your server, you can use PHP:
<?PHP
header('Access-Control-Allow-Origin: *');
?>
Ask the person maintaining the server at http://172.16.1.157:8002/ to add your hostname to Access-Control-Allow-Origin hosts, the server should return a header similar to the following with the response-
Access-Control-Allow-Origin: yourhostname:port
Using npm:
To allow cross-origin requests install 'cors':
npm i cors
Add this in the server-side:
let cors = require("cors");
app.use(cors());
When you have this problem with Chrome, you don't need an Extension.
Start Chrome from the Console:
chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security
Maybe you have to close all Tabs in Chrome and restart it.
I will assume that you're a front-end developer only and that you don't have access to the backend of the application (regarding the tags of the question).
Short answer on how to properly solve this in your case? You can't, you'll need somebody else.
What is this about?
You need to understand that CORS is a security thing, it's not just here to annoy you just for fun.
It's purpose is to mainly prevent the usage of a (malicious) HTTP call from a non-whitelisted frontend to your backend with some critical mutation.
You could give a look to this YouTube video or any other one really, but I recommend a visual video because text-based explanation can be quite hard to understand.
You also need to understand that if you use Postman or any other tool to try your API call, you will not get the CORS issue. The reason being that those tools are not Web frontends but rather some server-based tools.
Hence, don't be surprised if something is working there but not in your Vue app, the context is different.
Now, how to solve this?
Depending of the framework used by your backend team, the syntax may be quite different but overall, you'll need to tell them to provide something like Access-Control-Allow-Origin: http://localhost:3000 (or any other port you'll be using).
PS: Using Access-Control-Allow-Origin: * would be quite risky because it would allow anybody to access it, hence why a stricter rule is recommended.
If you're using a service, like an API to send SMS, payment, some Google console or something else really, you'll need to allow your localhost in the dashboard of the service. Ask for credentials to your manager or Tech Lead.
If you have access to the backend, you could it yourself as shown here (ExpressJS in this example): https://flaviocopes.com/cors/
How to hack it in a dirty way?
If you're in a damn hurry and want to get something really dirty, you could use a lot of various hacks a listed in the other answers, here's a quick list:
use any extension who is able to create a middleware and forward the request to the backend (it will work because it's not directly coming from your frontend)
force your browser to disable CORS, not sure how this would actually solve the issue
use a proxy, if you're using Nuxt2, #nuxtjs/proxy is a popular one but any kind of proxy (even a real backend will do the job)
any other hack related somehow to the 3 listed above...
At the end, solving the CORS issue can be done quite fast and easily. You only need to communicate with your team or find something on your side (if you have access to the backend/admin dashboard of some service).
I heavily do recommend trying get it right from the beginning because it's related to security and that it may be forgotten down the road...
The approved answer to this question is not valid.
You need to set headers on your server-side code
app.use((req,res,next)=>{
res.setHeader('Access-Control-Allow-Origin','*');
res.setHeader('Access-Control-Allow-Methods','GET,POST,PUT,PATCH,DELETE');
res.setHeader('Access-Control-Allow-Methods','Content-Type','Authorization');
next();
})
You can also try a chrome extension to add these headers automatically.
Hello If I understood it right you are doing an XMLHttpRequest to a different domain than your page is on. So the browser is blocking it as it usually allows a request in the same origin for security reasons. You need to do something different when you want to do a cross-domain request. A tutorial about how to achieve that is Using CORS.
When you are using postman they are not restricted by this policy. Quoted from Cross-Origin XMLHttpRequest:
Regular web pages can use the XMLHttpRequest object to send and receive data from remote servers, but they're limited by the same origin policy. Extensions aren't so limited. An extension can talk to remote servers outside of its origin, as long as it first requests cross-origin permissions.
To add the CORS authorization to the header using Apache, simply add the following line inside either the <Directory>, <Location>, <Files> or <VirtualHost> sections of your server config (usually located in a *.conf file, such as httpd.conf or apache.conf), or within a .htaccess file:
Header set Access-Control-Allow-Origin "*"
And then restart apache.
Altering headers requires the use of mod_headers. Mod_headers is enabled by default in Apache, however, you may want to ensure it's enabled.
I had the same problem in my Vue.js and SpringBoot projects. If somebody work with spring you can add this code:
#Bean
public FilterRegistrationBean simpleCorsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
// *** URL below needs to match the Vue client URL and port ***
config.setAllowedOrigins(Collections.singletonList("http://localhost:8080"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowedHeaders(Collections.singletonList("*"));
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
I found solution in this article Build a Simple CRUD App with Spring Boot and Vue.js
You are making a request to external domain 172.16.1.157:8002/ from your local development server that is why it is giving cross origin exception.
Either you have to allow headers Access-Control-Allow-Origin:* in both frontend and backend or alternatively use this extension cors header toggle - chrome extension unless you host backend and frontend on the same domain.
Try running this command in your terminal and then test it again.
curl -H "origin: originHost" -v "RequestedResource"
Eg:
If my originHost equals https://localhost:8081/ and my RequestedResource equals https://example.com/
My command would be as below:
curl -H "origin: https://localhost:8081/" -v "https://example.com/"
If you can notice the following line then it should work for you.
< access-control-allow-origin: *
Hope this helps.
Do specify #CrossOrigin(origins = "http://localhost:8081")
in Controller class.
You can solve this temporarily by using the Firefox add-on, CORS Everywhere. Just open Firefox, press Ctrl+Shift+A , search the add-on and add it!
You won't believe this,
Make sure to add "." at the end of the "url"
I got a similar error with this code:
fetch(https://itunes.apple.com/search?term=jack+johnson)
.then( response => {
return response.json();
})
.then(data => {
console.log(data.results);
}).catch(error => console.log('Request failed:', error))
The error I got:
Access to fetch at 'https://itunes.apple.com/search?term=jack+johnson'
from origin 'http://127.0.0.1:5500' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
But I realized after a lot of research that the problem was that I did not copy the
right URL address from the iTunes API documentation.
It should have been
https://itunes.apple.com/search?term=jack+johnson.
not
https://itunes.apple.com/search?term=jack+johnson
Notice the dot at the end
There is a huge explanation about why the dot is important quoting issues about DNS and character encoding but the truth is you probably do not care. Try adding the dot it might work for you too.
When I added the "." everything worked like a charm.
I hope it works for you too.
install:
npm i cors
Then include cors():
app.get("/list",cors(),(req,res) =>{
});
In addition to the Berke Kaan Cetinkaya's answer.
If you have control over your server, you can do the following in ExpressJs:
app.use(function(req, res, next) {
// update to match the domain you will make the request from
res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN.TLD");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
https://enable-cors.org/server_expressjs.html
I tried this code,and that works for me.You can see the documentation in this link
var io = require("socket.io")(http, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
})
The reason that I came across this error was that I hadn't updated the path for different environments.
you have to customize security for your browser or allow permission through customizing security. (it is impractical for your local testing)
to know more about please go through the link.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
These errors may be caused due to follow reasons, ensure the following steps are followed. To connect the local host with the local virtual machine(host). Here, I'am connecting http://localhost:3001/ to the http://abc.test Steps to be followed:
1.We have to allow CORS, placing Access-Control-Allow-Origin: in header of request
may not work. Install a google extension which enables a CORS request.*
2.Make sure the credentials you provide in the request are valid.
3.Make sure the vagrant has been provisioned. Try vagrant up --provision this make the localhost connect to db of the homestead.
Try changing the content type of the header. header:{ 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8;application/json' }
this point is very important.
Another solution to this problem in a specific scenario :
If
AWS APIGW is your backend with authentication enabled and
authentication fails,
your browser may end up complaining about CORS even if CORS is enabled in APIGW. You also need to enable CORS for 4XX as follows
API:YourAPI > Resources > /YourResource > Actions > Enable CORS > Gateway Responses for yourAPI check Default 4XX
Authentication will still fail but it won't look like CORS is the root cause
$.get('https://172.16.1.157:8002/firstcolumn/' + c1v + '/' + c1b, function (data) {
// some code...
});
Just put "https" .

Laravel Mix VueJS production page blank

After long frustrating hours of research I finally found the cause for my Laravel7 VueJS (within blade templates) application running on nginx throwing a blank screen. Yet I lack the explanation or correct config.
When I accessed any route it would be seen for around 200ms and then switch to a white screen without any errors in npm run prod config.
Body tag would be completely empty (it looked uncommented in the inspector)
[...]
<body>
<!-- -->
</body>
[...]
Funny enough (sarcastically speaking) on page reload the login page would work normally but after accessing any other route it would revert to the behaviour described above.
After switching to npm run dev the console threw the following error:
[Vue warn]: It seems you are using the standalone build of Vue.js in an environment with Content Security Policy that prohibits unsafe-eval. The template compiler cannot work in this environment. Consider relaxing the policy to allow unsafe-eval or pre-compiling your templates into render functions.
and
EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "default-src 'self' http: https: data: blob: 'unsafe-inline'".
Which made me realize my nginx security config which I generated using the fabulous Tool provided by DigitalOcean included the following line:
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
After removing and restarting nginx everything works and looks as it does on my dev environment.
From what I get I now theoretically make my site vulnerable to XSS attacks but I do not fully understand what the option does or if it is safe to run without it with these circumstance.
The CSP header just lets your browser know what sources of JS are allowed. However, it is really a backup plan - what causes XSS is some code on your system that would render unauthorised JavaScript.
For example, the comment boxes on Stack Overflow allow me to enter the following text: <script src="http://evilserver.com/malicious.js"></script>. Stack Overflow know what they are doing, so they make sure that what is rendered is HTML, and not a literal <script> tag. Thus, you need to make sure you take the necessary care when rendering user supplied content and you will be OK (in general you do this in your output layer, not when accepting/storing input).
If you accept HTML input from users (as Stack Overflow does) then you have to be especially careful to allow only certain tags, and to ensure that any JS vectors are blocked up. So, the following text:
is actually in an <i> tag, which is rendered literally in the web app
That one is OK, since it is safe. You do need to make sure that any attributes are carefully checked, and any invalid markup is rejected. These can also be the source of security problems. This is a complex enough problem that, if you need users to be able to input HTML, you should not attempt to filter it yourself. Use a well-tested and well-regarded library instead.

Enabling Content-Security-Policy on a minimal web app

I'm new to CSP and my goal is to enable the simplest possible CSP header.
Based on reading the spec and MDN docs I thought my app should work but unfortunately no luck on Chrome Canary v70.
I setup a minimal repo to reproduce. Can you see where I've gone wrong?
Turns out I was misunderstanding the details a bit. I'll post my solution here in case it helps someone else in the same boat.
My goal is to serve a React SPA with CSP enabled. The app happens to use Material-UI, which uses JSS, which injects inline styles - which of course are blocked by default with CSP.
Because it's a static SPA for the frontend and modifying HTTP headers is out of scope of the SPA, I instead generate a nonce on the web server. The nonce gets injected into the CSP HTTP Header and also in the index.html tag consistent with what JSS expects.
The upside is CSP is protecting the SPA, and we don't have to use unsafe-inline escape hatch. The downside, but a small one, is that index.html is dynamic now and can't be cached. But seeing as the file is already tiny (<1kb) the benefits of CSP seem worth that tradeoff.

Http to Https redirection not happening automatically

I am trying to access a secure website using this kind of url: https://securenet.someBank.com. Everything is good and I am shown the login page. Now when I just type:
http://securenet.someBank.com (i.e http instead of https) I expect to get back a page with https in the browser. (e.g when you say:http://mail.yahoo.com, you get back https://mail.yahoo.com).
But in this case https:://securenet.someBank.com just says :Page cannot be displayed.
So what did the website developer do wrong in implementing security? I am just curious. I thought this kind of thing (http --> https redirection) was handled automatically by the web server and the website developer does not even need to do anything. But apparently it is not so.
The redirections from HTTP to HTTPS are merely a convenience for the user.
As I was saying in this answer on Webmasters.SE, only the end user can check whether HTTPS is used at all, and whether it's used correctly. A MITM attacker could otherwise prevent that initial redirection from happening at all.
These automatic redirections are only useful based on the assumption that there's no MITM performing such an attack. They're useful to get the user used to seeing HTTPS on pages that should be secure, but whatever happens, it will always be up to the user to check what they're connecting to. Therefore, I wouldn't necessarily call the absence of such a redirection a developer or sysadmin mistake.
As a user, you should always bookmark and use the https:// address for sites where you expect it should be used.
[...] https://securenet.someBank.com. Everything is good and I am shown the login page.
[...]
But in this case https:://securenet.someBank.com just says :Page cannot be displayed.
Here, assuming the double :: is a typo in your question, you seem to contradict yourself. If https://securenet.someBank.com just says "Page cannot be displayed", this would be a mistake indeed.
besides the recommendation by Bruno above I would recommend you to read the following:
https://www.owasp.org/index.php/HTTP_Strict_Transport_Security
There are two things you could do:
1) Force HTTP Strict Transport Security
2) Do a permanent redirect as described in the example on that page.
Any questions, just let me know.
Fabio
#fcerullo
Probably wrong server configuration. For example in apache one must define a redirect option in httpd.conf file in order to automaticaly redirect to the https URL of the page.

Double slash at beginning of javascript include

I have been looking at the html5 boilerplate and noticed that the jquery include url starts with a double slash. The url is //ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js
Why is the http: missing?
I hate answering with a link but this explains it - http://paulirish.com/2010/the-protocol-relative-url/
Using a protocol relative URL like "//mydomain/myresource" will ensure that the content will be served via the same scheme as the hosting page. It can make testing a bit more awkward if you ever use FILE:// and then some remote locations as they will obviously resolve back to FILE. Never the less it does resolve the mixed insecure/secure content messages you can cause by not using it.
So that if the .html is accessed via HTTPS; the page will not have any unsecured script.