btcsuite / btcd

An alternative full node bitcoin implementation written in Go (golang)
https://github.com/btcsuite/btcd/blob/master/README.md
ISC License
6.16k stars 2.34k forks source link

What are the reasons for encouraging/requiring use of TLS/authentication for RPC? #451

Closed adamkrellenstein closed 9 years ago

adamkrellenstein commented 9 years ago

When are the data transmitted over RPC actually private? Doesn't btcd really only handle publicly available data, given that it has no wallet functionality? I imagine that there are cases where it's somewhat advantageous to mask the content of transaction broadcasts, to avoid linking identities with Bitcoin addresses, but I don't see how that justifies forcing client applications to use TLS whenever they're not on the same machine (and indeed sometimes when they are in the same machine, but just in two different Docker containers or virtual machines, for example).

Moreover, why even handle TLS yourselves at all, instead of outsourcing that functionality to a dedicated tool like stunnel?

Similarly, why require any authentication? If all you're doing is reading from btcd's API, esp. on localhost, it's often just a configuration headache.

dajohi commented 9 years ago

I connect btcwallet over the internet to btcd. I want that using TLS. Stripping builtin TLS out and using stunnel sounds like a configuration headache, and people won't use it.

I also want authentication so I can disable certain users, limit the commands they can use, etc.

If you want, you can run btcd with the --notls option to disable TLS on localhost.

What issues are you having?

adamkrellenstein commented 9 years ago

There are plenty of circumstances in which people will use btcd without any wallet. Why should TLS be on by default? Why should it be impossible to disable for any host except localhost?

EDIT: Maybe leave it on by default for btcwallet only?

stunnel is very easy to use and widely deployed. IMO if you can get rid of all of that code and configuration because there already exists a good implementation you can piggy-back on, you should do it.

Likewise, I'm not saying you should get rid of authentication, but rather that it shouldn't be required.

dajohi commented 9 years ago

We require TLS for non-localhost connections because consider we share the same ideals as projects like HTTPS-Everywhere; all traffic should be encrypted. If it leaves your machine, assume it will be sniffed. getrawtransaction retrieves public info, but without TLS, you also leak that you are interested in that particular transaction.

stunnel is a third party tool that requires its own configuration, testing, updating, etc. We already have a good TLS implementation which works, has test coverage, etc.

We want to make the default configuration secure without requiring the user to make it that way. If we remove all the security, no one will ever set it up.

I personally cannot think of a reason to disable authentication. I do not want my btcd shutdown or dos'd with heavy IO rpc commands unauthenticated.

What issues are you having?

adamkrellenstein commented 9 years ago

You're not leaking any information if you are accessing btcd over a private LAN, but btcd forces you to use TLS there anyway. I should be able to turn off TLS when I know my traffic cannot be intercepted, or if I just don't care if it is.

You shouldn't do TLS at all if you don't have to.

The default configuration I'm proposing isn't "insecure", and btcd is not used primarily by clueless users. When you ship a GUI, you can dumb that down, but for developers working with btcd it's obvious when authentication needs to be set up. Right now, it is even impossible to disable authentication, even for use cases where none is clearly necessary (yes, there are many).

My only issue is that btcd is a much bigger pain to deploy than it should be. It doesn't sound as though there are any good reasons to have such draconian configuration defaults and requirements... just "Why not?".

adamkrellenstein commented 9 years ago

There are two issues here: defaults and requirements. It's one thing to err on the side of security (even when it's superfluous in the majority of use cases). But it's quite another to have the user jump through hoops because you think you know how to secure his system better than he does in every case.

Can we have a --noauth flag that disables authentication for those that don't need it? Can we allow --notls for (apparently!) non-local connections?

dajohi commented 9 years ago

Can you describe the hoops that the user is needing to jump through? What is the user trying to achieve?

dajohi commented 9 years ago

Are you able to test diffs?

adamkrellenstein commented 9 years ago

The steps are roughly these: 1) Picking a username (What percentage of these are just 'rpc'?) 2) Generating a passphrase (What percentage of these are just 'foobar'?) 3) Finding the btcd configuration file 4) Setting the passphrase and username in the configuration file 5) Distributing passphrase and username to all clients (and dealing with their configuration files) 6) Enabling SSL in the client applications (which is always off by default, if it's even supported) 7) Either distributing the certificate and getting the clients to find it, or just disabling certificate verification (what we do every time)

If you're debugging a ConnectionRefused error, that's a lot that has to be perfect before you begin to worry about port numbers, --rpclisten, firewalls, Docker links, etc.

Compare that to just running, $ btcd --notls --noauth and having anything on localhost (only! rpclisten is restricted by default) be able connect immediately.

And whenever you switch back to using Bitcoin Core, you disable SSL and certificate validation again (it's is off by default in Bitcoin Core). You can't simultaneously support both SSL and non-SSL connections.

Yes, I can test diffs.

dajohi commented 9 years ago

Give btcd a spin with --notls and --norpcauth, or notls=1 and norpcauth=1 in your btcd.conf.

adamkrellenstein commented 9 years ago

Thanks, will do.

davecgh commented 9 years ago

While I agree that some type of unauthenticated (probably REST-based) query interface has some merit (even though it generally leaks privacy info, yes even on a private LAN), the issue is that RPC is both a query interface and a control interface. It's the latter that is the issue when it comes to relaxing authentication (and consequently TLS).

Relying solely on being on a private LAN to protect access to control ports is really just not good security. There are a myriad of ways bad things can happen with such a setup. For an extremely simple example, without TLS/auth all it would take is one rogue app anywhere on the private network (that doesn't even need root access I might add) to discover every btcd instance on the network, control their IP connections to instruct them to only connect to nodes the attacker controls, which can then serve up an invalid chain which appears perfectly valid according to all of the malicious peers, and cause all manner of havoc.

adamkrellenstein commented 9 years ago

The question isn't whether or not it's okay to rely solely on being on a private LAN for security; the question is whether developers using btcd should themselves be trusted to make the judgement as to when authentication is necessary and when it is gratuitous. Having btcd listen only to 127.0.0.1 by default suffices to prevent accidental occurrence of the kind of eventuality you describe.

You can't draw reliable conclusions about the insecurity of a network from the IP addresses involved (c.f. multiple Docker containers on a single host machine).

davecgh commented 9 years ago

Most developers and users, while they are certainly very intelligent people, are not security experts, nor should we expect them to be.

It's human nature to take the path of least resistance. Your breakdown above shows that it takes ever so slightly more effort to set things up with authentication and TLS (read properly and securely), but it is a bit more effort nonetheless. So, looking at it from a completely unbiased viewpoint, what do you think is the most likely outcome of the following two scenarios?

1) User/Developer needs to learn about and perform all the steps you listed above 2) User/Developer notices oh, cool, if I just use --nowhatever I can avoid all of that, and hey I'm on my own network anyway, so I'm "secure"

I can pretty much guarantee you that the vast majority of people will pick the second option regardless of whether they understand the implications. This very scenario has played out time and time again with countless software. I'd even be willing to bet that most of the Bitcoin setups out there using other software are insecure primarily due to this.

FWIW, I'm not oblivious to the arguments here, but I just don't think it's a good idea to essentially give developers/users a loaded gun pointed at their head with a choice between an easy to press button that will fire the gun, and a keyhole the requires a key they need to go find which will disarm the gun (and no sign saying which does what). In effect, many, many people would just push the button and unwittingly shoot themselves since it requires less effort.

adamkrellenstein commented 9 years ago

Those aren't the only two scenarios. Those aren't even two particularly likely scenarios...

Giving users the option to turn off a security feature has nothing in common with giving someone a loaded gun pointed at his head.

davecgh commented 9 years ago

I was mulling over this a bit and I think I might have a compromise which addresses the concerns of both sides.

The main sticking point is, as previously mentioned, we don't want to provide unauthenticated access to the control commands of the RPC interface. Also previously mentioned is that I believe an unauthenticated query interface has merit. Well, recently there was functionality added by @aakselrod which provides a limited RPC user which only allows access to the query commands.

So, what I propose is that if a --noauth option is provided, it is treated the same as the limited user. In other words, only the query interface is exposed. This would provide the unauthenticated query interface that I believe is what the main intent here is while preventing unauthenticated access to control commands.

With this proposal, the combination of the --noauth and --notls commands would disable the requirement for TLS on !localhost. However, --notls without --noauth would retain the current functionality to prevent the plaintext credentials being sent across the network (virtual or not).

Would that address your concerns?

EDIT: I personally still think it's a better idea to just take a few extra minutes to setup auth and TLS so you have an additional layer of protection when the next sysadmin comes in and changes things on the network and/or containers, some new vulnerability is found in the network layer/interface, something that has been overlooked in the setup is found, or any other number of things that can and do happen in production setups. However, I'm not unsympathetic to the desire for an unauthenticated query interface.

adamkrellenstein commented 9 years ago

As far as I'm concerned, you can't force people to implement secure authentication, even if authentication [for control interfaces] is always turned on: the user and password can always be trivial. Therefore you shouldn't try. Especially when it's sometimes definitely not necessary.

Of course, your proposal would be better than nothing.

adamkrellenstein commented 9 years ago

Also, a client accessing btcd from localhost without authentication should definitely be able to access the control interface.

alexlyp commented 9 years ago

A client connecting to the control without auth seems like a horrible idea.

I mean no-tls is one thing, arguably overkill. But noauth to directly access the node is a disaster waiting to happen.

jcvernaleo commented 9 years ago

I've mostly kept quiet on this, but I don't see a use case where a client on localhost would need to access controls without auth. In the localhost situation it is even easier than other situations to setup the 'client' with the auth info (you don't even need puppet or any config management) to get it working.

jcvernaleo commented 9 years ago

As for bad usernames/passwords, sure, users will do all sorts of things like that, but that doesn't mean that we should default to lower security to cater to those users. Ignoring emacs and a few other pathological cases (and I say that as an emacs user), most users will stick with the defaults for most programs which is why defaulting to as secure as you can is always a good idea.

jrick commented 9 years ago

One other point I don't believe has been brought up yet is that if you disable the requirement for any kind of user/pass authentication (even if it's just a silly or short password because security isn't actually necessary, I do this for development), now every client that accesses the server needs a way to disable the authentication on the client side. For graphical programs, this would mean adding another prompt for whether auth is truly necessary or not, and for command line clients like btcctl we would need to add another option (non-default mind you) to ignore the rpcuser and rpcpass options. As a whole, this would introduce more complexity into the whole environment than just using an intentionally insecure passphrase.

arnuschky commented 9 years ago

@adamkrellenstein, I don't quite follow the logic of "most users will chose bad passwords so let's remove auth altogether". Just because some use-cases might be insecure, one should not make all cases insecure (or the default, for that matter).

Regarding local control: Having a non-authenticated control interface is always a bad idea, also on localhost (eg, in multi-user environments).

I certainly vote for keeping strong default security. Configuration pain isn't that big IMHO, but many other projects show that it can be solved with tutorials, an auto-setup script, or built-in functionality. Similarly, I definitely vote against outsourcing TLS to stunnel. If the default behavior should be encryption over the network, I see no reason why by default one should be required to use another software. And yes, we use encryption even over internal networks.

davecgh commented 9 years ago

I think it's pretty unanimous that disabling auth altogether (for control purposes) is not a good idea. Just because a user can still use trivial usernames and passwords doesn't mean you shouldn't even try to encourage users into using more secure setups.

Disabling security is always a slippery slope. This is why I personally have been so adamant about not introducing options which intentionally reduce security. Supporting options such as this invariably lead to users that don't understand the implications of making use of them. A weak username/passphrase is still slightly better than leaving it wide open.

What's even worse, in my opinion, is it wouldn't even really save all that much (if any) time in configuration. Let's assume for a moment, that such options are added. The setup steps would then roughly be:

  1. Finding the btcd configuration file
  2. Setting the notls option in the configuration file
  3. Setting the noauth option in the configuration file
  4. Find the configuration file of each client
  5. Configuring each client to not use auth
  6. Potentially configuring each client to not use TLS (since most clients are unfortunately insecure by default, this step probably won't be required for most)

So, even if we discount the 6th step for most clients, there really is very little difference in the number of steps that need to be performed to configure it securely.

Additionally, we could even help mitigate the weak username/password argument by generating them for the user. There is another issue, #120, which discusses such automatic configuration. This would turn the first 2 steps in the original list to a single step of locating the configuration file and obtaining the username/passphrase to use for the clients. That would result in the same number of overall steps.

If configuration is really that much of a pain, we should work to provide better documentation and/or tools to help ease the process rather than punting and just providing an off button.

adamkrellenstein commented 9 years ago

People here are arguing against a ridiculous strawman. I am not proposing "removing auth altogether", or "[not even trying] to encourage users into using more secure setups" or "[not using encryption] even over internal networks" or "[defaulting] to lower security" (except w.r.t. outsourcing SSL to stunnel).

There are use-cases where TLS and authentication are each superfluous. There should be options to disable them. End of story.

adamkrellenstein commented 9 years ago

Bitcoin Core is now dropping support for SSL: see https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-71181146 and subsequent comments.

davecgh commented 9 years ago

As long as the authentication mechanism for RPC is a plain-text username/password, we won't be dropping the requirement for SSL over remote RPC. If a secure authentication mechanism that doesn't require SSL is implemented, then there would be much less issue with dropping it.

Anyone who really wants to make this change is free to do so and maintain it themselves (@dajohi even provided a commit to do so), but our team has unanimously agreed that we won't accept it or support it so I'm going to close this issue.

In regards to the arguments from BC, I wouldn't lend much credence to it since, frankly, BC is not a shining example of good design in regards to the RPC interface. It is a control interface that is unprotected by default, their existing SSL support is poor (see the second point in the post you linked which even calls this out), the entire API is largely inconsistent (unfortunately this applies to btcd too since it's compatible), and has several other issues related to it (there is a reason the REST interface was developed).

To address the specific points there though:

We understand not everyone will agree with our decision and/or viewpoints. That is the beauty of open source however, as those who disagree are free to maintain their own modifications.

l0k18 commented 5 years ago

Pardon the necrobump, but I am writing a fork of btcd, and for me, the way btcsuite apps deal witht TLS and certificates is ENTIRELY unsatisfactory. Not only is it a monumental pain to get the CA and 'trust' checks to work, nobody in probably the whole world bothers to encrypt traffic over any network link that is physically isolated from intrusion, and implausible to tap without physical breach.

As such, I flipped the sense of the TLS toggle to default disabled, removed the 'you can only use localhost' tests/nags/obstructions and let the user decide, and default configuration does not use it.

In my opinion the better solution is to give the option of OTR encryption instead, which is ad-hoc and does not require the public keys to bear a signature from a trusted third party. Really, the security model of SSL/TLS is for centralised services where MITM attacks are more likely and profitable. Peer to peer systems nobody trusts anybody anyway, so it seems absurd to use this trust mechanism, at least in the way SSL/TLS does it.

Consider how bitcoin full nodes identify each other. The server's 'nonce' could easily be substituted with an EC key and with DH PFS to establish the shared symmetric encryption. Then you could add an RPC call or configuration (or both), to determine which connections the node will accept.

For people running full nodes with public IP addresses, it would be simple to add an ACME protocol verification from letsencrypt, inside the btcd and btcwallet, and you could even make it so one certificate covers several nodes IP/DNS addresses.

I am adding all of these features in the near future, because security is important, especially when a wallet is involved, and the cognitive burden of dealing with TLS trust model especially for LAN and VPNs (like zerotier, for example), where there is already one layer of encryption...

And because, as many have pointed out, the majority of TLS/SSL implementations in the crypto-sphere are really quite broken and difficult, it makes absolutely no sense to make TLS default and not give one little bit of help with the 'bad certificate' problem.

I don't understand at all how anyone could not be having issues with this. TLS enabled on localhost and private address ranges is, quite frankly, silly. In fact, the simplest way to make this not so damned irritating, would be to actually allow all non-routeable addresses to listen without TLS.