1. 从一次凌晨告警说起:RPC端口暴露的真实代价
凌晨两点多,手机突然连续震动,监控平台推来一串告警:某台自建节点的出块延迟飙升,CPU占用直接顶到100%,磁盘IO也异常繁忙。爬起来连上去一看,geth进程的日志里刷满了来自陌生IP的eth_sendRawTransaction和eth_getBlockByNumber请求,频率高得离谱。那一刻我就明白了——节点的RPC端口又被人盯上了。
这不是什么新鲜事。很多人在本地或者云主机上跑以太坊全节点,图省事,直接把--http.addr设成0.0.0.0,端口8545就这么明晃晃地挂在公网上。跑起来那一刻确实爽,钱包、脚本、DApp后端都能连上,但同时也等于把自家大门钥匙插在锁孔上,谁路过都能拧一下。轻则被当成免费公共RPC节点被人白嫖带宽和算力,重则被恶意合约调用、被扫描器批量探测、被当成跳板发起更大规模的请求,甚至因为eth_accounts没关干净导致本地账户被掏空。
这篇笔记就是围绕以太坊节点RPC端口暴露这件事,把攻击面、风险点、以及我自己踩过坑之后总结出来的一套网络安全配置方案完整讲清楚。不管你是刚学会geth命令的新手,还是已经跑了几个月的半熟手,只要你的节点RPC曾经或正在对公网开放,这里面的内容都值得对照着检查一遍。核心关键词就三个:RPC暴露、访问控制、节点加固。我会从攻击者视角先讲清楚他们怎么打,再讲防守方怎么配,最后给一份可以直接抄的配置清单。
2. 攻击者眼里的8545端口:他们到底在打什么
2.1 端口扫描与节点指纹识别
公网上的扫描器是24小时不休息的。8545这个端口在Shodan、Censys这类资产搜索引擎里属于高频目标,因为以太坊JSON-RPC的默认端口太固定了。攻击者不需要知道你的IP,只需要批量扫全网开放8545的地址,然后发一个{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1},就能拿到你节点的客户端类型和版本号。
这一步的意义在于筛选。不同客户端、不同版本的已知问题不一样,攻击者拿到指纹后就能针对性地下手。比如老版本某些客户端在特定RPC方法上存在信息泄露,或者对请求频率没有限制,这些都是可利用的点。我实测过,一台刚暴露8545的节点,快的话几分钟内就会收到第一波探测请求,慢的话也不会超过半小时。
2.2 被白嫖算力:公共RPC的隐形账单
最常见的攻击其实谈不上"攻击",就是盗用。攻击者把你的节点当成免费公共RPC,用来查询余额、广播交易、拉取区块数据。单看一个请求没什么,但架不住量大。我见过最夸张的情况是一台节点一天处理了上百万次eth_call,全是陌生地址发来的,CPU和带宽被吃满,自己业务反而卡得动不了。
这种盗用的隐蔽性很强,因为请求本身都是合法的RPC调用,日志里看起来就是正常的查询。但你的云主机流量账单、CPU负载、磁盘读写会诚实地反映出来。更麻烦的是,如果攻击者用你的节点做高频轮询,还可能触发云服务商的流量限制或者被标记为异常主机。
2.3 危险方法调用:从信息泄露到资产风险
JSON-RPC里有一批方法,在暴露环境下是绝对不能开的。我整理了一张表,把风险等级和后果列清楚:
| RPC方法 | 风险等级 | 暴露后的后果 |
|---|---|---|
eth_accounts | 极高 | 返回节点管理的账户地址列表,配合其他方法可能进一步操作 |
personal_*系列 | 极高 | 涉及账户解锁、转账等敏感操作,绝不能对公网开放 |
admin_*系列 | 高 | 节点管理接口,可添加删除节点、修改配置 |
debug_*系列 | 高 | 调试接口,可能泄露内存、堆栈等内部信息 |
txpool_*系列 | 中 | 交易池内容,可能被用于抢跑分析 |
eth_sendRawTransaction | 中 | 广播交易,被滥用会消耗节点资源 |
eth_call | 低 | 只读调用,但高频滥用会拖垮节点 |
关键点在于,很多客户端默认会开放一部分admin和debug接口,如果你没有显式关闭,它们就跟着8545一起暴露了。eth_accounts尤其危险,虽然它本身只是返回地址,但如果节点上恰好有解锁的账户,后续就可能被利用。
2.4 资源耗尽型攻击:让节点自己把自己拖死
还有一类攻击不图你的资产,就是单纯让你的节点瘫痪。手法很简单:高频发送计算量大的eth_call,或者构造大量复杂查询,让节点CPU长时间满载。节点一旦响应变慢,出块、同步、交易广播都会受影响,严重时直接失去与网络的连接。
这种攻击的成本极低,攻击者只需要一个脚本循环发请求就行。而防守方如果没有限流和访问控制,基本只能被动挨打。我在早期就吃过这个亏,一台配置还不错的机器,被连续请求打了几个小时,最后只能重启节点才恢复。
3. 暴露面收敛:从监听地址到方法白名单的逐层收紧
3.1 监听地址:为什么0.0.0.0是万恶之源
--http.addr这个参数决定了RPC服务监听在哪个网络接口上。默认情况下,很多教程会让你设成0.0.0.0,意思是监听所有网卡,任何能访问到这台机器IP的人都能连。这就是暴露的起点。
正确的做法是只监听本地回环地址127.0.0.1。这样只有本机上的进程能访问RPC,外部一律连不上。如果你的DApp后端和节点在同一台机器上,这个配置就够了。如果不在同一台机器,那也不应该直接把节点暴露出去,而是通过其他方式转发,这个后面会讲。
# 错误示范:监听所有网卡 geth --http --http.addr 0.0.0.0 --http.port 8545 # 正确示范:只监听本地 geth --http --http.addr 127.0.0.1 --http.port 8545改完这一行,公网扫描器就彻底找不到你的RPC了。这是成本最低、效果最明显的一步。
3.2 端口选择:换个门牌号能挡掉多少脚本
有人会想,那我把端口从8545改成别的,比如18545,是不是就安全了?答案是:能挡掉一部分无差别扫描,但挡不住针对性扫描。端口混淆属于"安全通过隐蔽"的思路,有一定价值,但不能作为主要防线。
我的建议是,如果你确实需要对外提供RPC(比如给多个远程服务用),可以换一个不常见的端口,同时配合后面的访问控制一起用。但如果你只是本机用,那监听127.0.0.1就够了,端口改成什么都不影响。
3.3 模块白名单:只开必须的,关掉危险的
以太坊客户端允许你通过--http.api参数指定开放哪些RPC模块。默认配置往往开得比较多,我们需要手动收窄。下面是我推荐的配置:
geth --http --http.addr 127.0.0.1 --http.port 8545 \ --http.api eth,net,web3这里只开了eth、net、web3三个模块。eth是查询和发交易必须的,net提供网络信息,web3提供客户端版本等基础信息。admin、debug、personal、txpool这些全部不开。如果你确实需要txpool来监控交易池,那也要在访问控制做好之后再开,并且只对可信来源开放。
注意:不同客户端的模块名称略有差异,配置前先查一下你所使用客户端的文档,确认模块名拼写正确,否则可能启动报错。
3.4 IPC与WebSocket:别只顾着HTTP
很多人只关注HTTP的8545,却忽略了IPC和WebSocket。IPC是本地进程间通信,默认走文件系统,一般不会暴露到网络,但如果你把IPC路径设到了共享目录,那就有风险。WebSocket默认端口是8546,同样可能被暴露。
# 关闭WebSocket(如果不需要) geth --http --http.addr 127.0.0.1 \ --ws.addr 127.0.0.1 --ws.port 8546 \ --ws.api eth,net,web3如果不需要WebSocket,直接不启动--ws相关参数即可。需要的话,同样只监听本地,并且收窄API模块。
4. 访问控制实战:防火墙、反向代理与认证三板斧
4.1 系统防火墙:第一道也是最硬的一道墙
即使你把监听地址改成了127.0.0.1,也建议在系统防火墙上再加一层规则,防止配置被误改。以常见的Linux防火墙为例:
# 使用ufw的情况 sudo ufw deny 8545/tcp sudo ufw deny 8546/tcp sudo ufw allow 30303/tcp # P2P端口需要保留 sudo ufw allow 30303/udp30303是以太坊P2P通信端口,这个必须保留,否则节点无法和网络同步。但8545和8546这两个RPC端口,除非有明确的对外需求,否则一律拒绝。这样即使某天你不小心把监听地址改回了0.0.0.0,防火墙也能兜住。
4.2 反向代理:把RPC藏在Nginx后面
如果你确实需要让远程服务访问RPC,又不想直接暴露节点,可以用Nginx做反向代理。节点只监听127.0.0.1:8545,Nginx监听公网端口,转发请求到本地节点。这样你可以在Nginx层做限流、认证、日志记录。
server { listen 443 ssl; server_name your-domain.example; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location /rpc { # 只允许特定IP访问 allow 203.0.113.10; deny all; # 限流:每秒最多10个请求 limit_req zone=rpc_limit burst=20 nodelay; proxy_pass http://127.0.0.1:8545; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }配合Nginx的limit_req_zone配置,可以有效挡住高频请求。allow和deny则实现了IP白名单。这样即使有人扫到了你的公网端口,没有白名单IP也进不来。
4.3 认证层:给RPC加一把锁
Nginx还可以做HTTP Basic认证,给RPC接口加一层用户名密码。虽然Basic认证本身是明文传输(所以必须配合HTTPS),但作为一层额外防护是有效的。
# 生成密码文件 sudo htpasswd -c /etc/nginx/.htpasswd rpcuser然后在Nginx配置里加上:
location /rpc { auth_basic "RPC Access"; auth_basic_user_file /etc/nginx/.htpasswd; # ... 其他配置 }这样客户端请求时需要带上认证头。对于脚本调用,可以在请求里加-u rpcuser:password。这层认证能挡掉绝大多数没有凭据的扫描和盗用。
4.4 限流与熔断:让节点有喘息的机会
限流是防守资源耗尽攻击的关键。除了Nginx层的限流,客户端本身也有一些参数可以控制。比如geth的--http.rpcprefix可以给RPC路径加前缀,增加一点隐蔽性。更重要的还是外部限流。
我自己的做法是,在Nginx层配置两个限流维度:按IP限流和全局限流。按IP限流防止单个IP打爆,全局限流防止分布式攻击。具体阈值根据你的节点配置和业务量调整,一般单IP每秒10到20个请求,全局每秒几百个请求,是比较稳妥的起点。
5. 监控与应急:被打了怎么发现、怎么止损
5.1 日志里该盯哪些信号
节点日志和Nginx访问日志是发现异常的第一现场。我平时会重点关注这几个信号:
- 请求频率突增:某个IP或某段时间的请求量明显高于基线。
- 异常方法调用:日志里出现
admin_、debug_、personal_等不该出现的方法名。 - 错误率上升:大量
method not found或invalid request,说明有人在探测。 - 资源指标异常:CPU、内存、磁盘IO在没有业务增长的情况下持续高位。
把这些指标接入监控平台,设置阈值告警,比事后翻日志要主动得多。
5.2 应急响应:发现被攻击后的操作顺序
一旦确认节点正在被攻击,我的操作顺序是这样的:
- 先切流量:在防火墙或Nginx层直接封掉攻击源IP,或者临时关闭对外RPC入口。
- 再看资产:检查节点上是否有解锁账户,确认没有异常交易发出。
- 后查日志:分析攻击来源、攻击手法、是否有成功入侵的痕迹。
- 最后恢复:确认安全后,逐步恢复服务,同时加强防护。
这个顺序的核心逻辑是先止损,再排查。不要一上来就研究攻击者是谁,先把口子堵上,避免损失扩大。
5.3 日常巡检清单
防守是持续的事,不是配一次就完事。我给自己列了一份巡检清单,每周过一遍:
- 确认RPC监听地址仍是
127.0.0.1,没有被误改。 - 确认防火墙规则仍然生效,
8545和8546没有意外开放。 - 检查Nginx访问日志,看是否有异常IP或异常请求模式。
- 检查节点日志,看是否有危险方法被调用。
- 检查系统资源使用情况,看是否有异常负载。
- 确认客户端版本,及时更新已知安全问题的版本。
这份清单看起来简单,但坚持做下来,能挡掉大部分低级攻击和配置漂移带来的风险。
6. 一套可以直接抄的加固配置模板
6.1 客户端启动参数模板
把前面讲的内容整合起来,这是一份我目前在用的启动参数模板:
geth \ --http \ --http.addr 127.0.0.1 \ --http.port 8545 \ --http.api eth,net,web3 \ --http.corsdomain "" \ --ws.addr 127.0.0.1 \ --ws.port 8546 \ --ws.api eth,net,web3 \ --authrpc.addr 127.0.0.1 \ --authrpc.port 8551 \ --authrpc.jwtsecret /path/to/jwt.hex \ --datadir /path/to/data \ --syncmode snap \ --maxpeers 50几个关键点说明一下:--http.corsdomain设为空,避免浏览器跨域请求被滥用;--authrpc是引擎API,用于共识层通信,同样只监听本地;--maxpeers限制对等节点数量,避免连接数被恶意占满。
6.2 Nginx反向代理配置模板
如果需要对外提供RPC,这份Nginx配置可以直接参考:
limit_req_zone $binary_remote_addr zone=rpc_per_ip:10m rate=10r/s; limit_req_zone $server_name zone=rpc_global:10m rate=200r/s; server { listen 443 ssl http2; server_name your-domain.example; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; ssl_protocols TLSv1.2 TLSv1.3; location /rpc { allow 203.0.113.10; allow 203.0.113.11; deny all; limit_req zone=rpc_per_ip burst=20 nodelay; limit_req zone=rpc_global burst=50 nodelay; auth_basic "RPC Access"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://127.0.0.1:8545; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 30s; } }这份配置同时做了IP白名单、双层限流、Basic认证和HTTPS加密。实际使用时把IP和域名换成你自己的即可。
6.3 防火墙规则模板
# 默认拒绝所有入站 sudo ufw default deny incoming sudo ufw default allow outgoing # 允许SSH(换成你自己的端口) sudo ufw allow 22/tcp # 允许P2P端口 sudo ufw allow 30303/tcp sudo ufw allow 30303/udp # 明确拒绝RPC端口 sudo ufw deny 8545/tcp sudo ufw deny 8546/tcp sudo ufw deny 8551/tcp sudo ufw enable这套规则的核心是默认拒绝,按需放行。RPC端口即使被误开,防火墙也会拦住。
7. 几个容易忽略的细节和我的实操心得
7.1 云服务商的安全组别忘配
很多人配了系统防火墙,却忘了云服务商还有一层安全组。安全组是在虚拟机外层的网络过滤,优先级往往高于系统防火墙。如果你在安全组里放行了8545,那系统防火墙再严也没用。所以配置的时候,两层都要检查。我一般会在安全组里只放行SSH和P2P端口,RPC端口一律不放行。
7.2 测试环境同样要加固
有人觉得测试节点无所谓,反正没资产。但测试节点被攻陷后,可能被当成跳板去攻击内网其他机器,或者被用来挖矿消耗你的云主机资源。所以测试环境也要按同样的标准加固,至少监听地址和防火墙规则要配好。
7.3 定期更新客户端版本
以太坊客户端会不定期发布安全更新,修复已知问题。我一般会关注客户端的发布页面,看到安全相关的更新就尽快升级。升级前先在测试环境验证,确认没问题再上生产。不要因为怕麻烦就一直用老版本,很多攻击就是针对已知问题来的。
7.4 别把RPC地址写进前端代码
有些DApp前端直接把RPC地址硬编码在JavaScript里,这样任何人打开浏览器开发者工具都能看到你的RPC地址。如果这个地址是对公网开放的,那就等于主动告诉别人"来打我这里"。正确做法是前端请求自己的后端,由后端去访问节点,节点地址不暴露给前端。
7.5 用独立的机器跑节点
如果条件允许,把节点跑在一台独立的机器上,和业务服务分开。这样即使节点被攻击,也不会直接影响到业务系统。节点机器只开放必要的端口,业务机器通过内网访问节点,整体安全性会高很多。
7.6 备份和恢复方案要提前准备
节点数据虽然可以从网络重新同步,但同步一次全节点可能要几天时间。所以定期备份关键数据(比如keystore、配置文件)是必要的。同时要准备好恢复流程,万一节点被攻击需要重建,能快速恢复服务。我自己的做法是每周备份一次keystore和配置,数据目录则根据磁盘情况定期快照。
8. 最后再分享一个小技巧
如果你只是本机开发用,其实还有一个更省事的办法:用SSH隧道。节点只监听127.0.0.1,远程机器通过SSH端口转发来访问。这样完全不需要对外暴露任何RPC端口,安全性最高。
# 在远程机器上执行,把本地8545转发到节点机器的8545 ssh -L 8545:127.0.0.1:8545 user@node-host执行后,远程机器上访问http://127.0.0.1:8545就等于访问节点机器的RPC。这种方式适合开发调试场景,简单又安全。生产环境如果有多台机器需要访问,还是建议用前面讲的Nginx反向代理方案,更便于统一管理和审计。
节点安全这件事,说到底就是最小暴露原则:能不开放就不开放,必须开放的就加访问控制,加了访问控制还要持续监控。我踩过的坑基本都在这篇笔记里了,希望你看完之后,至少能把监听地址从0.0.0.0改回127.0.0.1,这一步就能挡掉八成以上的麻烦。