I just wanted to make a simple website with Node.js, but I can't manage to get the CDN of CSS and JS files from Bootstrap without being blocked by Content Security Policy.
Here's what happens:
CASE 1 (works): When I just move my HTML file in the browser (so C://... .html) it works and gets all CDN's
CASE 2 (doesn't work): When I start my server (using express) in Node.js and then go to localhost:4000, it doesn't get the CDN's due to Content Security Policy (I can see it in console as it says it's being blocked by it)
I tried to put in the meta tag with the CDN's in it from here: Content Security Policy: The page's settings blocked the loading of a resource, but it didn't work and I even got more errors.
How do I fix this? I can't find any solution.
CASE 1 (works): When I just move my HTML file in the browser (so C://... .html) it works and gets all cdn's
When you web page works from C://... .html it's no Content Security Policy (CSP) published therefore nothing is blocked.
CASE 2 (doesn't work): When I start my server (using express) in Node.js and then go to localhost:4000 it doesn't get the CDN's due to Content Security Policy (I can see it in console as it says its being blocked by it)
When you web page works from localhost:4000 the server publishes a default CSP. NodeJS has in dependencies a Helmet middleware which publishes this default CSP header.
You can disable a middleware:
// This disables the `contentSecurityPolicy` middleware but keeps the rest.
app.use(
helmet({
contentSecurityPolicy: false,
})
);
or configure it to allow external CDNs, see details in helmet.contentSecurityPolicy(options) section.
Note: next time please add console messages into a question, they can be very helpful in case of CSP.
Content Security Policy works the other way around. The CDN needs to give access to your url to use their resource, not the other way around. They will have to add a header with access-control-allow-origin and then set the value of * which means anyone can use their resource files or specifically your domain url.
So most likely you have a typo in your url and that domain doesn't allow localhost to fetch their js files.
Related
I am trying to load socket.io using the following code:
<script src="http://cdn.socket.io/socket.io-1.4.5.js"></script>
However some users have reported the following error to me:
Failed to load https://cdn.socket.io/socket.io-1.4.5.js ERR_SSL_PROTOCOL_ERROR
Is this an automatic security setting on modern browsers? And if so can it be disabled?
The problem is not your fault!
Accessing that link in my browser fails as well, and inspecting the unsuccessful request shows that the following header was set:
Upgrade-Insecure-Requests: 1
This tells the browser to "upgrade" all http:// URLs to https://, which seems to mirror the error your users are reporting.
ERR_SSL_PROTOCOL_ERROR indicates that the SSL certificate for https://cdn.socket.io/ is incorrectly configured and thus the browser (rightly) assumes the worst, and chooses not to trust data served from that domain over the secure protocol. When the domain is configured to "upgrade" insecure requests to secure ones, and secure requests are rejected by the browser, it becomes clear why there is no way to access the content correctly at either URL.
I would contact the administrators of the website and inform them of the problem, or just simply switch to another CDN like Chris Chen suggested:
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.4.5/socket.io.min.js"></script>
Sounds like the users who are experiencing that error are hitting the https version of your page. Best way to deal with this issue is by changing your code to:
<script src="//cdn.socket.io/socket.io-1.4.5.js"></script>
Or
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
The former is preferable (because it is faster for http users) unless you are working with an .html or .htm page and want to open it without a web server.
The link is not working at all from anywhere. Is it a private link that require certification?
If you just want socket.io.js, use link from https://cdnjs.com/libraries/socket.io
I recently added the crossorigin attribute to certain script tags to enable my scripts to gather error information from scripts from a different subdomain. I added the header in nginx to allow the cross-origin request.
Since then, I occasionally have a page load without the browser requesting certain javascript files from the server. Reloading the page resolves the issue, but this has happened several times now.
I think this is related to CORS, but since it works most of the time, I have no idea how to reproduce it.
Here are some excerpts from my code:
Nginx configuration contains this rule for javascript files in a certain location:
add_header 'Access-Control-Allow-Origin' "$http_origin";
My script tag in the php page:
<script type="text/javascript" src="<?php print "$host/js/$filename?v=$version";?>" crossorigin></script>
When my page loads, I can see in Firebug that the script tag is correct, but in the Firebug Net tab there isn't even a request shown. Normally there is a request shown, even if it uses a cached version of the file.
I found one question here which I thought might be related:
all of my browsers are not sending the origin header
But thinking about it further, I think there should be an initial request which would fail and which would show in Firebug.
Does anyone have any theories on why this might be happening?
Edit:
I added a separate access log for my CORS requests. Any file in the location which gets Nginx adding the CORS header also gets logged in a new access log.
When the page fails to load a javascript file, Nginx is logging a request with a 304 status (not modified). That means that Nginx got a conditional request for the resource only if modified, and Nginx sent back the 304 and nothing else. If the cached version was not loaded with the CORS header, then maybe the javascript can not be executed.
I have a version number which I append to the src of the script tag as shown above. This version number has changed. So shouldn't that cause the browser to re-request all these resources as if they had a different file name? I think the browser should have been treating these as uncached resources. There should not have been any requests that could result in a 304. What could be causing this?
I figured out what's causing this. First, we need more information about the configuration.
I have 3 hosts, a.my.com, b.my.com, and c.my.com. The static files are all served from c.my.com, and the html and php are served from a.my.com and b.my.com.
I added the crossorigin attribute to my script tags so I could get useful error information from my scripts. See the SO question describing this issue here: Cryptic "Script Error." reported in Javascript in Chrome and Firefox
I am using the requesting host as the allowed origin instead of *, as a precursor to whitelisting allowed origins. See this question for more: How to properly setup nginx Access-Control-Allow-Origin into response header based on the Origin header from the request?
My nginx configuration has a long expiration for static content so stuff is cached and not loading down my server with repeated requests. I append a version number to the url for static content so it can be re-requested when something changes. The version number comes from my version in svn, so when I update the server files to the newest version, browsers will all start loading a new url for each static file.
So here's what's happening:
A new user visits a.my.com and loads the page. Javascript files 1 through 5 are loaded from c.my.com for use on a.my.com. Nginx sends them with an origin header allowing "a.my.com" and a far future expiration date. This page works fine, and the javascript loads successfully.
The user then goes on to the other part of the site at b.my.com and loads the page. Javascript files 1 through 10 are requested from c.my.com. Files 1 through 5 are the same files as were loaded for a.my.com. The browser knows it has those files in its cache, so it asks nginx for their status. Nginx replies with a 304 (not modified) and the browser goes on to request the next file.
So now the browser has loaded files 6 through 10 from c.my.com, and has looked in the cache for files 1 through 5. The cached files have their allow origin header attached, and this says "a.my.com" is the allowed origin. The page requesting the files is on b.my.com, so it doesn't match and isn't allowed to use them. So it silently discards them and shows the user a page with missing javascript.
Solutions:
One solution is to send the Access-Control-Allow-Origin with a value of * to allow any origin. This would mean that the cached file is allowed for the current origin even if they didn't initiate the first download. There are security implications for this, as discussed in this SO question: When is it safe to enable CORS?
A second solution is to make each origin use a different url for the same static file. This forces the browser to cache them separately. That allows the Access-Control-Allow-Origin header to be specific to a single origin. The cost is more resource requests coming to the server, and the user's browser uses more memory and storage for cached resources.
You need Vary:Origin in your response headers.
i'm writing a chrome extension that use a content_script.
the content script use XMLHttpRequest to send information about the page to my server, and base on that information the server respond with somethings that has to be done.
everything works well on http pages, but fail on http*s*.
The error i get is:
[blocked] The page at '==https page==' was loaded over HTTPS, but ran insecure content from '===myserver - http===': this content should also be loaded over HTTPS.
If i will use https on my server will it work? even though it's a different domain? is there any way to do it without using ssl on my server?
Thanks.
Yes, you can only call https content from an https page. See these for help on mixed content issue :
https://support.google.com/chrome/answer/1342714?hl=en
http://kb.iu.edu/data/bdny.html
You can test your extension with mixed content by enabling it explicitly as instructed at:
http://wiki.sln.suny.edu/display/SLNKB/Enabling+mixed+content+in+Google+Chrome
If you enable SSL/https on your web-server this will solve the issue for your users also. A cheaper and easier way to enable SSL on your server almost instantly would be to use Cloudflare.
If a page is served over https but the associated files are served from a non-secure http website, Chrome will throw the “insecure content” warning. Is there an event/property that I could be using to know when Chrome has blocked an unsecure content and also know if the user allowed the insecure content. A shield appears at the right of the adress bar when Chrome loads "insecure content" and the user has the possibility to click on this shield and still run the script. Is there any event for this?
Thank you.
The only way I can think to do this would be to serve a file over non-https, that would include a function to run if they allow non-secure content.
This script will obviously only be included if they've allowed the non-secure content to be loaded, and therefore works as your event check. You can therefore also check if these haven't been allowed by storing a global variable in the non-secure file & checking for it in a secure JS file (or within the document).
Obviously, if you're serving content via SSL, you should really ensure all of your content included is also over SSL.
I want to serve my JavaScript scripts from a CDN like cloudflare.
Now my scripts communicate with my app server via ajax. Wouldn't the same-origin policy restrictions come into play when I load these scripts from a CDN?
Let's say my app is on the domain:
http://app.com
And I load my scripts from
http://cdn.com/xyz/all.js
Now, since my scripts are loaded from a different domain than the domain my app is running from, I guess the same origin policy would prevent me from doing ajax communication with my app.
Am I getting something wrong?
No, it will work. That's why JSONP works. The "origin" of the script is the page it is executed in, not where it comes from.
As you asked for it, here's a reference (I couldn't find any better, but Crockford is well known)
The src attribute, surprisingly, is not constrained by the Same Origin Policy. This means that a script element can be created which can go to any server, fetch a script, and execute it. If the script causes the delivery of JSON-encoded data, then this is a very useful thing. Unfortunately, there is no way to constrain the script or to inspect it before it executes. It runs with the same authority as scripts from the page. So the script can access and use its cookies. It can access the originating server using the user's authorization. It can inspect the DOM and the JavaScript global object, and send any information it finds anywhere in the world. The Script Tag Hack is not secure and should be avoided.
http://javascript.crockford.com/script.html
Not really a reference: If this wouldn't work, nobody could include jQuery from Google's CDN and then use it's $.ajax method.