CORS, Content Security Policy and Access Control for SAFE sites

This topic is for anyone like me who is new to CORS and frequently mystified by browser complaints of failed “pre-flight checks” and so on. Such errors are the result of the Content Security Policy enacted by SAFE Launcher to improve security of users accessing web content on SAFE Network.

This is a place to gather together some info and how to’s that is editable by anyone (i.e. it’s a wiki post).

I’ll kick it off below with my meagre understanding at this point. If you have further advice either edit it into this post or in a reply with a suggestion that I add it. Now I’m off to try and get my RS.js test apps to jump the hurdle of SAFE Launcher Content Security Policy!

Info & Tips

  • Content Security Policy is controlled by SAFE Launcher. To see the details of these restrictions, search for “Content-Security-Policy” and “Access-Control” etc in safe_launcher/app/server/web_proxy.js.
  • Turn On The Browser Console: obvious once you know, but if your website isn’t behaving turn on your browser’s debugging features and particularly the output sent to the browser console. This can be done with Ctrl-Shift-K in Firefox and Ctrl-Shift-J in Chrome.

How To Comply

Please help fix and add to what follows to act as a quick start guide for anyone trying to leap this hurdle.

Here is what I currently understand (not much :slight_smile:):

  • Don’t Inline Things: scripts and CSS must all be in separate files and linked from your HTML, and not be included inline inside your HTML file.
  • CORS Everywhere: need a quick fix so you can test without hitting these errors? There’s a browser setting you can hack to turn off CORS pre-flight checks, and in Firefox there’s the “CORS Everywhere” plugin to give you a toolbar button to toggle this setting.
  • Beware: confusion and head bashing can occur when SAFE Launcher returns a 403 (Forbidden) or perhaps it was 404 (Not Found). The browser can report this as a CORS error, which technically it might be, but it can throw you off the scent if you actually expect and need to handle the error.
  • SAFE API Endpoints: In a deployed website you access the API using the endpoints given in the API documentation. For example, authorisation uses endpoint http://api.safenet/auth but see Development next…

Development

Option 1: Using a Local Web Server

The official endpoints (e.g. http://api.safenet/auth) work once the website is live on the network, but not while you are working on it locally :frowning:. This is because the CSP headers inserted by the SAFE Launcher web-proxy prevent access to other domains.

As the launcher web proxy does not allow ‘localhost’ in the headers it inserts, you will need to turn CORS if in your browser. This can be done in Firefox by changing a browser setting, or toggled on and off more easily if you install the “CORS Everywhere” Firefox plugin. I don’t know about Chrome.

For local development run a local web server at the root of the app/website you are working on that serves up say http://localhost:8100 (which seems to be a standard default).

I use “ws” on linux and run it with the command ws -d ~/path/to/mysafewebsite. If you are using npm, then npm start does exactly this too. In your code you must then use that as your SAFE API endpoint, as in http://localhost:8100/auth etc. but… before you upload and publish on SAFEnetwork, change the endpoints to http://api.safenet as in http://api.safenet/auth and so on.

Option 2: Using a Local SAFE Launcher

If you clone https://github.com/maidsafe/safe_launcher/ and follow the build instructions you can have a local SAFE Launcher running. It is then possible to disable the insertion of CSP headers by the proxy as follows (but note, this doesn’t work with the binary, only when run using npm):

npm run start-dev

This invokes node ./tasks/start --proxy_unsafe_mode and if you look in safe_launcher/server/web_proxy.js you can see the “unsafeMode” flag disables lots of stuff. This won’t work with the safe_launcher binary though as I mentioned (not for me anyway!).

Here is what I know is being changed:

  • Data URI’s: loading from data URI’s is currently disabled (its the default) but being changed to allow certain safe types to be loaded such as images. Few people should hit this and it should be fixed soon, in API v.06 (see safe_launcher issue 245).

Cheeky call for tips, edits, links etc from @drunkcod @joshuef @frabrunelle @Krishna (and get over here @lightyear, @seneca and @eblanshey)!

4 Likes

define:CORS
=Cross-Origin Resource Sharing

Re: Content_Security_Policy
see also basic description at

Having been unaware of it until seeing it in SAFE, it did seem rather like magic; I still wonder how at how it’s actioned but it seems to be well intentioned and simple to work around. Also, perhaps is good practice not to have script inline.

Dealing with CSP is also new to me, here’s what I found:

  • If you get CSP error when making a API call from an uploaded safesite make sure you use the url http://api.safenet/ instead of http://localhost:8100/. This CSP rule is enforced by the launcher, you can find more details here..
  • By default making SAFE API calls from a safesite that is loaded locally from your file system (uri is file:// etc) will give a CSP error, you need to load it into the safe network.

I don’t know what is the best setup for development, updating to SAFE everytime a change is made is very tedious, I’m curious how others deal with this, use a local web server maybe?

Lol, what was that whole 6 post conversation that you guys @happybeing and @cretz deleted?

Yes, I’ve finally established this just now and am about to add it to the OP…

For local development run a local web server at the root of the app/website you are working on that serves up say http://localhost:8100 (which seems to be a standard default). I use “ws” on linux and run it with the command ws -d ~/path/to/mysafewebsite. In your code you must then use that as your SAFE API endpoint, as in http://localhost:8100/auth etc. but…

Before you upload and publish on SAFEnetwork, change the endpoint to http://api.safenet as in http://api.safenet/auth and so on.

I have just got my first RS.js demo app working live on the alpha1 network. Unfortunately it won’t work for others as I had to loosen the CSP in the web proxy (see safe_launcher issue 245 where I’ve asked @Krishna if he can let me have these during alpha while I see if we can fix this in RS.js).

@WhiteOutMashups we went a bit off topic :slight_smile:

Off topic?.. but above just reminded me of another surprise when networks switched from one test to another, local cached pages were not refreshed to the newer version. It seemed to catch a few of us out. I don’t know if that’s CSP related but to my mind is in a similar box of oddities from normal. I wonder whatever that is might lead to visitors seeing old pages not updated. A crude solution perhaps would be a long time http-equiv refresh.

Just FYI, I’m @ben here.

2 Likes

I’m trying this but still getting problem. Did you deactivate some security settings in your browser? The error I get is this:

XMLHttpRequest cannot load http://localhost:8100/auth. Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8000’ is therefore not allowed access.

The URL I use to access my webpage is http://localhost:8000/

This doesn’t solve the CSP issue because localhost is not allowed by the web proxy CSP headers.

It might be acceptable for MaidSafe to allow localhost, that’s what Dropbox do, but I haven’t asked because I don’t need it.

Instead I’ve been turning off CSP in the browser for local testing. As I mentioned elsewhere (but forgot in the OP - sorry - now fixed) , there’s a Firefox plugin that lets you toggle this easily, otherwise it requires changing a cryptic browser config setting! I haven’t done this with Chrome yet.

Ah ok, I see. @Krishna would it be fine to add localhost to the csp rules? Is it also possible to add file:// so we can run it without local server?

I’d vote against that – at least for production usage. It is quite a security whole to allow localhost things. I’d very much like to have either a toggle for this in the App or (which I prefer:) have minimal proxy-setup which alters the CSP rules for development only. This proxy could/would then also act as a file-server serving the app in development…

1 Like

I don’t really mind how it would be done but it would be very useful to have. Changing the CSP rules to allow it is easy to do and we could have it now. Maybe change the rules for now and later on change it for something else when times allow it. What is the security issue you have with allowing localhost?

For rare occasions when this is needed you might as well just clone safe_launcher and run in dev mode as in the OP. I don’t like the idea of opening up security holes to everyone running a local server - so it should at least be opt-in, and this achieves that.

EDIT: And if you want to keep the CSP and just allow localhost, you can edit your copy of safe_launcher/server/web_proxy.js

But is that really the best answer for all the new devs that will come flocking here to try their hand at the API, clone and modify the launcher? A switch for dev mode in the launcher would work. Meanwhile a change to the rules would do the trick.

Either way I still don’t understand why this is a security hole (not saying it isn’t). You need an authorization token to do anything and for this the user needs to explicitly authorize it. Your local server might become compromised and send authorization request but the user always need to accept it.

I understand there are ways around it but I also understand every single dev starting with the SAFE API will get stuck by this. It doesn’t make for a friendly dev environment and it’s especially bad if this compromise is more based on fear then on facts.

Anywyay, my two cents on the subject.

Or. If you are using webpack (and their dev-server) you can transparent-proxy /0.5 through to the launcher and all is good (as ‘self’ is listed), like so. Then you can run it against local development or even live safenet…

This is much better and emulates the final behavior of the network closest.

Would there be interest in us providing a minimal proxy-ing webpack setup for people to start their development with?

2 Likes

The problem isn’t on this side, but the other way round. There was a lengthy discussion, which lead to the CSP rules in the first place. I recommend to read up on that, but the gist is: Allowing any not *.safenet domain means potential leakage of information – like tracking tools and alike. And although the potential problem with localhost itself is small (like, the tracker would need to have either installed something on the computer or somehow route it through localhost), I’d consider whitelisting it bad practice – especially as it is only about development convenience. This is where security bugs come from: developer convenience (or why do you think all router have a super simple default password).

We should not compromise on this, considering there are clean and easy ways (as shown right before) to provide a smooth development experience without touching the good integrity of the CSP rules.

1 Like

Fair enough, I don’t really mind how it’s done, but I think it would be good to keep the amount of hoop someone needs to go through to start coding as little as possible.

And it should be done quickly, with the new API coming up and the tutorials on their way we need this ASAP.

2 Likes

I whole heartily agree!

1 Like

Under Windows 10 IE11 en Edge can’t be bothered to prevent access when doing it this way:

<!-- https://crypto.stanford.edu/cs155/lectures/11-workers-sandbox-csp.pdf -->
<!DOCTYPE html>
<html>
  <head>
    <title>Simple Safe API example</title>
  </head>
  <body>
    <iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
            src="http://localhost/simple_safe/simple_safe.html"
            style="border:0; height:300px; width:100%;">
    </iframe>
  </body>
</html>

This is “index.html”, opening it from a local webserver loads “simple_safe.html” containing @DavidMtl’s code and localhost:8100 as endpoint.

Also works from “simple_safe.html” opened as a local file if you remove his ‘localstorage’ lines.

FF and Chrome do complain. As the MS twin set should but does not.

1 Like

IE doesn’t understand default CSP (unless you do the deprecated prefix, wondering if we might want to provide that) and Edge only from version 12 – see https://content-security-policy.com/ – which version are you running?

But even then Edge only supports CSP-1.0 and the child-src (which should prevent this here) is only part of CSP-2.0 (I refer to the URL from before). I suppose we should also add the already deprecated frame-src 'self'. I’m wondering though why the default-src doesn’t catch it here.

Is there any way you, @JBishop, can confirm it blocks with that tag added?

2 Likes