Skip to content

Security #36

Closed
rking opened this Issue Dec 11, 2012 · 32 comments

7 participants

@rking
rking commented Dec 11, 2012

To further adoption (and to prevent it from being really profitable to spider port 3000 looking for better_error's), what kinds of ideas can we come up with for security?

I'd be OK with a very simple layer, such as you have to type in a user-configured password (just a few chars) to open the REPL. If done right, it could be remembered by the browser and thus provide very little irritation for good users, while still thwarting simple attack spiders.

A more complete solution could go further.

http://www.youtube.com/watch?v=jZkdcYlOn5M#t=1m31s

@epitron
epitron commented Dec 11, 2012

I think a very simple and comprehensive security solution is to only show the better_errors REPL when the connecting IP is 127.0.0.1 (or the IPv6 version).

People developing locally will always see the REPL.

People trying to solve hard-to-replicate bugs in production could safely see the REPL by SSH tunneling into their production server, which would make requests appear to be coming from 127.0.0.1.

@charliesome
Owner

I'm not really convinced that extra security is necessary in better_errors.

You should generally trust the people on your local network, and if not you can always tell the server to listen on localhost only.

People trying to solve hard-to-replicate bugs in production could safely see the REPL by SSH tunneling into their production server, which would make requests appear to be coming from 127.0.0.1.

better_errors should never be installed on any production server - regardless of whether it is restricted to 127.0.0.1 or not.

@epitron
epitron commented Dec 12, 2012

What if the requests from the local network are actually proxied remote connections from a load balancer?

@charliesome
Owner

I'm not following - why would you have a load balancer sitting on your private internal network?

@epitron
epitron commented Dec 12, 2012

You're asking why it would be assigned a LAN IP address instead of an internet IP address?

Perhaps its network interface is connected to the LAN, such as in an Amazon EC2 setup.

@charliesome
Owner

Are you referring to a production environment?

@epitron
epitron commented Dec 12, 2012

Sigh.

@charliesome
Owner

I don't know why you'd expose a development instance of your app over the internet. If you're doing this then you're certainly in the minority of cases so I don't think better_errors should burden all users with security measures designed for hosts on the public internet.

@epitron
epitron commented Dec 12, 2012

This is what I was sighing about. I could see your next move.

Think about this though: what if you want to expose your development application to a client by opening port 3000 on your firewall, but don't want people to be able to root your box?

Showing the REPL to 127.0.0.1 will solve this.

What if you find a bug that exists in production but not in development?

Showing the REPL to 127.0.0.1 will solve this too. (Just create an SSH port forward to your server's localhost interface, and reload the page.)

I'm merely trying to help you anticipate security problems that people will run into.

@charliesome
Owner

what if you want to expose your development application to a client by opening port 3000 on your firewall, but don't want people to be able to root your box?

Disable better_errors

What if you find a bug that exists in production but not in development?

I don't want to hear of anyone runnings better_errors in production. There are performance, stability and security issues that make it totally unsuitable for production usage.

I don't want to lull anyone into a false sense of security by restricting the REPL to localhost either - depending on the environment, there may be middleware that rewrites the apparent remote address to X-Forwarded-For or something along those lines.

@rstacruz
Collaborator

@charliesome I will have to agree with @epitron here about restricting the REPL shell to 127.0.0.1. Here's a very dangerously-common use case:

I implemented better_errors in a project we're working in the office. At any given time, I know 2 others are working on the same project as me. I can just go to http://my-coworkers-mac.local:3000/__better_errors (default Rails port, quite a good assumption to make), log into their REPL, and type system 'say -v whisper "I see you"'.

Well... I may or may not have done this exact thing to creep my coworkers out today 😈

@rstacruz
Collaborator

If you access the error page from a remote computer, we can show a message like Tip: Go to /__better_errors on your local machine to open the REPL shell.

This is a fairly common case I can run into. I regularly run my Rails server locally and access it remotely to test in Windows/IE or an iPad. If I run into an error there, and I want to have a REPL shell, I can simply log into /__better_errors on my local machine to debug further.

@rking
rking commented Dec 12, 2012

The defailt rails s behavior is -b 0.0.0.0.

So that means that if you follow almost any tutorial anywhere, you'll end up with a server that accepts connections on port 3000 to anyone in the coffeeshop/conference/world.

The README should at least mention -b 127.0.0.1, and probably it should have a warning if that's not set.

If you agree I can write the patch.

@epitron
epitron commented Dec 12, 2012

The thing I like about the localhost security feature (with X-Forwarded-For support) is that it's a least authority security model. It removes the possibility of all kinds of known and unknown attacks by only allowing the local user to access the REPL.

If someone needs less security (for running in a VM, where the LAN is totally secure), they can disable the localhost restriction. (Of course, if you're using a VM, you can still use an SSH tunnel to connect to it from localhost.)

@charliesome charliesome reopened this Dec 12, 2012
@epitron
epitron commented Dec 19, 2012

Only showing the console if there's an error isn't really a security fix -- you can still get root on the person's machine by just causing the Rails app to throw an error (which is pretty trivial. :)

ryanf- summed it up well in #ruby-lang:

17:23 < ryanf> charliesome: I really really think you should limit better_errors to 
               localhost requests by default
17:24 < ryanf> it's one thing to have a reasonable amount of trust in the people on the 
               same network as you, and another one to offer every single one of them 
               root access to your machine
17:24 < ryanf> especially in a world where conferences, coffee shops, coworking spaces, 
               etc exist

Even if you don't want this to be default, you can still make it a configurable setting for users who need it!

@epitron
epitron commented Dec 27, 2012

You don't have to kill the whole thing if it's not localhost, just the interactive console!

@JustinAiken

Could this be made optional? I do lots of development on a remote server mounted through SSH, this change would prevent me from using better_errors...

@charliesome
Owner

@JustinAiken Can you open an issue? I'll remember to get around to it that way

@epitron
epitron commented Dec 28, 2012

@JustinAiken You can do that quite easily by doing an SSH port forward:

ssh -L3000:localhost:3000 you@server.com

You'd then connect to http://localhost:3000/ on your machine, and SSH would forward that to port 3000 on your server (and the request would appear to be coming from localhost).

Or, if your server was on port 80:

ssh -L80:localhost:80 you@server.com

Then you'd connect to http://localhost:80/

If you want to connect to http://localhost:3000/ and have it connect to port 80 on the server:

ssh -L3000:localhost:80 you@server.com

So many possibilities! :)

@anthonyalberto

+1 for making this optional ... currently can't use the REPL on my configuration (I'm running all my code in a VM and accessing it via custom /etc/hosts definition).

I can give it a try if you're willing to accept a pull request for it ...

@toobulkeh

Another +1 for making this optional or configurable. Our team develops in vagrant VMs and shares out on a local network, so requests don't come from 127.0.0.1. Even the same LAN would be a step in the right direction.

I understand the desire for this functionality, but making it optional would be nice!

@rking
rking commented Feb 14, 2013

ssh. port. forward.

@toobulkeh

I do not want to have to ssh port forward each time I am developing. That is NOT a proper solution. I honestly don't care if my application is secure in development or not. It's development.

@anthonyalberto

Yeah easy ... +1 again to implement a conf of some sort :)

@rking
rking commented Feb 14, 2013

I'm OK with a config option as long as it's:

BetterErrors.i_am_far_too_lazy_to_do_this_right_and_if_i_am_writing_code_at_a_coffee_shop_everyone_can_pwn_me_kk!
@rking
rking commented Feb 14, 2013

Your vagrant setup can easily, automatically port-forward so that requests appear to be 127.0.0.1

@toobulkeh

rking: yes, if someone is trying to pwn me in a coffee shop, then that's fine. Now past you being rude about this issue, SSH port forwarding should NOT be a requirement of a basic feature like this.

I am using port forwarding on my Vagrant VM - http://docs.vagrantup.com/v1/docs/config/vm/forward_port.html - but the requests still come in as an address other than the LOOPBACK address. Hardcoding any IP address is a bad idea.

@rstacruz
Collaborator
@toobulkeh

Yes, restricting unsecure features (or just having a config option to turn it off) would be ideal.

What concerns would REPL shell restriction NOT mitigate? Are variables from binding_of_caller that concerning?

I'm still baffled why there is so much concern over security of a development machine. Are you guys developing at DEFcon or something?

@epitron
epitron commented Feb 14, 2013

Is there documentation for this whole situation? Whether or not there's a configuration option, there should be something in the README that explains to SSH port forward, or enable a config option.

@toobulkeh

@epitron agreed. I looked into how port forwarding works in Vagrant and why my requests aren't coming in as 127.0.0.1 (or the address of the VM at all). https://github.com/mitchellh/vagrant/blob/master/plugins/providers/virtualbox/action/forward_ports.rb was about as far as I got.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.