FRP/花生壳内网穿透SSH安全加固:5分钟搞定公网IP限制与密钥登录
最近和几个运维朋友聊天,发现一个挺普遍的现象:很多中小团队为了远程维护方便,用FRP或者花生壳把内网机器的SSH端口映射到了公网。这本是个省事的法子,但没过多久,服务器就莫名其妙地卡顿,一查日志,好家伙,全是来自全球各地的SSH暴力破解尝试。我自己也踩过这个坑,一台测试机因为密码设得简单了点,不到一周就被扫成了“矿机”,清理起来那叫一个麻烦。所以,今天我们不谈那些复杂的安全架构,就聚焦两个最直接、最有效,而且五分钟内就能落地的加固方案,帮你把暴露在公网上的SSH风险降到最低。
对于运维来说,时间就是金钱。我们没空去研究每一层安全协议,但必须堵住最明显的漏洞。这篇文章就是为你准备的,如果你正用着FRP或花生壳,并且担心SSH端口被扫,那么接下来的内容会像一份清晰的“操作清单”,照着做,安全水位立刻就能提升一个档次。
1. 理解风险:为什么内网穿透的SSH格外危险?
把SSH服务通过内网穿透暴露出去,和你直接把服务器放在公网上,面临的威胁模型其实不太一样,但危险程度一点不低。很多人有个误解,觉得“反正前面有穿透服务挡着,攻击者看不到我真实的服务器”。这个想法很危险。
穿透服务成了“单点暴露”。无论是FRP的服务端(公网服务器),还是花生壳的转发节点,都成为了一个公开的入口。攻击者扫描的是这个入口的IP和端口。一旦他们开始尝试爆破,所有的登录尝试流量都会通过这个入口,原封不动地转发到你的内网机器上。从你的内网服务器视角看,这些攻击流量可能全部来自于同一个“内网IP”——也就是FRP客户端或花生壳终端的地址。这会让一些基于源IP的简单防护策略失效,因为你无法直接区分“正常的穿透流量”和“恶意的攻击流量”。
日志里会频繁出现类似下面的记录,源IP却可能始终是192.168.1.100(你的穿透客户端IP):
sshd[12345]: Failed password for invalid user admin from 192.168.1.100 port 56789 ssh2 sshd[12346]: Failed password for root from 192.168.1.100 port 56790 ssh2攻击者正在用庞大的密码字典,通过这个唯一的入口,对你的服务器进行“盲打”。他们不在乎IP是否被记录,因为穿透服务帮他们“隐藏”了真实的攻击源。
注意:这种持续不断的扫描不仅带来安全风险,还会消耗服务器资源(CPU、内存用于处理SSH连接),并填满你的认证日志,影响问题排查。
所以,我们的加固思路必须围绕这个特点展开:
- 在入口处设卡:既然攻击都从一个“门”进来,我们就在这个门上加把最结实的锁,甚至只允许特定的“钥匙”来开。
- 提升认证强度:把那个容易被猜的“密码锁”换成几乎无法伪造的“指纹锁”。
下面,我们就从这两个维度,给出具体的操作指南。
2. 第一道防线:精确限制公网访问来源
最理想的情况是,只有你信任的IP地址才能连接到你的穿透服务端口。这对于有固定办公网络或云服务器作为跳板机的团队来说,是性价比最高的方案。
2.1 方案选择:防火墙 vs. 穿透服务本身
你需要根据使用的穿透工具,决定在哪里实施限制:
- 使用FRP:你拥有公网服务器的完全控制权。最佳实践是在FRP服务端所在的公网服务器上配置防火墙规则。因为攻击流量在到达你的内网机器之前,在这里就被拦截了,对后端零消耗。
- 使用花生壳(免费版):你无法控制花生壳的转发节点。因此,限制必须在你的内网服务器上实施。但由于所有流量源IP都是花生壳客户端IP,传统的IP限制意义不大,此时重点应放在第二部分的密钥认证上。花生壳付费版可能提供IP白名单功能,可直接在服务端配置。
这里我们主要讲解FRP场景下,在公网服务器上的操作。内网服务器的防火墙配置逻辑类似,但目标IP是固定的穿透客户端IP。
2.2 使用 iptables 实施IP白名单
iptables是Linux系统最强大的防火墙工具。我们来设置一个规则:只允许特定IP(比如你的公司公网IP203.0.113.10和你的家庭IP198.51.100.20)访问FRP服务端上映射SSH的端口(假设为60022)。
首先,清除旧规则(谨慎操作,最好在本地终端操作,避免把自己关在外面):
# 查看现有规则,确认你的SSH管理端口(通常是22)没有被影响 sudo iptables -L -n --line-numbers # 为FRP的SSH映射端口60022设置规则 # 1. 默认拒绝所有对60022端口的输入 sudo iptables -A INPUT -p tcp --dport 60022 -j DROP # 2. 允许特定IP访问60022端口 sudo iptables -I INPUT -p tcp -s 203.0.113.10 --dport 60022 -j ACCEPT sudo iptables -I INPUT -p tcp -s 198.51.100.20 --dport 60022 -j ACCEPT规则顺序很重要。-I表示插入到链的顶部,-A表示追加到链的底部。上面的命令先插入了两条允许规则,然后追加了一条拒绝所有规则。这样,只有来自白名单IP的流量会被允许,其他一律拒绝。
为了让规则永久生效,你需要保存它们。在Ubuntu/Debian上通常使用iptables-persistent:
sudo apt-get install iptables-persistent -y sudo netfilter-persistent save在CentOS/RHEL 7+上,可以使用:
sudo iptables-save > /etc/sysconfig/iptables # 或 sudo service iptables save2.3 使用 fail2ban 进行动态封禁
如果你的访问IP不固定(比如需要移动办公),或者想有一个更智能的防护层,fail2ban是绝佳选择。它监控日志文件,当发现同一个IP在短时间内有多次失败登录尝试时,自动将其加入防火墙黑名单一段时间。
安装与配置:
# Ubuntu/Debian sudo apt-get update && sudo apt-get install fail2ban -y # CentOS/RHEL sudo yum install epel-release -y sudo yum install fail2ban -yfail2ban的配置通常放在/etc/fail2ban/jail.local来覆盖默认设置。我们为SSH创建一个监控策略,但关键是要监控FRP服务端的系统日志,还是内网服务器的SSH日志?
- 监控FRP服务端日志:如果攻击者在FRP服务端层面就被
iptables白名单挡住了,他们连登录尝试都不会产生,fail2ban可能无用武之地。但可以监控FRP服务端本身的异常连接。 - 监控内网服务器SSH日志(推荐):这是防御的第二层。即使攻击流量通过了FRP,在内网服务器认证失败时,
fail2ban可以识别出恶意IP(虽然显示为穿透客户端IP),并通知FRP服务端封锁该端口上的后续连接。这需要更复杂的联动配置。
一个更简单的思路是,在内网服务器上安装fail2ban,直接保护SSH服务。虽然源IP固定,但fail2ban可以针对“对同一用户的大量失败尝试”进行封禁,仍然有效。
内网服务器上配置/etc/fail2ban/jail.local:
[sshd] enabled = true port = ssh # 注意日志路径可能不同 logpath = /var/log/auth.log maxretry = 5 bantime = 3600 findtime = 600这个配置表示:在10分钟(600秒)内,如果同一IP有5次失败认证,则禁止其1小时(3600秒)。重启服务生效:
sudo systemctl restart fail2ban sudo systemctl enable fail2ban你可以用以下命令查看封禁状态:
sudo fail2ban-client status sshd3. 第二道防线:彻底禁用密码,强制密钥登录
如果说IP限制是“锁门”,那么密钥登录就是给门换了一把几乎无法撬开的锁。这是防止暴力破解最根本、最有效的方法。
3.1 生成SSH密钥对
首先,在你的本地办公电脑(不是服务器)上生成密钥对。推荐使用更安全的Ed25519算法,它比传统的RSA更快速、更安全。
ssh-keygen -t ed25519 -C "your_email@example.com"执行命令后,你会被提示输入密钥的保存路径(默认~/.ssh/id_ed25519)和密码短语(passphrase)。强烈建议设置一个强密码短语,这为你的密钥又加了一层保护。生成后,你会得到两个文件:
id_ed25519:私钥,必须像保护密码一样严格保密,绝不传输。id_ed25519.pub:公钥,可以放心地放到服务器上。
3.2 部署公钥到服务器
将公钥上传到需要登录的内网服务器。最简单的方法是使用ssh-copy-id命令:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your_internal_server_ip -p 22如果服务器SSH端口不是22,请替换-p后的端口号。这条命令会自动将你的公钥内容追加到服务器对应用户家目录下的~/.ssh/authorized_keys文件中。
你也可以手动操作:
- 将公钥内容复制到剪贴板。
- 登录服务器,确保
~/.ssh目录存在且权限为700,~/.ssh/authorized_keys文件存在且权限为600。 - 将公钥内容粘贴到
authorized_keys文件的末尾。
3.3 配置SSH服务端强制使用密钥登录
这是关键步骤。编辑内网服务器上的SSH服务端配置文件/etc/ssh/sshd_config。
sudo nano /etc/ssh/sshd_config找到并修改以下参数:
# 禁用密码认证 PasswordAuthentication no # 启用公钥认证 PubkeyAuthentication yes # 可选:禁止root用户直接登录(根据需求调整) PermitRootLogin no # 可选:指定允许登录的用户,增加一层限制 AllowUsers your_username警告:在应用此配置并重启SSH服务之前,请务必在另一个已保持连接的SSH会话中测试密钥登录是否成功。确保你不会因为配置错误而把自己锁在服务器外面。
测试密钥登录:
ssh -i ~/.ssh/id_ed25519 user@your_internal_server_ip确认可以无密码(或输入密钥密码短语后)登录成功后,再重启SSH服务使配置生效:
sudo systemctl restart sshd # 或 sudo service sshd restart3.4 处理常见的密钥格式问题
有时候,从其他平台(如PuTTY、Windows)生成的密钥格式可能与OpenSSH不兼容。这里提供两个常见的转换命令:
- 将PuTTY私钥(.ppk)转换为OpenSSH格式:你需要使用PuTTY附带的
puttygen工具进行转换。 - 将OpenSSH私钥转换为PuTTY格式:同样使用
puttygen工具加载OpenSSH私钥然后保存为.ppk。 - 处理“Load key ".ssh/id_rsa": invalid format”错误:这通常是因为私钥文件的格式或权限不对。确保文件权限是600,并且是正确的OpenSSH格式。如果是PEM格式的RSA密钥,OpenSSH通常也能识别。
一个有用的检查命令是:
ssh-keygen -l -f ~/.ssh/your_private_key它能显示密钥的指纹,并验证密钥文件是否有效。
4. 进阶组合策略:按来源区分认证方式
对于更复杂的场景,比如希望内网用户图方便用密码,而来自公网穿透的连接必须用密钥,SSH提供了强大的Match指令。这正是应对我们开头提到的“所有穿透流量来自同一IP”场景的利器。
假设你的FRP客户端或花生壳终端在内网的IP是192.168.1.100。你可以这样配置/etc/ssh/sshd_config:
在文件末尾添加:
# 匹配来自穿透客户端的连接 Match Address 192.168.1.100 # 对这些连接强制使用公钥认证,禁用密码 PasswordAuthentication no PubkeyAuthentication yes # 可以进一步限制允许的用户 AllowUsers admin_user # 以下为全局默认配置(针对其他内网IP) PasswordAuthentication yes PubkeyAuthentication yes这个配置实现了:
- 当连接来自
192.168.1.100时,执行Match块内的严格规则。 - 其他内网地址的连接,则使用相对宽松的全局配置。
配置完成后,同样需要重启sshd服务。你可以从内网另一台机器(非192.168.1.100)用密码登录测试,再从192.168.1.100(或通过公网穿透)用密钥登录测试,验证策略是否生效。
重要提示:此方法依赖于穿透客户端IP的稳定性。如果该IP是DHCP动态获取的,可能会变。务必在路由器上为该设备设置静态IP绑定(DHCP保留),否则IP一变,规则失效,可能导致所有公网连接被拒。
5. 加固后的监控与维护
安全不是一劳永逸的。实施上述措施后,建立简单的监控习惯至关重要。
- 定期检查认证日志:尽管攻击被阻挡,扫描尝试不会停止。定期查看
/var/log/auth.log或/var/log/secure,可以了解攻击态势,确认你的规则是否有效。# 查看最近的失败登录尝试 sudo grep \"Failed password\" /var/log/auth.log | tail -20 # 查看被fail2ban封禁的IP sudo fail2ban-client status sshd - 更新与备份:定期更新服务器系统和SSH软件包以修复安全漏洞。备份你的SSH私钥和服务器上的
sshd_config文件。 - 密钥管理:团队成员离职时,务必从其服务器的
authorized_keys文件中移除对应的公钥。考虑使用更集中的密钥管理方案(如证书认证)来应对多人团队的需求。
我自己的几台服务器在应用了“IP白名单+密钥登录”组合拳之后,auth.log里清静了非常多,从每天成千上万条失败记录降到几乎为零。CPU的“无缘无故”高负载也再没出现过。这套组合实施起来真的很快,核心操作就是几条命令和一次配置文件修改,但对于安全性的提升是立竿见影的。如果你还在为公网SSH的安全问题头疼,不妨现在就花上五分钟,把这两件事给办了。