以太坊支持RPC模式,以太坊賬戶開啟這種模式后,就可以自動(dòng)化完成某些操作珠月,比如礦池挖出幣之后自動(dòng)向錢包轉(zhuǎn)賬扩淀。攻擊者主要利用RPC開放端口,所以只要限制RPC端口就可以做到防護(hù)。
一桥温、主要攻擊手段分析:
- 1.批量掃描8545端口或18545端口等常用開放RPC端口
- 2.當(dāng)掃描到開放的端口之后,使用 eth.getBlockByNumber(查詢區(qū)塊高度)蹲堂、eth.accounts(查詢錢包地址)歇拆、eth.getBalance(查詢錢包余額)三個(gè)命令來做相應(yīng)動(dòng)作。
- 3.不斷嘗試發(fā)送 eth.sendTransaction 命令础嫡,該命令如果生效氛谜,則會(huì)把錢包中的余額轉(zhuǎn)移到攻擊者的錢包.有人會(huì)問掏觉,轉(zhuǎn)賬需要密鑰參與,黑客是怎么繞開密鑰呢值漫?
原來澳腹,以太坊賬戶支持unlockAccount命令,這個(gè)命令是為了方便某些機(jī)械化交易提供的杨何。在代幣交易中酱塔,有些人使用電腦進(jìn)行高頻交易,以此來獲取波動(dòng)價(jià)差(股票高頻交易也是這么做危虱,有時(shí)候一分鐘來回買賣幾十次)羊娃。
以太坊在高頻交易中(或者礦池自動(dòng)轉(zhuǎn)賬)可以設(shè)置一段時(shí)間內(nèi)無需輸入密碼,時(shí)間長(zhǎng)短由用戶自己指定埃跷。如果黑客正好在這段時(shí)間之內(nèi)發(fā)來了“余額轉(zhuǎn)移”的指令蕊玷,以太坊賬戶(錢包或web賬戶)就會(huì)自動(dòng)執(zhí)行該操作,將錢包里的以太坊轉(zhuǎn)到黑客錢包中弥雹。
我曾在自己的以太坊私鏈及公鏈中都被攻擊垃帅,希望可以引起大家的重視。
二剪勿、用戶應(yīng)該如何防止此類攻擊贸诚?
2.1 端口限制
1、更改默認(rèn)的 RPC API 端口厕吉,配置方法如:--rpcport 18545 或 --wsport 18546 赦颇;如果使用的是docker容器的方式部署的節(jié)點(diǎn),可在容器啟動(dòng)映射端口時(shí)赴涵,修改端口(讓端口掃描無法生效)
2媒怯、更改 RPC API 監(jiān)聽地址為固定的IP地址或者網(wǎng)段,配置方法如:--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服務(wù)器監(jiān)聽地址 扇苞、wsaddr:websocket服務(wù)器監(jiān)聽地址
注:此方法是在以太坊節(jié)點(diǎn)處進(jìn)行IP限制
- 3欺殿、配置防火墻或安全組 限制對(duì) RPC API 端口的訪問,舉例:只允許 192.168.1.100 訪問 8545 端口(只接受特定IP發(fā)來的命令):
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的一個(gè)接口鳖敷,旨在簡(jiǎn)化配置防火墻的過程,一般在ubuntu系統(tǒng)中使用
1.安裝UFW
$ sudo apt-get install ufw
2.設(shè)置默認(rèn)策略
$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing
3.允許以太網(wǎng)p2p網(wǎng)絡(luò)端口
我們還將啟用以太坊網(wǎng)絡(luò)脖苏,以便我們的節(jié)點(diǎn)能夠與公共區(qū)塊鏈網(wǎng)絡(luò)進(jìn)行通信和同步。例如以太坊網(wǎng)絡(luò)端口是30303
$ sudo ufw allow 30303
注:此方法是在部署節(jié)點(diǎn)的服務(wù)器中進(jìn)行IP和端口的限制定踱,物理服務(wù)器可通過iptables防火墻進(jìn)行限制棍潘,云服務(wù)器可通過安全組進(jìn)行限制
- 4.啟用RPC端口 我們只允許從我們的可信節(jié)點(diǎn)連接到我們的以太坊客戶端。以太坊端口的默認(rèn)RPC端口為8545崖媚。
$ sudo ufw allow from <IP addr> to any port 8545
例如亦歉,如果我的外部服務(wù)器IP地址是192.168.1.101,如果你使用的是與8545不同的不同RPC端口畅哑,還應(yīng)該指定相應(yīng)的端口肴楷。
sudo ufw allow from 192.168.1.101 to any port 8545
注:設(shè)置以上規(guī)則需要啟用UFW, sudo ufw enable
綜上所述荠呐,建議你配置為:允許所有人可連接到以太坊RPC和網(wǎng)絡(luò)端口赛蔫。在防火墻或安全組中確保允許服務(wù)器需要的任何其他傳入連接,同時(shí)限制任何不必要的連接泥张,以便你的服務(wù)器功能和安全呵恢。
2.2 私鑰安全
- 1.賬戶信息(keystore)不要存放在節(jié)點(diǎn)上 (因?yàn)橘~戶不在節(jié)點(diǎn)上,所以就不會(huì)用到 unlockAccount 了)
注:平時(shí)賬戶信息不要存放在節(jié)點(diǎn)中媚创,但是如果需要沖洗某個(gè)賬戶的交易渗钉,有可能會(huì)使用到節(jié)點(diǎn)人為操作,這時(shí)候務(wù)必確保你的節(jié)點(diǎn)rpc端口僅信任的IP地址可連接筝野,否則有可能造成賬戶資金被轉(zhuǎn)移的情況晌姚。
- 2.任何轉(zhuǎn)賬均用 web3 的 sendTransaction 和 sendRawTransaction 發(fā)送私鑰簽名過的 transaction(限制不安全的轉(zhuǎn)賬命令)
- 3.私鑰物理隔離(如冷錢包、手工抄寫)或者高強(qiáng)度加密存儲(chǔ)并保障密鑰的安全
注:私鑰的安全配置歇竟,除了以上需要幾點(diǎn)挥唠,還有特別多需要注意的地方,因?yàn)楸酒恼轮v述的是RPC端口的網(wǎng)絡(luò)安全問題焕议,所以此處不再贅述私鑰安全宝磨。
三、RPC端口訪問加密及訪問控制
如果geth節(jié)點(diǎn)不得不暴露在公網(wǎng)上面盅安,則會(huì)面臨很多安全風(fēng)險(xiǎn)唤锉。一個(gè)可能的補(bǔ)救措施是對(duì)RPC訪問進(jìn)行加密。通過nginx的HTTP basic Auth(Http基本認(rèn)證)技術(shù)别瞭,可以實(shí)現(xiàn)更高的安全窿祥。
原理:通過配置nginx的反向代理和加密技術(shù),可以給運(yùn)行在linux上的應(yīng)用程序分配一個(gè)新的url蝙寨,訪問應(yīng)用程序就相當(dāng)于訪問這個(gè)url晒衩。外部用戶想訪問這個(gè)url嗤瞎,必須輸入用戶名和密碼,否則訪問會(huì)被拒絕听系。對(duì)于geth節(jié)點(diǎn)贝奇,以前必須對(duì)所有用戶暴露rpc端口,采用NBHA技術(shù)靠胜,則給geth分配一個(gè)對(duì)于的url掉瞳,需要用戶名和密碼才能訪問geth節(jié)點(diǎn)。這個(gè)時(shí)候浪漠,geth節(jié)點(diǎn)不必對(duì)外開放RPC端口陕习。
3.1 nginx配置
nginx使用docker部署的方法,可參考我以前的文章【三分鐘教程】docker快速部署nginx服務(wù)
部署好nginx服務(wù)以后郑藏,再進(jìn)行以下的操作:
- 安裝htpasswd工具
# docker exec -it nginx bash
# apt-get update
# apt-get install apache2-utils -y
- 創(chuàng)建認(rèn)證用戶名和密碼
# htpasswd -c /etc/nginx/geth.htpasswd eth
New password: 輸入密碼
Re-type new password: 再次輸入密碼
Adding password for user eth (已為用戶eth添加密碼)
3.2 http請(qǐng)求配置
將在/etc/nginx下創(chuàng)建名為geth.htpasswd的密碼文件衡查,用戶名設(shè)置為eth瘩欺。輸入上面命令必盖,會(huì)提示用戶輸入倆次密碼。 修改nginx配置俱饿,打開文件 /etc/nginx/sites-enabled/default文件歌粥,將里面的內(nèi)容修改成這樣:
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;
}
在這里將服務(wù)器的名字設(shè)為localhost,geth對(duì)應(yīng)的url為localhost/eth拍埠,其對(duì)應(yīng)的密碼文件通過auth_basic_user_file指令進(jìn)行制定失驶。
此時(shí)可以用瀏覽器中訪問看什么效果,此時(shí)應(yīng)出現(xiàn)的效果應(yīng)該是:
訪問:http://localhost/枣购,出現(xiàn)404頁(yè)面
訪問:http://localhost/eth 當(dāng)輸入正確的用戶名和密碼后點(diǎn)擊OK,如果沒有出現(xiàn)錯(cuò)誤嬉探,這說明配置成功。
到現(xiàn)在為止棉圈,已經(jīng)成功的用nginx為geth構(gòu)建了一層安全防護(hù)涩堤,并給geth映射了一個(gè)外部訪問的url,現(xiàn)在訪問geth不必通過http://<ip>:<port>的方式,而是直接訪問映射的url分瘾。如geth attach http://username:password@ip/eth 所以現(xiàn)在是時(shí)候把geth暴露出去的rpc端口采取禁止外部訪問的操作了胎围。騰訊云阿里云都有安全組可以實(shí)現(xiàn)這個(gè)操作。
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' http://eth:123456@lijie.bbef.top/eth
3.3 安卓機(jī)ios訪問配置
web3j使用的Http模塊為OkHttp3德召,認(rèn)證需要的用戶名和密碼信息可以按照OkHttp3添加認(rèn)證的方式來添加白魂。沒使用Http認(rèn)證時(shí),web3j構(gòu)建Admin對(duì)象的方式是:
Admin ethClient;
ethClient = Admin.build(new HttpService(url));
加入認(rèn)證用戶名和密碼的方式:
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上岗,現(xiàn)在可以用Web3j訪問加入了Http認(rèn)證保護(hù)的geth節(jié)點(diǎn)了福荸。
上面適合安卓客戶端,而ios端調(diào)用web3.js來訪問Http Basic Authentication保護(hù)資源的問題
ios客戶端訪問geth的方式跟安卓端不一樣。由于沒有開源成熟的OC語(yǔ)言的類似于web3j的庫(kù)肴掷,ios端只有通過webview的方式建立一個(gè)Html頁(yè)面敬锐,在頁(yè)面里通過js來調(diào)用web3.js的API函數(shù)來訪問geth辞嗡。在瀏覽器里面訪問有Http Basic Authentication的geth節(jié)點(diǎn),會(huì)報(bào)錯(cuò),這是瀏覽器在報(bào)js跨域訪問的問題滞造。一番谷歌后仿照網(wǎng)上解決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 配置
當(dāng)然除了HTTP基本認(rèn)證還可以配置帶證書保護(hù)的Https谒养,這個(gè)更安全挺狰。
Http協(xié)議的傳輸過程是明文,因此使用HTTP協(xié)議傳輸隱私信息非常不安全买窟。HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸丰泊、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,要比http協(xié)議安全始绍。它能夠?qū)鬏攦?nèi)容進(jìn)行加密瞳购。HTTPS需要申請(qǐng)一個(gè)CA證書,阿里云上面可以申請(qǐng)免費(fèi)的Symantec證書亏推。阿里云證書需要先有一個(gè)可用的域名学赛,該域名映射到節(jié)點(diǎn)的ip。申請(qǐng)證書后再下載到節(jié)點(diǎn)中吞杭,然后在nginx的配置文件中進(jìn)行配置盏浇。
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服務(wù)既可以使用https了
3.6 nginx 訪問控制配置
在某些時(shí)候芽狗,我們可能還需要僅允許部分IP可以訪問绢掰。當(dāng)然,這個(gè)需求童擎,其實(shí)在阿里云或騰訊云的安全組上就可以實(shí)現(xiàn)滴劲,或者使用服務(wù)器的iptables防火墻也是可以的。下面這種方法是利用nginx中訪問控制的功能進(jìn)行實(shí)現(xiàn)的顾复。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;
}
例如以上配置班挖,出現(xiàn)在allow中的IP是可以訪問的,未出現(xiàn)在allow中的IP訪問 https://localhost/eth 時(shí)捕透,會(huì)出現(xiàn)403拒絕訪問的狀態(tài)碼聪姿。
以上,就是今天分享的全部?jī)?nèi)容了乙嘀。
希望大家通過以上方式可以解決自己的實(shí)際需求末购,解決自己目前所遇到的問題。
原創(chuàng)不易虎谢,碼字不易盟榴。 覺得這篇文章對(duì)你有點(diǎn)用的話,麻煩你為本文點(diǎn)個(gè)贊婴噩,留言或轉(zhuǎn)發(fā)一下擎场,因?yàn)檫@將是我輸出更多優(yōu)質(zhì)文章的動(dòng)力羽德,感謝!