Bitcoind

使與 bitcoind 伺服器的遠端 RPC 連接安全

  • April 11, 2019

我在 Ubuntu 伺服器上設置了一個 bitcoind 伺服器,我可以在伺服器上遠端執行命令。我正在使用 Java/RPC 執行此操作。要執行命令,我需要提供使用者名和密碼。但我認為這還不夠安全。這就是我在這裡問的原因。我怎樣才能使這個連接真正安全?首先,我認為我只能允許來自特定 IP 的請求,但這不起作用,因為我的應用程序在 Google 的 App Engine 上執行,因此沒有靜態 IP。

任何想法如何使這個安全?這是我的程式碼,如果感興趣的話:

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());      
   }
}

編輯:我剛剛注意到您的問題要求 App Engine 特定的解決方案。此解決方案僅適用於您對執行程式碼的 Linux 伺服器有 100% 的控制權,因此這在 App Engine 上不起作用(或者我不知道它現在是否具有建構隧道的能力)。無論如何,我建議您將程式碼從應用引擎移動到虛擬伺服器,以更好地控制您的堆棧,因為如果輪詢 bitcoind 進行交易,您可能會很快達到 App Engine 的限制。

通過 SSH 從執行程式碼的電腦到執行bitcoind.

建立這樣一個在斷開連接時重新啟動的隧道的一種簡單方法是AutoSSH

這是一個 AutoSSH 範例腳本:

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

建議:

  1. 為節點與外部之間的通信建構 API-REST、WS 或任何等效項。
  2. 盡可能限制對 RPC 節點的訪問(僅在本地訪問節點),您應該將比特幣節點視為數據庫。僅使用您的 ubuntu 伺服器來執行 RPC 和外部服務。
  3. 永遠不要將與節點的連接暴露給外部。查看比特幣 RPC 文件以獲取更多資訊。

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

抱歉,我的自動校對器讓我相信這是西班牙語論壇。

引用自:https://bitcoin.stackexchange.com/questions/21592