8

I have a Cordova based mobile app that is hitting some API via a local server on mobile. The mobile app sets origin as Localhost. Here cors kicks in and I can't make the request. Now these API's can be used via a terminal, postman and other non-browser environments without triggering CORS.

Now in this scenario what are the risks of enabling cors on localhost? Just to clarify I want to whitelist cors for localhost in production.

  • 1
    Is your question the same as stackoverflow.com/questions/39042799/…? – Arminius Apr 6 '17 at 19:31
  • 1
    cors is not about security, it's about content ownership protection; don't expect hackers to obey the SOP – dandavis Apr 7 '17 at 5:07
  • @dandavis plz post it as an answer – aWebDeveloper Apr 7 '17 at 9:09
  • Could you be a bit more specific? What server do you want to return CORS headers, and what would they be? – Anders Nov 16 '17 at 14:25
  • the server, not my control, only whitelists requests from certain domains. so i want them to whitelist requests from my mobile app – aWebDeveloper Nov 16 '17 at 19:03
5
+25

The answer really depends on what API you created and how it works. This Site gives a very good explaination on the goods and bads of CORS. In short the author creates a fictional API that is used to send e-mails from another domain. He states:

If you are using authentication based on session cookies, you probably shouldn’t allow CORS requests by everyone. A malicious website can issue e-mail sending requests to api.yoursebsite.com via an AJAX request without the specific permission of your user.

This is (in his hypothetical case) the answer to the question "what are the risks of enabling cors"? In that case he also gives some more information about how to think of mitigation:

If the user has valid session cookies in their browser, they will be used to authenticate on api.yoursebsite.com and that would lead to unwanted e-mail sending. In most cases, dangerous requests will be “preflighted,” which means the domain needs to be approved before they can even send a request. This will prevent any malicious activities from happening.

This states (in a slightly hidden way) what dandavis already said: CORS has not much to do with security. The security is done on server side. The SOP won't be obeyed by hackers anyway.

In your case, from what I understand, you want to enable localhost as a domain via CORS so that requests can be made through some different domain? If that is correct I think that you will face no real security issue. Under the precondition that you opend some socket bound only to the loopback adress (localhost) the only way someone would be able to access that (in a malicious or in another way) would be: He already has access to the loopback adress. That means: He already gained access to the device.

Based on Conor Mancone's quite right comment: CORS primarily protects against unauthorized read requests. It is not protecting the Server from writes or triggering unauthorized actions. This has to be enforced by an authorization concept.

  • I don't believe that article is properly representing the usage and importance of CORS. The issue is that CORS is a read-only protection. Even if a CORS request is denied, it will still hit your server (with the exception of requests that must be pre-flighted). The request is still made, but if CORS blocks it, the response will simply not be returned to the calling script. As a result a URL endpoint that triggers an email will still trigger an email. CORS doesn't necessarily stop that. – Conor Mancone Nov 16 '17 at 19:21
  • Having looked over the article again, and read over your comments, it does make it clear that CORS primarily protects against unauthorized reads (not writes). It's just easy to take away the wrong idea, because the issue is subtle. – Conor Mancone Nov 16 '17 at 19:33
  • Correct. Thanks for the hint. I've just added a little text to make sure people don't take away that idea. – Ben Nov 17 '17 at 5:42
4

No, this is NOT (necessarily) safe. The other answers are mostly correct, except they are making two (common, but incorrect) assumptions: that localhost is always 127.0.0.1, and that a webserver running on your machine is one you wanted to run. THESE ARE NOT SAFE ASSUMPTIONS.

Some machines, due to either deliberate modification for some purpose or simply because the HOSTS file is minimal (or missing), do not define localhost as 127.0.0.1 (or ::1 for IPv6) and therefore do a DNS lookup for that name. DNS is of course generally not secure; an attacker on the same network (or anywhere between you and a DNS server willing to authoritatively state what IP address "localhost" maps to) can inject a DNS reply specifying their own IP address. Your app then loads the web content from the attacker's web server. The attacker can send the victim malicious web content that steals the creds to your service, steals content from your account, maliciously misuses your account, uses JS-to-native API bridges to attack your device (or at least maliciously access the data the mobile app can see), and so on.

OK, so what if you used "127.0.0.1" instead of "localhost"? IP addresses never need to go over DNS, 127.0.0.1 is always routed just to your own machine, and you should be fine, right?

Still a bad idea! TCP sockets do not respect privilege isolation between users (or between sandboxed apps). If your mobile user has one sketchy app that is running a webserver on that port, your app will connect to the malicious server instead of to the one your app tried to launch (which will have failed to bind the socket, as it's already in use). You could almost certainly get that into the app store, too; it's not using any disallowed APIs or anything, just serving web content on a loopback socket bound to a particular port (same as you are). Similarly on servers/desktops/laptops, if your machine allows non-admins to remote in (via SSH, remote desktop, etc.) then one of those users could spin up a malicious web server on the port you use, and wait for your app to connect to it.

Of course, even without any malicious attempt, this whole idea is just fragile. As I mentioned above, there's no guarantee that no other process is running a web server on the same port you've chosen. There's only 2^16 of them to choose from, and for some ranges the OS itself may randomly bind outbound connections to that port so it could be in use by a client app (like a web browser) rather than a server. Either way, the server used to offer up your web content will fail to bind the port, your app won't be able to talk to the server it expects, and your user will have a bad experience.


Note that this has nothing to do with CORS. WHATEVER origin you load the content from, your server will need to allow that origin to see web responses.

The important point is to ensure that the web content is loaded securely, and HTTP over normal TCP - that is, without TLS or other ways to authenticate and protect the connection - is not secure!


Solution: just load the content (via HTTPS) from your Internet-facing web servers. Then your app doesn't need to load anything over HTTP, your web service doesn't need to allow any requests from any web page loaded over HTTP, and the app can be sure it's loading content from the right server.

You can even serve the content from the same domain, so that cross-origin (that is, CORS) requests aren't even needed! Just use old-school XMLHttpRequests (or Fetch, without CORS) and rip out anything CORS-related from the web service.


Story time:

The previous company I worked for had a product that did something like what you're describing - loading data from a localhost web server into a webview - and we ran into a really funny problem where some people were reporting that the web view was just... empty. No content. The local server was running, the content was packaged and installed correctly, the webview was trying to make the web requests... but it seemed like the server wasn't responding. Long story short, we eventually tracked it down to "localhost" being undefined on those machines. This was only a few users out of ~10,000 (on Macs, as that was the only platform that ran our app), but it was enough of a problem that we stopped using "localhost". Of course, "127.0.0.1" turned out not to be secure either, as I explain above, but that decision was made before they had a security person on the team.

  • I think we are answering different questions. It could be that I misunderstood the OP. My presumption is that he is talking about making these changes exclusively in a development environment, for development purposes, with both the server and the application running on the local machine. It sounds like you are referring to someone doing this in an actual production environment. That is certainly a bad idea, in which case my answer would effectively be "Why in the world would you want to do that???" and I 100% agree with you. – Conor Mancone Nov 18 '17 at 14:00
  • no the server is a mobile app not on my system – aWebDeveloper Nov 18 '17 at 16:25
  • I'm going to go ahead and delete my answer. I obviously misunderstood, and my answer is not applicable here. Yours is the correct one. – Conor Mancone Nov 18 '17 at 19:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.