3

I set up a bitcoind server on an Ubuntu server and I can remotely execute commands on the server. I am doing this with Java/RPC. To execute a command I need to provide a username and password. But I think that would not be enough security. That's why I am asking here. How can I make this connection really secure? First, I thought I could only allow requests from a specific IP, but that will not work because my app runs on Google's App Engine and therefore does not have a static IP.

Any ideas how to make this secure? Here is my code, if it is of interest:

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

public class RPCClient {

    private static final String COMMAND_GET_BALANCE = "getbalance";
    private static final String COMMAND_GET_INFO = "getinfo";
    private static final String COMMAND_GET_NEW_ADDRESS = "getnewaddress";

    private JSONObject invokeRPC(String id, String method, List<String> params) {

//      CloseableHttpClient httpclient = HttpClientBuilder.create().build();
//      
//      httpclient.getCredentialsProvider();
        DefaultHttpClient httpclient = new DefaultHttpClient();

        JSONObject json = new JSONObject();
        json.put("id", id);
        json.put("method", method);
        if (null != params) {
            JSONArray array = new JSONArray();
            array.addAll(params);
            json.put("params", params);
        }
        JSONObject responseJsonObj = null;
        try {
            httpclient.getCredentialsProvider().setCredentials(new AuthScope("55.233.188.139", 9332),
                    new UsernamePasswordCredentials("myUser", "mySuperSecurePW"));
            StringEntity myEntity = new StringEntity(json.toJSONString());
            System.out.println(json.toString());
            HttpPost httppost = new HttpPost("http://55.233.188.139:9332");
            httppost.setEntity(myEntity);

            System.out.println("executing request" + httppost.getRequestLine());
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
                // System.out.println(EntityUtils.toString(entity));
            }
            JSONParser parser = new JSONParser();
            responseJsonObj = (JSONObject) parser.parse(EntityUtils.toString(entity));
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (org.json.simple.parser.ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            // When HttpClient instance is no longer needed,
            // shut down the connection manager to ensure
            // immediate deallocation of all system resources
            httpclient.getConnectionManager().shutdown();
        }
        return responseJsonObj;
    }

    public Double getBalance(String account) {
        String[] params = { account };
        JSONObject json = invokeRPC(UUID.randomUUID().toString(), COMMAND_GET_BALANCE, Arrays.asList(params));
        return (Double)json.get("result");
    }

    public String getNewAddress(String account) {
        String[] params = { account };
        JSONObject json = invokeRPC(UUID.randomUUID().toString(), COMMAND_GET_NEW_ADDRESS, Arrays.asList(params));
        return (String)json.get("result");
    }

    public JSONObject getInfo() {
        JSONObject json = invokeRPC(UUID.randomUUID().toString(), COMMAND_GET_INFO, null);
        return (JSONObject)json.get("result");
    }

    public JSONObject getInfo(String command) {
        JSONObject json = invokeRPC(UUID.randomUUID().toString(), command, null);
        return (JSONObject)json.get("result");
    }

    public static void main(String[] args) {
        System.out.println(new RPCClient().getInfo());      
    }
}
  • You first said you had an Ubuntu server with bitcoind running, and then AppEngine. Which one is it? – Luca Matteis Feb 3 '14 at 12:11
2

EDIT: I just noticed your question asks for App Engine specific solution. This solution only applies if you have 100% control over the Linux server running your code, so this does not work on App Engine (or I have no idea does it nowadays have capability of tunnel building). In any case I recommend you to move your code to a virtual server from the app engine to have more control over your stack, as you might hit App Engine limitations quite fast if polling bitcoind for transactions.

Build a TCP/IP tunnel through SSH from the computer running your code to the server running bitcoind.

One easy way to build such a tunnel which restarts itself on disconnect is AutoSSH.

Here is one AutoSSH example script:

http://www.ubuntugeek.com/automatically-restart-ssh-sessions-and-tunnels-using-autossh.html

0

Recommendations:

  1. Build an API-REST, WS, or any equivalent for communication between the node and the outside.

  2. Limit access to the RPC node as much as possible (Access the node only locally), you should consider the bitcoin node as a data base. use your ubuntu server only to run RPC and the external service.

  3. Never expose a connection to the node to the outside. check the Bitcoin RPC documentation for more information.

https://bitcoincore.org/en/doc/

Sorry, my automatic proofreader made me believe that this is the forum in Spanish.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.