Bitcoin Forum
December 08, 2016, 07:56:40 AM *
News: Latest stable version of Bitcoin Core: 0.13.1  [Torrent].
 
   Home   Help Search Donate Login Register  
Pages: [1]
  Print  
Author Topic: HTTPS support for bitcoin JSON-RPC  (Read 7153 times)
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652


Chief Scientist


View Profile WWW
September 01, 2010, 10:06:42 PM
 #1

But, use of HTTP-Basic is just a crime, because it is so trivial to obtain the shared secret.  If HTTP-Basic is to be kept, at least require SSL connections?
It isn't trivial to obtain the secret unless you patch the code to bind to interfaces other than loopback....

SSL connections are The Right Answer.

If I had any OpenSSL programming experience I'd volunteer to implement it.  Anybody willing and able to teach bitcoin to speak https?

And for extra credit, support SSL client certificates for authentication either instead of or in addition to HTTP-Basic...

How often do you get the chance to work on a potentially world-changing project?
1481183800
Hero Member
*
Offline Offline

Posts: 1481183800

View Profile Personal Message (Offline)

Ignore
1481183800
Reply with quote  #2

1481183800
Report to moderator
1481183800
Hero Member
*
Offline Offline

Posts: 1481183800

View Profile Personal Message (Offline)

Ignore
1481183800
Reply with quote  #2

1481183800
Report to moderator
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
1481183800
Hero Member
*
Offline Offline

Posts: 1481183800

View Profile Personal Message (Offline)

Ignore
1481183800
Reply with quote  #2

1481183800
Report to moderator
1481183800
Hero Member
*
Offline Offline

Posts: 1481183800

View Profile Personal Message (Offline)

Ignore
1481183800
Reply with quote  #2

1481183800
Report to moderator
1481183800
Hero Member
*
Offline Offline

Posts: 1481183800

View Profile Personal Message (Offline)

Ignore
1481183800
Reply with quote  #2

1481183800
Report to moderator
aceat64
Full Member
***
Offline Offline

Activity: 127



View Profile
September 02, 2010, 01:32:05 AM
 #2

But, use of HTTP-Basic is just a crime, because it is so trivial to obtain the shared secret.  If HTTP-Basic is to be kept, at least require SSL connections?
It isn't trivial to obtain the secret unless you patch the code to bind to interfaces other than loopback....

SSL connections are The Right Answer.

If I had any OpenSSL programming experience I'd volunteer to implement it.  Anybody willing and able to teach bitcoin to speak https?

And for extra credit, support SSL client certificates for authentication either instead of or in addition to HTTP-Basic...


For anyone looking for a quick hack, if you run a webserver on the same server as Bitcoin you could use the relay.php script I threw together. Then you can access the JSON-RPC interface over HTTPS, the relay simply passes commands it receives to the Bitcoin server on the loopback interface.

jgarzik
Legendary
*
qt
Offline Offline

Activity: 1470


View Profile
September 02, 2010, 06:09:31 AM
 #3

SSL connections are The Right Answer.

If I had any OpenSSL programming experience I'd volunteer to implement it.  Anybody willing and able to teach bitcoin to speak https?

And for extra credit, support SSL client certificates for authentication either instead of or in addition to HTTP-Basic...

SSL is easy in C.  C++, satoshi-style, is another matter Smiley  boost has some stuff: http://live.boost.org/doc/libs/1_37_0/doc/html/boost_asio/overview/ssl.html

Jeff Garzik, bitcoin core dev team and BitPay engineer; opinions are my own, not my employer.
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652


Chief Scientist


View Profile WWW
September 03, 2010, 11:41:13 PM
 #4

Nobody volunteered, but the boost ssl LOOKS like it will make it easy... so I've started playing around with it.

After much wrestling with the (sucky) OpenSSL and boost::asio::ssl docs, I've got a standalone, dumb, Satoshi-style-c++ https server running (code below).

Are there any real OpenSSL experts here who can review the code and answer questions like:

 + I understand the temp Diffie-Hellman file contains large prime numbers used to do public key exchange.  Everything works just fine if I leave out the call to context.use_tmp_dh_file; what are the security implications?  Will it matter for what we'll be doing (securing the JSON-RPC channel from eavesdropping/man-in-the-middle attacks)?

 + I'm following the advice from here, excluding old, low-security ciphers using:
    SSL_CTX_set_cipher_list(context.impl(), "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH");
    Am I correct in assuming that any sane JSON-RPC/HTTP/HTTPS library will support the higher-strength ciphers?  Or does Java on a PC do something braindead and support only DES-MD5?  (and yeah, I'll make this overridable via a config file param, but I want to get the defaults right)

+ Oh, and a C++ expert question:  what magic incantation will turn the boost::asio::ssl::stream into an iostream that understands << and >> ?

And thumbnail sketch of how I imagine this working with bitcoin:

+ config file setting to turn on ssl/tls rpc  ( maybe rpcssl=true ... or should it be rpctls=true ? )
+ if turned on, only ssl connections accepted on the rpcport
+ if turned on, bitcoin binds rpcport to all addresses (not just 127.0.0.1)

Code:
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <sstream>
#include <string>

using namespace std;
using namespace boost;
using boost::asio::ip::tcp;

typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_stream;

string HTTPReply(int, const string&);

int main()
{
    // Bind to loopback 127.0.0.1 so the socket can only be accessed locally                                           
    boost::asio::io_service io_service;
    tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), 1111);
    tcp::acceptor acceptor(io_service, endpoint);

    boost::asio::ssl::context context(io_service, boost::asio::ssl::context::sslv23);
    context.set_options(
        boost::asio::ssl::context::default_workarounds
        | boost::asio::ssl::context::no_sslv2);
    context.use_certificate_chain_file("server.cert");
    context.use_private_key_file("server.pem", boost::asio::ssl::context::pem);
    context.use_tmp_dh_file("dh512.pem");
    SSL_CTX_set_cipher_list(context.impl(), "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH");

    for (;;)
    {
        // Accept connection                                                                                           
        ssl_stream stream(io_service, context);
        tcp::endpoint peer_endpoint;
        acceptor.accept(stream.lowest_layer(), peer_endpoint);
        boost::system::error_code ec;
        stream.handshake(boost::asio::ssl::stream_base::server, ec);

        if (!ec) {
            boost::asio::write(stream, boost::asio::buffer(HTTPReply(200, "Okely-Dokely\n")));
        }
    }
}

string HTTPReply(int nStatus, const string& strMsg)
{
    if (nStatus == 401)
        return "HTTP/1.0 401 Authorization Required\r\n"
            "Server: HTTPd/1.0\r\n"
            "Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n"
            "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
            "Content-Type: text/html\r\n"
            "Content-Length: 311\r\n"
            "\r\n"
            "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
            "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
            "<HTML>\r\n"
            "<HEAD>\r\n"
            "<TITLE>Error</TITLE>\r\n"
            "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
            "</HEAD>\r\n"
            "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
            "</HTML>\r\n";
    string strStatus;
    if (nStatus == 200) strStatus = "OK";
    else if (nStatus == 400) strStatus = "Bad Request";
    else if (nStatus == 404) strStatus = "Not Found";
    else if (nStatus == 500) strStatus = "Internal Server Error";
    ostringstream s;
    s << "HTTP/1.1 " << nStatus << " " << strStatus << "\r\n"
      << "Connection: close\r\n"
      << "Content-Length: " << strMsg.size() << "\r\n"
      << "Content-Type: application/json\r\n"
      << "Date: Sat, 09 Jul 2009 12:04:08 GMT\r\n"
      << "Server: json-rpc/1.0\r\n"
      << "\r\n"
      << strMsg;
    return s.str();
}

How often do you get the chance to work on a potentially world-changing project?
aceat64
Full Member
***
Offline Offline

Activity: 127



View Profile
September 04, 2010, 12:17:41 AM
 #5

I'm glad to hear that someone is working on this. My only question is what SSL certificate/key is used, and can we specify which cert/key?

Edit: I should have looked closer at your code, it clearly references a pem file.

Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652


Chief Scientist


View Profile WWW
September 06, 2010, 04:48:32 PM
 #6

Bear with me, this is a brain dump to try to organize my thoughts on securing the client <--> bitcoin JSON-RPC connection:

First: Preventing man-in-the-middle attacks:

HTTPS only prevents man-in-the-middle attacks if it is implemented properly by the client.  Example attack scenario against a lazy client:
  • Client connects to "https://bitcoinservice.org:8332/"
  • Attacker intercepts connection (e.g. via a DNS poisoning attack), and connects to the client using it's certificate.
  • Client gets certificate and doesn't bother to verify that the connection certificate is for bitcoinservice.org.  Completes SSL handshake.
  • Client then continues conversation by sending JSON-RPC request containing unencrypted rpcuser/rpcpassword.
  • Attacker now has rpcuser/rpcpassword and can mount a man-in-the-middle attack against the bitcoin server.

The "correct" way to prevent this is for clients to properly authenticate the server's certificate, but I don't think that's practical-- the default behavior for most url-opening libraries (used by the various JSON-RPC libraries) is to NOT validate server certificates.  You have to write extra code to install certificate authorities and/or write callbacks to examine the certificate and determine whether or not it is the certificate you expect.

I think a more practical way for the client to prevent a man-in-the-middle attack is for the client to hard-code the bitcoin server's IP address and avoid any DNS lookups-- connect to http://111.11.11.111:8332/ (if bitcoinservice.org is at IP 111.11.11.111).  It is much, much harder to successfully IP spoof a TCP connection than it is to successfully poison a DNS cache.

"Security in depth" is a good idea, and I've thought about layering other mechanisms for making the client->server connection secure, but I think we'd just be duplicating SSL functionality.  For example, I can imagine encrypting the whole JSON-RPC request string with a pre-shared key known to the clients and the server, but that's just a lame version of the strong encryption you get from SSL if the client is properly validating server certificates.  I think the security-in-depth will come from having the server authenticate clients, which brings me to:

Second: Authenticating clients:

The whole point of implementing HTTPS on the bitcoin JSON-RPC port is to allow connections from IP addresses other than 127.0.0.1.  But the "security-in-depth" idea means we almost certainly don't want to allow just anybody to connect and start sending bitcoins from our wallet.  Even if an attacker manages to steal the rcpuser/rpcpassword, we'd like to prevent them from emptying out our wallet if they try to connect from an unauthorized machine (if they can connect from an authorized machine you're already screwed).

Again, the "correct" way to authenticate clients is to do the public-key-infrastructure thing (... create a master bitcoin certificate you'll use as your certificate authority, then create public/private keys and certificates signed by that authority and require the clients and server to accept only connections properly signed with the right keys...).   And I think bitcoin should definitely support validating client certificates (that's just a couple of lines of OpenSSL library calls).

But again, I'm worried that some people deploying bitcoin either won't bother or will be using languages/libraries/systems that make it difficult or impossible to send a client certificate when connecting.

Hard-coding the IP addresses of clients that are allowed to connect via HTTPS (maybe allowing wild-carding of IP ranges) is a much easier-to-setup, almost-as-secure, way to authenticate clients.

So, to summarize my current thoughts on all this:

Recommendation for clients will be to:
  • Connect to the bitcoin JSON-RPC port via IP address and/or:
  • Properly validate the bicoin server certificate

The bitcoin JSON-RPC-https server will require:
  • Server private/public keys (generated using openssl, filename/path specified in bitcoin.conf file)
  • IP addresses (or ranges) of clients that are allowed to connect in the bitcoin.conf file
  • (optional)Certificate authority file used to validate clients (they must connect using a certificate signed by that authority)

What do y'all think-- sound reasonable?

How often do you get the chance to work on a potentially world-changing project?
jgarzik
Legendary
*
qt
Offline Offline

Activity: 1470


View Profile
September 06, 2010, 05:08:36 PM
 #7


Sounds good, though I think anonymous SSL + passwords + IP security will be sufficient for most.


Jeff Garzik, bitcoin core dev team and BitPay engineer; opinions are my own, not my employer.
Donations / tip jar: 1BrufViLKnSWtuWGkryPsKsxonV2NQ7Tcj
fellowtraveler
Sr. Member
****
Offline Offline

Activity: 440


View Profile
September 08, 2010, 03:58:48 AM
 #8

Quote
It isn't trivial to obtain the secret unless you patch the code to bind to interfaces other than loopback....

SSL connections are The Right Answer.

If I had any OpenSSL programming experience I'd volunteer to implement it.  Anybody willing and able to teach bitcoin to speak https?

And for extra credit, support SSL client certificates for authentication either instead of or in addition to HTTP-Basic...

My concern about HTTPS is that, via subpoena power or some other power (depending on jurisdiction) certain powerful entities can cause certificate registries to substitute one cert for another, thereby giving the entity the ability to listen in on communications or to forge signatures.

(This has already happened.)

co-founder, Monetas
creator, Open-Transactions
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652


Chief Scientist


View Profile WWW
September 08, 2010, 01:27:16 PM
 #9

Unlike a public HTTPS web server, which accepts connections from anybody, the bitcoin HTTPS JSON-RPC server will only accept connections from trusted clients, and you'll almost certainly be your own root certificate authority-- there is no reason to pay for a Verisign certificate, you should generate your own and deploy it with the code that is talking JSON-RPC to your server.

Or, in other words, since you'll control both ends of the conversation (as opposed to a web server, where you typically control EITHER the server OR the web browser) you can make it completely secure.

How often do you get the chance to work on a potentially world-changing project?
rodin
Newbie
*
Offline Offline

Activity: 14


View Profile
September 10, 2010, 09:51:19 PM
 #10

I've been using stunnel for SSL with self-signed certificates. My init script is posted here:

http://bitcointalk.org/index.php?topic=533.0

If you like this post, show your appreciation: 131bwEe6zWvEpnxGAqxDSqr9nsrrr7GDqH
Gavin Andresen
Legendary
*
qt
Offline Offline

Activity: 1652


Chief Scientist


View Profile WWW
September 15, 2010, 03:16:41 PM
 #11

Implementation was easy, once I figure out how boost::asio::ssl::stream worked...

Anyway, I've created a git branch for anybody who's willing to help test:
  http://github.com/gavinandresen/bitcoin-git/tree/jsonhttps

Documentation for what I done did:

Communicating with the Bitcoin JSON-RPC interface over SSL (https)

By default, bitcoin allows JSON-RPC commands to be sent to
http://localhost:8332/, and accepts connections only from the local
host.

It can be configured to allow https connections from other hosts;
three things must be setup for this to work properly:

1. You must setup a server certificate and private key.  A self-signed
certificate will work, you don't need a certificate signed by Verisign
or another certificate authority.

By default, bitcoin looks for the server's private key file in a
"server.pem" in the bitcoin data directory (e.g. ~/.bitcoin/server.pem
on unix), and the server certificate file in "server.cert".  To
generate them using the openssl command-line program, run:

  cd ~/.bitcoin
  openssl genrsa -out server.pem 2048
  openssl req -new -x509 -nodes -sha1 -days 3650 -key server.pem > server.cert

You should NOT enter a passphrase.

2. Specify the IP addresses of clients that are allowed to connect using
"rpcallowip" configuration file options.

Edit the bitcoin.conf file (in the bitcoin data directory), and add a
line for each IP address allowed to connect:
  rpcallowip=10.11.13.15
  rpcallowip=10.11.13.16
You may also allow connections from any IP address in a subnet using *:
  rpcallowip=192.168.1.*
  rpcallowip=10.1.*.*
You can also specify 'rpcallowip=*' to allow all IP addresses.

Connections from the local host (127.0.0.1) are always allowed.

3. You must tell bitcoin to use ssl using the "rpcssl" configuration file option.

Edit the bitcoin.conf file, and add:
  rpcssl=true

Restart bitcoin or bitcoind to make these changes take effect.  You
can test bitcoin's ssl functionality using the openssl s_client command:

  openssl s_client -connect localhost:8332

The connection should be successful and you should see the server's
certificate details.  If you press return twice, you should get a
'HTTP/1.0 401 Authorization Required' response.


Client setup

Once the server is accepting https connections, to be secure you should
make sure the client is actually connecting to the bitcoin server and
not an attacker trying to hijack the connection.

If you can, you should copy the server.cert certificate chain file to
the client machine and use it to validate the OpenSSL connection.
For example, in php you would call stream_context_create() with
the 'verify_peer' and 'ca_file' options and then call
stream_context_set_default().

If you can't validate using the server certificate, you should connect
to the server using its IP address instead of its host name.


All HTTPS-JSON-RPC-related bitcoin.conf options:

rpcport      : default: 8332  Listen for connections on this port
rpcuser      : user for HTTP BASIC authentication
rpcpassword  : password for HTTP BASIC authentication
rpcssl       : Not set by default, if set bitcoin will only accept SSL
               connections
rpcallowip   : Allow a client at this IP address to connect
               (may be specified multiple times)
rpcsslciphers: default "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH"
               (see the openSSL documentation for syntax)
rpcsslcertificatechainfile : default "server.cert"
rpcsslprivatekeyfile       : default "server.pem"


How often do you get the chance to work on a potentially world-changing project?
LZ
Staff
Legendary
*
Offline Offline

Activity: 1456


Satoshi everywhere!


View Profile WWW
September 16, 2010, 03:37:03 PM
 #12

[...] accepts connections only from the localhost [...]
I think that we should test it with faked hosts file on target operating systems.

"Never invest unless you can afford to lose your entire investment." © S3052
bitcoinex
Sr. Member
****
Offline Offline

Activity: 350


probiwon.com


View Profile WWW
November 06, 2010, 06:24:10 AM
 #13


All HTTPS-JSON-RPC-related bitcoin.conf options:

rpcport      : default: 8332  Listen for connections on this port
rpcuser      : user for HTTP BASIC authentication
rpcpassword  : password for HTTP BASIC authentication
rpcssl       : Not set by default, if set bitcoin will only accept SSL
               connections
rpcallowip   : Allow a client at this IP address to connect
               (may be specified multiple times)
rpcsslciphers: default "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH"
               (see the openSSL documentation for syntax)
rpcsslcertificatechainfile : default "server.cert"
rpcsslprivatekeyfile       : default "server.pem"




I think we should go ahead and add client authentication by SSL.
Need rpcsslcacertificates and rpcsslcarevoked variables. Moreover, it is best to add the ability read them directly from the directory in the set.

Then the next logical step is to add to a demon simultaneous control of several wallets.

The result is a ready infrastructure for the secure storage of money for a group of people in the likeness of mybitcoin.

These people have their low-power mobile devices (with client like this: http://bitcointalk.org/index.php?topic=533.0 ) will be able to securely connect to that server and send and receive money.

Huh... And so bitcoin captures the Universe!..

New bitcoin lottery: probiwon.com
- Может, ты ещё и в Невидимую Руку Рынка веруешь? - Зачем же веровать в то, что можно наблюдать непосредственно?
Pages: [1]
  Print  
 
Jump to:  

Sponsored by , a Bitcoin-accepting VPN.
Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!