24

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.

5
  • 1
    Is your question the same as stackoverflow.com/questions/39042799/…?
    – Arminius
    Commented Apr 6, 2017 at 19:31
  • 1
    cors is not about security, it's about content ownership protection; don't expect hackers to obey the SOP
    – dandavis
    Commented Apr 7, 2017 at 5:07
  • @dandavis plz post it as an answer Commented Apr 7, 2017 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
    Commented Nov 16, 2017 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 Commented Nov 16, 2017 at 19:03

2 Answers 2

16
+25

The answer really depends on what API you created and how it works. This site gives a very good explanation 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 opened some socket bound only to the loopback address (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 address. 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.

3
  • 1
    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. Commented Nov 16, 2017 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. Commented Nov 16, 2017 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
    Commented Nov 17, 2017 at 5:42
5

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.

3
  • 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. Commented Nov 18, 2017 at 14:00
  • no the server is a mobile app not on my system Commented Nov 18, 2017 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. Commented Nov 18, 2017 at 19:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .