SSH隧道基础原理
SSH连接机制
SSH不仅仅是远程登录工具,更重要的是提供加密通信通道。当SSH客户端与服务端建立连接后:
- 客户端输入的命令(如
ls)被封装成加密数据包传输 - 服务端执行命令后,结果以同样的加密方式返回
- 防火墙只能看到SSH数据包,无法获知内部传输内容
端口与网络限制问题
实际场景中存在两大访问限制:
- 网络限制:客户端无法通过公网直接访问内网服务器
- 端口限制:
- SSH服务端默认监听
22端口 - 数据库默认监听
3306端口 - 如果服务器只开放特定端口,其他服务无法被外部访问
- SSH服务端默认监听
SSH本地隧道(Local Tunnel)
工作原理
利用已建立的SSH加密通道,让客户端通过跳板机访问内网服务:
- SSH客户端监听本地新端口(如
3307) - 本地应用连接
3307端口时,请求被拦截并通过SSH隧道转发 - 跳板机收到加密数据包后解密,转发给内网目标服务
- 返回数据同样通过加密通道回传
实操命令
基础语法:
ssh -L [本地地址:]本地端口:目标主机:目标端口 用户名@跳板机地址 -i 私钥路径
具体示例:
# 建立本地隧道,监听本地3307端口,转发到内网数据库3306端口
ssh -L 127.0.0.1:3307:<内网数据库IP>:3306 <用户名>@<跳板机IP> -i ~/.ssh/private_key
# 简化写法(省略本地IP,默认监听127.0.0.1)
ssh -L 3307:<内网数据库IP>:3306 <用户名>@<跳板机IP> -i ~/.ssh/private_key
# 不需要操作跳板机shell时,添加-N参数
ssh -L 3307:<内网数据库IP>:3306 <用户名>@<跳板机IP> -i ~/.ssh/private_key -N
# 后台运行,添加-f参数
ssh -L 3307:<内网数据库IP>:3306 <用户名>@<跳板机IP> -i ~/.ssh/private_key -N -f
使用隧道访问数据库:
# 连接本地3307端口,实际访问内网数据库
mysql -h 127.0.0.1 -P 3307 -u <数据库用户名> -p
安全注意事项
- 本地监听地址:建议明确指定
127.0.0.1,避免隧道暴露给局域网其他机器 - 私钥权限:确保私钥文件权限为
600或400chmod 600 ~/.ssh/private_key
管理后台隧道
查找后台运行的SSH隧道进程:
# Linux/Mac
ps aux | grep "ssh -L"
# Windows (Git Bash)
Get-Process ssh
关闭指定的隧道进程:
kill <进程ID>
配置要求
确保跳板机SSH配置文件/etc/ssh/sshd_config中:
AllowTcpForwarding yes
SSH远程隧道(Remote Tunnel)
应用场景
解决从公网服务器反向访问家用电脑的问题:
- 家用路由器通常屏蔽外部对
22端口的访问 - 家用电脑只有内网IP,无法被公网直接访问
工作原理
通过内网穿透实现反向连接:
- 从家用电脑主动向公网服务器建立SSH连接
- 同时建立远程隧道,让服务器监听指定端口
- 服务器通过该端口即可反向访问家用电脑
实操命令
# 从家用电脑执行,建立远程隧道
ssh -R 2200:localhost:22 <用户名>@<公网服务器IP> -i ~/.ssh/private_key
# 在公网服务器上验证端口监听
netstat -tlnp | grep 2200
# 或使用ss命令
ss -tlnp | grep 2200
# 从公网服务器访问家用电脑
ssh <家用电脑用户名>@localhost -p 2200
扩展配置
如需让其他公网机器也能通过服务器访问家用电脑,需在服务器SSH配置中设置:
GatewayPorts yes
⚠️ 安全警告:启用 GatewayPorts yes 会让远程隧道监听在 0.0.0.0(所有网络接口),这意味着任何能访问该服务器的机器都可以使用该隧道。建议:
- 仅在可信网络环境中使用
- 配合防火墙规则限制访问来源
- 或使用
GatewayPorts clientspecified让客户端自行指定监听地址
SSH动态隧道(Dynamic Tunnel)
解决的问题
本地隧道和远程隧道都是一对一的端口映射,存在以下限制:
- 访问多个服务需要建立多条隧道
- 可能出现端口冲突
- 需要预先知道目标IP和端口
- IP地址变化时需要重新配置
SOCKS5代理机制
动态隧道通过引入SOCKS5协议解决上述问题:
- 只需指定一个本地监听端口
- 该端口成为SOCKS5代理服务器
- 支持动态目标,无需预设IP和端口
- 任何支持SOCKS5的应用都可使用
实操命令
建立动态隧道:
# 监听本地1080端口,建立SOCKS5代理
ssh -D 127.0.0.1:1080 <用户名>@<服务器IP> -i ~/.ssh/private_key -N
# 后台运行
ssh -D 127.0.0.1:1080 <用户名>@<服务器IP> -i ~/.ssh/private_key -N -f
通过代理访问服务:
# 使用curl通过SOCKS5代理访问远程服务
curl --socks5-hostname localhost:1080 http://127.0.0.1:8001
curl --socks5-hostname localhost:1080 http://127.0.0.1:8002
# 配置浏览器使用SOCKS5代理
# 代理地址: 127.0.0.1
# 端口: 1080
动态隧道优势
- 灵活性:可访问远程服务器能访问的任意IP和端口
- 简单性:只需一条命令建立,无需多个端口映射
- 动态性:目标地址可以随时变化,无需重新配置隧道
安全注意事项
⚠️ 代理安全风险:
- SOCKS5代理会将所有流量通过SSH服务器转发,请确保:
- 仅在本地监听(
127.0.0.1),不要暴露给局域网 - 不要在不可信的公共网络上使用
- 注意服务器的流量使用和带宽限制
- 关闭不使用的代理隧道,避免被滥用
- 仅在本地监听(
实战环境配置
云服务器配置示例
跳板机配置:
- 具备公网IP地址
- 开放入站
22端口 - 与内网服务器处于同一网络
内网服务器配置:
- 仅有内网IP地址
- 开放特定服务端口(如MySQL的
3306) - 可被跳板机通过内网访问
常见问题排查
隧道无法建立:
- 检查服务器
/etc/ssh/sshd_config中的AllowTcpForwarding配置 - 确认SSH服务已重启:
sudo systemctl restart sshd
- 检查服务器
端口访问失败:
- 确认防火墙和安全组设置
- 检查端口是否被占用:
netstat -tlnp | grep <端口号>
权限问题:
- 验证SSH私钥权限:
ls -l ~/.ssh/private_key(应为 600 或 400) - 检查用户是否有权限访问目标服务
- 验证SSH私钥权限:
连接中断:
- 添加保活参数防止超时断开:
ssh -L 3307:<目标IP>:3306 <用户>@<服务器> -o ServerAliveInterval=60 -o ServerAliveCountMax=3
- 添加保活参数防止超时断开:
私钥权限错误:
# 错误提示:Permissions 0644 for 'private_key' are too open # 解决方法: chmod 600 ~/.ssh/private_key
总结
SSH隧道技术为网络访问提供了强大的解决方案,通过合理运用三种隧道类型,可以安全高效地解决各种网络连通性问题:
- 本地隧道:从本地访问远程内网服务
- 远程隧道:让远程服务器访问本地服务(内网穿透)
- 动态隧道:灵活的SOCKS5代理,支持动态目标
使用时务必注意安全配置,避免将隧道暴露给不可信的网络环境。
