4

以太坊系节点RPC端口开放被攻击的网络安全配置

 2 years ago
source link: https://learnblockchain.cn/article/3143
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

以太坊系节点RPC端口开放被攻击的网络安全配置

以太坊支持RPC模式,以太坊账户开启这种模式后,就可以自动化完成某些操作,比如矿池挖出币之后自动向钱包转账。攻击者主要利用RPC开放端口,所以只要限制RPC端口就可以做到防护。

一、主要攻击手段分析:

  • 1.批量扫描8545端口或18545端口等常用开放RPC端口
  • 2.当扫描到开放的端口之后,使用 eth.getBlockByNumber(查询区块高度)、eth.accounts(查询钱包地址)、eth.getBalance(查询钱包余额)三个命令来做相应动作。
  • 3.不断尝试发送 eth.sendTransaction 命令,该命令如果生效,则会把钱包中的余额转移到攻击者的钱包.有人会问,转账需要密钥参与,黑客是怎么绕开密钥呢?

原来,以太坊账户支持unlockAccount命令,这个命令是为了方便某些机械化交易提供的。在代币交易中,有些人使用电脑进行高频交易,以此来获取波动价差(股票高频交易也是这么做,有时候一分钟来回买卖几十次)。
以太坊在高频交易中(或者矿池自动转账)可以设置一段时间内无需输入密码,时间长短由用户自己指定。如果黑客正好在这段时间之内发来了“余额转移”的指令,以太坊账户(钱包或web账户)就会自动执行该操作,将钱包里的以太坊转到黑客钱包中。

我曾在自己的以太坊私链及公链中都被攻击,希望可以引起大家的重视。

二、用户应该如何防止此类攻击?

2.1 端口限制

  • 1、更改默认的 RPC API 端口,配置方法如:--rpcport 18545 或 --wsport 18546 ;如果使用的是docker容器的方式部署的节点,可在容器启动映射端口时,修改端口(让端口扫描无法生效)
  • 2、更改 RPC API 监听地址为固定的IP地址或者网段,配置方法如:--rpcaddr 192.168.1.100 或 --wsaddr 192.168.1.100,--rpcaddr 192.168.1.100/24 或 --wsaddr 192.168.1.100/24

注:rpcaddr:HTTP-RPC服务器监听地址 、wsaddr:websocket服务器监听地址

注:此方法是在以太坊节点处进行IP限制

  • 3、配置防火墙或安全组 限制对 RPC API 端口的访问,举例:只允许 192.168.1.100 访问 8545 端口(只接受特定IP发来的命令):
iptables -A INPUT -s 192.168.1.101 -p TCP --dport 8545 -j ACCEPT
iptables -A INPUT -p TCP --dport 8545 -j DROP

或者使用UFW防火墙,UFW或Uncomplicated Firewall是iptables的一个接口,旨在简化配置防火墙的过程,一般在ubuntu系统中使用

1.安装UFW 
  $ sudo apt-get install ufw

2.设置默认策略
  $ sudo ufw default deny incoming
  $ sudo ufw default allow outgoing

3.允许以太网p2p网络端口
我们还将启用以太坊网络,以便我们的节点能够与公共区块链网络进行通信和同步。例如以太坊网络端口是30303
  $ sudo ufw allow 30303

注:此方法是在部署节点的服务器中进行IP和端口的限制,物理服务器可通过iptables防火墙进行限制,云服务器可通过安全组进行限制

  • 4.启用RPC端口 我们只允许从我们的可信节点连接到我们的以太坊客户端。以太坊端口的默认RPC端口为8545。
$ sudo ufw allow from <IP addr> to any port 8545

例如,如果我的外部服务器IP地址是192.168.1.101,如果你使用的是与8545不同的不同RPC端口,还应该指定相应的端口。

sudo ufw allow from 192.168.1.101 to any port 8545

注:设置以上规则需要启用UFW, sudo ufw enable

综上所述,建议你配置为:允许所有人可连接到以太坊RPC和网络端口。在防火墙或安全组中确保允许服务器需要的任何其他传入连接,同时限制任何不必要的连接,以便你的服务器功能和安全。

2.2 私钥安全

  • 1.账户信息(keystore)不要存放在节点上 (因为账户不在节点上,所以就不会用到 unlockAccount 了)

注:平时账户信息不要存放在节点中,但是如果需要冲洗某个账户的交易,有可能会使用到节点人为操作,这时候务必确保你的节点rpc端口仅信任的IP地址可连接,否则有可能造成账户资金被转移的情况。

  • 2.任何转账均用 web3 的 sendTransaction 和 sendRawTransaction 发送私钥签名过的 transaction(限制不安全的转账命令)
  • 3.私钥物理隔离(如冷钱包、手工抄写)或者高强度加密存储并保障密钥的安全

注:私钥的安全配置,除了以上需要几点,还有特别多需要注意的地方,因为本篇文章讲述的是RPC端口的网络安全问题,所以此处不再赘述私钥安全。

三、RPC端口访问加密及访问控制

如果geth节点不得不暴露在公网上面,则会面临很多安全风险。一个可能的补救措施是对RPC访问进行加密。通过nginx的HTTP basic Auth(Http基本认证)技术,可以实现更高的安全。

原理:通过配置nginx的反向代理和加密技术,可以给运行在linux上的应用程序分配一个新的url,访问应用程序就相当于访问这个url。外部用户想访问这个url,必须输入用户名和密码,否则访问会被拒绝。对于geth节点,以前必须对所有用户暴露rpc端口,采用NBHA技术,则给geth分配一个对于的url,需要用户名和密码才能访问geth节点。这个时候,geth节点不必对外开放RPC端口。

3.1 nginx配置

nginx使用docker部署的方法,可参考我以前的文章【三分钟教程】docker快速部署nginx服务

部署好nginx服务以后,再进行以下的操作:

  • 安装htpasswd工具
# docker exec -it nginx bash
# apt-get update
# apt-get install apache2-utils -y
  • 创建认证用户名和密码
# htpasswd -c /etc/nginx/geth.htpasswd eth  
New password:   输入密码
Re-type new password: 再次输入密码
Adding password for user eth   (已为用户eth添加密码)

3.2 http请求配置

将在/etc/nginx下创建名为geth.htpasswd的密码文件,用户名设置为eth。输入上面命令,会提示用户输入俩次密码。 修改nginx配置,打开文件 /etc/nginx/sites-enabled/default文件,将里面的内容修改成这样:

server {
    listen 80 default_server;
    server_name localhost;
 
    location / {
        try_files $uri $uri/ =404;
    }
 
    location /eth {
        auth_basic "Restricted Area";
        auth_basic_user_file /etc/nginx/geth.htpasswd;
        proxy_pass http://localhost:8545;
      }
    access_log  /var/log/nginx/localhost.log  main;
}

在这里将服务器的名字设为localhost,geth对应的url为localhost/eth,其对应的密码文件通过auth_basic_user_file指令进行制定。

此时可以用浏览器中访问看什么效果,此时应出现的效果应该是:

访问:http://localhost/,出现404页面

访问:http://localhost/eth 当输入正确的用户名和密码后点击OK,如果没有出现错误,这说明配置成功。

到现在为止,已经成功的用nginx为geth构建了一层安全防护,并给geth映射了一个外部访问的url,现在访问geth不必通过http://:的方式,而是直接访问映射的url。如geth attach http://username:password@ip/eth 所以现在是时候把geth暴露出去的rpc端口采取禁止外部访问的操作了。腾讯云阿里云都有安全组可以实现这个操作。

curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' http://eth:[email protected]/eth

3.3 安卓机ios访问配置

web3j使用的Http模块为OkHttp3,认证需要的用户名和密码信息可以按照OkHttp3添加认证的方式来添加。没使用Http认证时,web3j构建Admin对象的方式是:

Admin ethClient;
ethClient = Admin.build(new HttpService(url));

加入认证用户名和密码的方式:

private static OkHttpClient buildBasicAuthClient() {
        return new OkHttpClient.Builder().authenticator(new Authenticator() {
            @Override
            public Request authenticate(Route route, Response response) throws IOException {
                String credential = okhttp3.Credentials.basic(Define.userName, Define.passwd);
                return response.request().newBuilder().header("Authorization", credential).build();
            }
        }).build();
 }
 
Admin ethClient;
ethClient = Admin.build(new HttpService(url,buildBasicAuthClient(),false));

3.4 nginx 跨域配置

OK,现在可以用Web3j访问加入了Http认证保护的geth节点了。
上面适合安卓客户端,而ios端调用web3.js来访问Http Basic Authentication保护资源的问题
ios客户端访问geth的方式跟安卓端不一样。由于没有开源成熟的OC语言的类似于web3j的库,ios端只有通过webview的方式建立一个Html页面,在页面里通过js来调用web3.js的API函数来访问geth。在浏览器里面访问有Http Basic Authentication的geth节点,会报错,这是浏览器在报js跨域访问的问题。一番谷歌后仿照网上解决CROS的方法,通过添加配置nginx的配置文件添加,最终的配置:

server {
    listen 80 default_server;
    server_name localhost;
 
    location / {
        try_files $uri $uri/ =404;
    }
 
    location /eth {
        auth_basic "Restricted Area";
        auth_basic_user_file /etc/nginx/geth.htpasswd;
        proxy_pass http://localhost:8545;
        if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers'         'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Auth        orization';
        
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
          }
     }
    access_log  /var/log/nginx/localhost.log  main;
}

3.5 nginx https 配置

当然除了HTTP基本认证还可以配置带证书保护的Https,这个更安全。
Http协议的传输过程是明文,因此使用HTTP协议传输隐私信息非常不安全。HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。它能够对传输内容进行加密。HTTPS需要申请一个CA证书,阿里云上面可以申请免费的Symantec证书。阿里云证书需要先有一个可用的域名,该域名映射到节点的ip。申请证书后再下载到节点中,然后在nginx的配置文件中进行配置。

nginx配置HTTPS,具体配置方法如下:

server{
    listen 443 ssl; 
    server_name localhost;
    charset utf-8;
    ssl_certificate /etc/nginx/cert/xxx.pem;
    ssl_certificate_key  /etc/nginx/cert/xxx.key;
    ssl_session_timeout 5m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
    ssl_prefer_server_ciphers on;
    location / {
        try_files $uri $uri/ =404;
    }
 
    location /eth {
        auth_basic "Restricted Area";
        auth_basic_user_file /etc/nginx/geth.htpasswd;
        proxy_pass http://localhost:8545;
        if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
        }
     } 
     access_log  /var/log/nginx/localhost.log  main;
}

重启nginx服务既可以使用https了

3.6 nginx 访问控制配置

在某些时候,我们可能还需要仅允许部分IP可以访问。当然,这个需求,其实在阿里云或腾讯云的安全组上就可以实现,或者使用服务器的iptables防火墙也是可以的。下面这种方法是利用nginx中访问控制的功能进行实现的。nginx配置如下:

server{
    listen 443 ssl; 
    server_name localhost;
    charset utf-8;
    ssl_certificate /etc/nginx/cert/xxx.pem;
    ssl_certificate_key  /etc/nginx/cert/xxx.key;
    ssl_session_timeout 5m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
    ssl_prefer_server_ciphers on;
    location / {
        try_files $uri $uri/ =404;
    }
 
    location /eth {
        auth_basic "Restricted Area";
        auth_basic_user_file /etc/nginx/geth.htpasswd;
        proxy_pass http://localhost:8545;
        if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
        }
       #####限制仅部分IP访问##############
       allow 49.7.66.132;
       allow 124.65.8.139;
       deny all;
       ######限制仅部分IP访问##############
     } 
     access_log  /var/log/nginx/localhost.log  main;
}

例如以上配置,出现在allow中的IP是可以访问的,未出现在allow中的IP访问 https://localhost/eth 时,会出现403拒绝访问的状态码。


以上,就是今天分享的全部内容了。

希望大家通过以上方式可以解决自己的实际需求,解决自己目前所遇到的问题。

如果在配置过程中有任何疑问,可以添加我的个人微信,备注:地区-职业方向-昵称,欢迎来撩,加入区块链技术交流群,与更多的区块链技术大佬学习交流。

原创不易,码字不易。 觉得这篇文章对你有点用的话,麻烦你为本文点个赞,留言或转发一下,因为这将是我输出更多优质文章的动力,感谢!

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 2天前
  • 阅读 ( 82 )
  • 学分 ( 15 )
  • 分类:公链

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK