59

When I'm developing a webapp, let's say a Django site, I run it locally and typically access it at http://localhost.

I thought this was inherently secure because I assumed that localhost can only be accessed locally. However, I discovered that even running a local web server (Apache, Nginx...) with a self-signed HTTPS certificate won't help because localhost is not really required to be local:

In empirical testing, we've seen multiple resolvers... send localhost queries to the network... As a result accessing "https://localhost", say, on a hostile WiFi access point (such as your coffee shops) can be intercepted by a network attacker and redirected to a site (or a certificate) of their choosing. (In email chain "Exception to Baseline Requirements, section 7.1.4.2.1".)

If I'm developing a webapp, I need to run it locally and access it through a browser. Sometimes I need to do this at a coffee shop with an internet connection. What access point should I use, if not localhost?

Note

Some of my desktop applications also expose themselves via HTTP at other ports, for example http://localhost:9000. Presumably I shouldn't access those at a coffee shop either?

11
  • 8
    You could potentially run a virtual machine with a network shared only with the host computer - you'd need to access your application by IP address (or set up a hosts file to enable name based access), but it wouldn't expose the code to any third party computer, assuming the VM network config is correct.
    – Matthew
    Commented May 17, 2017 at 12:51
  • 4
    To clarify, are you concerned that others poison a possible DNS query to localhost and intercept your connection or are you concerned that others on your wifi access your local server by themselves?
    – Arminius
    Commented May 17, 2017 at 12:54
  • 26
    Assuming that localhost is written in your hosts file, which it probably is, you wont have a problem.
    – mcfedr
    Commented May 17, 2017 at 14:47
  • 10
    Don't all common platforms locally resolve "localhost" to 127.0.0.1 or ::1 by default? How would someone be vulnerable?
    – Macil
    Commented May 17, 2017 at 18:16
  • 9
    A slightly different issue, but you need to make sure that your webserver only listens on 127.0.0.1 and not 0.0.0.0, otherwise it's publicly accessible. Commented May 18, 2017 at 8:20

8 Answers 8

74

Safely developing against localhost can be done provided:

  • your machine is configured to resolve localhost to a loopback address (note, it's possible to change your hosts file to resolve localhost to a different address)
  • your machine is configured to route the loopback address via the loopback interface (it's possible to route loopback addresses to non loopback interface)
  • you configure your application to listen on the loopback address, not 0.0.0.0 (many web frameworks listens on 0.0.0.0 by default, this is probably the most common reason for unexpectedly exposing services to untrusted network during development)
  • if you use a proxy, your browser is configured not to route localhost/loopback through the proxy

In other words, a fairly typical networking configuration.

Also, take care that your database server aren't binding to 0.0.0.0, as that'll allow anyone on the network to connect directly to the database server. It's probably best to set a firewall configuration so you know exactly what ports and addresses that local services are listening on.

The link you pointed is under the context of a publicly trusted CA issuing certificates with "localhost" name. This is unsafe under that context because the recipient of such certificate may use the certificate to intercept the communication of someone with some unusual networking configurations. When you have full control over your own machine's configuration and you know that you don't have some weird configurations on your machines, the loopback interface is safe.

6
  • 13
    While typical, this is probably not the default. It might be worth OP's time to bring another machine and try to access his app in ways he doesn't want people to. Testing - it's pretty cool.
    – corsiKa
    Commented May 17, 2017 at 17:55
  • For the proxy part, make sure your system isn't configured to automatically discover proxy settings, as those give a proxy configuration script back that can allow people to change localhost
    – Ferrybig
    Commented May 17, 2017 at 20:37
  • @LieRyan could you clarify in your answer if this means that http is good enough, including for desktop apps that have a web interface at localhost, or if https is required/preferred, thanks!
    – lofidevops
    Commented May 18, 2017 at 9:32
  • 1
    @d3vid: assuming the typical networking configuration and that your machine isn't already compromised, https for localhost service is wholly superfluous. Though, as raised by Oli in another answer, https://localhost may be the most straightforward way to force HTTPS for scheme-relative links (links that starts with //) to external resources, but you might as well just link external resources directly to the HTTPS version instead.
    – Lie Ryan
    Commented May 18, 2017 at 14:55
  • 5
    The most critical advice here is the binding to loopback only, because that's the most commonly violated item here and the one most unexpected versus developing behind a consumer-grade NAT firewall.
    – Riking
    Commented May 20, 2017 at 6:19
33

First, you could use http://127.0.0.1 to bypass the DNS lookup.

Secondly, you can create your own self-signed CA certificate, create a certificate for localhost and connect to https://localhost securely. There is no way an attacker can intercept that connection.

As a result, accessing "https://localhost", say, on a hostile WiFi access point (such as your coffee shops) can be intercepted by a network attacker and redirected to a site (or a certificate) of their choosing.

This is true in the context of the email thread. The email thread is about whether someone could obtain a valid certificate for localhost from a trusted CA. If this were possible, then yes, someone else could impersonate https://localhost. But a public CA is not permitted to issue certificates for localhost (Baseline Requirements, section 7.1.4.2.1; see also this discussion on the Let's Encrypt tracker).

Because this is not possible, your own private CA is the only one that you trust that issued a localhost certificate.

7
  • 8
    Navigating to localhost doesn't perform a DNS lookup; it's returned by the machine's hosts file.
    – user134828
    Commented May 17, 2017 at 21:52
  • 5
    @JeremiahMegel: At least on Linux, that is configurable (via /etc/nsswitch.conf). However, all Linux distributions I know ship a configuration that works like you describe.
    – sleske
    Commented May 18, 2017 at 20:13
  • 4
    Note that valid certificates for localhost have been seen in the wild.
    – Siguza
    Commented May 19, 2017 at 15:34
  • 2
    @JeremiahMegel: That is neither universally true of HOSTS files, nor is it universally true that all machines have a HOSTS file. Strange though those claims might sound, do commercial software development (that uses localhost, in our case) for a while and you'll see some really weird OS configurations.
    – CBHacking
    Commented May 19, 2017 at 22:33
  • 2
    For a long while now, MS Windows by default will use DNS to lookup localhost.
    – rjt
    Commented May 21, 2017 at 5:59
8

If you're doing this type of stuff often, why not just get a travel router?

With a small travel router, you can set up your own internal network with its own SSID, add encryption, and set up a customized whitelist so only your MAC addresses are allowed on it.

4
  • If you're talking wifi, I'm pretty sure that's snoop- and spoofable.
    – Rob Grant
    Commented May 19, 2017 at 12:29
  • 1
    @RobertGrant That depends on the encryption used. The details are well beyond the scope of a comment, but WPA2-PSK with a secure (complex) key should be secure enough for this use. However, this solution seems more cumbersome than software-based solutions.
    – StockB
    Commented May 19, 2017 at 14:46
  • It is somewhat more complicated than using software, but it also has the potential to be more secure by default. If d3vid is only using his laptop, he can just connect it via ethernet as well. It only gets more complex if you want to establish your own wifi network.
    – Dan Smith
    Commented May 19, 2017 at 17:14
  • @DanSmith agreed - if you're talking wired then it's more secure. As long as you have a padlock on the router :-)
    – Rob Grant
    Commented May 22, 2017 at 11:22
5

If you develop in Docker, then when you start your web app (in a Docker container), the container will have its own IP address that may not be accessible from the outside. You would access it with a special IP, that only you can see, as assigned by Docker - e.g. http://172.17.0.2:9000.

Whether your web app is also accessible on your host's physical network interface depends on how you start the container. For example, the docker run command won't bind to the host interface unless you use the -p, -P, or --expose options.

Other benefits:

  • The app is otherwise isolated from your host system.
  • Deployment to other systems is more reproducible.
1
  • I prefer to run the browser in docker as well. Everything can (and should) be dockerized.
    – emory
    Commented May 18, 2017 at 13:41
5

There probably isn't a viable MITM attack here. Assuming Ubuntu and Django, there are two big factors that conspire against an attacker:

  • Ubuntu's default hosts and dns configuration will resolve localhost using a hardcoded setting. It won't even perform a DNS query. You can change this... But don't instead :)

  • Django binds to 127.0.0.1:8000 by default. To fully MitM you, the attacker would need to intercept the traffic being served by Django but they don't have access.

That said, web security is complicated. There might be things you're doing that an attacker could exploit to have some sort of an effect on you.

External resources have to be secure

Many of us embed third-party, CDN-hosted files. Jquery, Bootstrap, etc. If these are http:// or // (remember the dev server doesn't use TLS), that could give an attacker an opportunity to MITM those files and inject live script into your pages.

For the sake of local development away from an internet connection, it may be best on all counts to just host all the stuff yourself.

Click-jacking and iframe techniques

Just because they can't access your local-running server, doesn't mean they couldn't tell your browser to access it. Cross origin security will (probably) stop them doing things with it directly but they could stick it in an iframe. This is sort of a reverse-clickjack.

To the user this would just look like your website. They could even capture all URLs at their end and feed them through to the frame. If it were a public website they could also work out what you were clicking.

But of course you're already using django-secure, aren't you? I'd recommend it. One setting and you'll start sending out X-Frame-Options: DENY headers with every Django request. Alternatively there is a Django-builtin option that does the same. I recommend django-secure because it does a lot more.

Your security on a hostile network is more than a web server

You probably have other daemons running, well beside things like PostgreSQL that you're using for development. You might be running SSH servers, filesharing servers, etc and if you're used to a home environment, you may have skipped leg day gone with weaker security for convenience.

The easiest single thing to do is block all incoming traffic. Assuming you have no existing UFW configuration, that's as simple as:

sudo ufw enable
sudo ufw default deny incoming
sudo ufw default allow outgoing

That will persist reboots. If you get home and want to access something, you can either turn it off with sudo ufw disable or change the default and open certain ports explicitly.

If you are going to leave a SSH port exposed, I have written an article on hardening SSH configurations. Unless you're in the NSA canteen, that should keep most people out of your system.

1
  • great tips (and thanks for the Ubuntu confirmation)
    – lofidevops
    Commented May 18, 2017 at 13:43
2

The problem that forum is describing is actually the opposite one from what you are worried about. You are worried someone else on the network will be able to see what is being served on localhost. That problem is you trying to see what's being served on localhost and instead being served a malicious web page by someone else on the network.

That problem is actually not that hard to set up. I've had it happen by accident here at work. We make network equipment and software, so there are a lot of people with various levels of experience putting machines in various states of experimentation on the network. Someone accidentally set 'localhost' as their hostname, it got registered in Active Directory, and served up to everyone in DNS.

At a coffee shop, that wouldn't be that difficult to notice, because your webapp would suddenly be some other page instead. If you're using a TLS certificate, it wouldn't have a valid certificate.

If you're worried about your webapp details leaking, just block the relevant incoming ports on your external firewall. On linux, you would do something like this:

/sbin/iptables -A INPUT -o eth0 -p tcp --dport 80 -j DROP
1

Access your site with http(s)://127.0.0.1/, configure your app to listen to 127.0.0.1 only and you are safe. Encryption is not necessary as there is no possibility for someone outside to listen: nothing goes outside of your computer, your app on your computer "talk" with your browser on your computer via an address witch cannot be used outside of your computer.

0

You could code, host and run in your browser in the cloud over https using Cloud9 ide, a GitHub repo and Heroku. Unless a keylogger is installed or somebody is looking at your screen, nobody in that room can detect what you are doing.

You must log in to answer this question.

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