前言
在UE项目开发中,经常需要访问远程服务器上的数据库、API或内网服务。直接暴露这些服务到公网存在安全风险,而SSH隧道(SSH Tunnel)提供了一种安全的解决方案:通过SSH加密通道转发本地端口到远程服务,既保证了数据传输的安全性,又避免了服务直接暴露。
本文将介绍SSH隧道的工作原理,以及如何在UE中实现这一功能。
SSH隧道的实现方式
调用系统SSH客户端
我们先来实现最简单的方式,那就是借助系统自带的SSH客户端:
Windows (使用OpenSSH客户端):
#include "GenericPlatform/GenericPlatformProcess.h"void CreateSSHTunnelByCommand(const FString& SSHHost,int32 SSHPort,const FString& Username,const FString& Password,int32 LocalPort,const FString& RemoteHost,int32 RemotePort)
{// 构建SSH命令// ssh -L LocalPort:RemoteHost:RemotePort Username@SSHHost -p SSHPortFString Command = FString::Printf(TEXT("ssh -L %d:%s:%d %s@%s -p %d -N"),LocalPort, *RemoteHost, RemotePort,*Username, *SSHHost, SSHPort);// 使用UE的进程管理启动SSHFProcHandle ProcHandle = FPlatformProcess::CreateProc(TEXT("C:/Windows/System32/OpenSSH/ssh.exe"),*Command,true, // bLaunchDetachedfalse, // bLaunchHiddenfalse, // bLaunchReallyHiddennullptr,0,nullptr,nullptr);// 保存进程句柄用于后续关闭if (ProcHandle.IsValid()){UE_LOG(LogTemp, Log, TEXT("SSH隧道已启动"));}
}// 关闭SSH隧道
void CloseSSHTunnel(FProcHandle& ProcHandle)
{if (ProcHandle.IsValid()){FPlatformProcess::TerminateProc(ProcHandle);FPlatformProcess::CloseProc(ProcHandle);}
}
这种方式的优缺点:
✅ 优点:
- 实现简单,几行代码就能完成
- 无需集成第三方库
- 利用系统自带SSH客户端
❌ 缺点:
- 依赖系统环境(需要预装SSH客户端)
- 无法在代码中输入密码(需要配置密钥或手动输入)
- 进程管理复杂,难以获取连接状态
- 跨平台兼容性差(Windows/Linux/Mac路径不同)
- 无法获取详细的错误信息
- 不适合打包发布(用户环境不可控)
集成SSH库
更可靠的方式是集成专业的SSH库。
这里选用开源的libssh2+OpenSSL的组合,需要两个关键库:
libssh2 — SSH协议实现
- 负责SSH连接建立
- 用户认证(密码/密钥)
- 端口转发功能
- 🔗 开源地址: https://github.com/libssh2/libssh2
- 📄 许可证: BSD 3-Clause
OpenSSL — 加密支持
- 提供底层加密算法
- 密钥交换
- 数据加密/解密
- 🔗 开源地址: https://github.com/openssl/openssl
- 📄 许可证: Apache 2.0
如何使用这两个库
集成libssh2到UE项目的基本步骤:
1. 编译库文件
首先需要为目标平台编译libssh2和OpenSSL的静态库:
# Windows平台需要编译出
libssh2.lib / libssh2.dll
libcrypto.lib / libcrypto.dll
libssl.lib / libssl.dll
2. 在.Build.cs中添加依赖
// 添加头文件路径
PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "libssh2", "include"));
PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "openssl", "include"));// 链接静态库
PublicAdditionalLibraries.Add(Path.Combine(ThirdPartyPath, "libssh2", "lib", "libssh2.lib"));
PublicAdditionalLibraries.Add(Path.Combine(ThirdPartyPath, "openssl", "lib", "libcrypto.lib"));
PublicAdditionalLibraries.Add(Path.Combine(ThirdPartyPath, "openssl", "lib", "libssl.lib"));// 运行时需要的DLL
RuntimeDependencies.Add("$(BinaryOutputDir)/libssh2.dll", Path.Combine(ThirdPartyPath, "libssh2", "bin", "libssh2.dll"));
3. 基本的libssh2使用流程
#include "libssh2.h"// 初始化libssh2
libssh2_init(0);// 创建会话
LIBSSH2_SESSION* session = libssh2_session_init();// 连接到SSH服务器(基于已有的Socket)
libssh2_session_handshake(session, socket);// 用户认证
libssh2_userauth_password(session, username, password);// 创建端口转发通道
LIBSSH2_CHANNEL* channel = libssh2_channel_direct_tcpip(session,remote_host, // 远程目标地址remote_port // 远程目标端口
);// 后续进行数据转发...// 清理资源
libssh2_channel_free(channel);
libssh2_session_disconnect(session, "Normal Shutdown");
libssh2_session_free(session);
libssh2_exit();
关键点:
- libssh2需要配合Socket使用,UE中可以用
FSocket - 端口转发需要在本地开启监听Socket接受连接
- 数据转发需要在独立线程中循环处理,避免阻塞主线程
- 所有libssh2操作都需要正确的错误处理和资源释放
两种方式对比
| 特性 | 调用系统SSH | 集成SSH库 |
|---|---|---|
| 实现难度 | 简单 | 复杂 |
| 环境依赖 | 需要系统SSH客户端 | 无依赖 |
| 密码认证 | 不支持(需手动输入) | 完全支持 |
| 状态监控 | 困难 | 完整支持 |
| 错误处理 | 无法获取详情 | 详细错误信息 |
| 跨平台 | 路径不一致 | 统一接口 |
| 打包发布 | 不可靠 | 可靠 |
| 适用场景 | 开发测试 | 生产环境 |
结论:
- 如果只是临时测试,调用系统SSH是最快的方式
- 如果要做成产品级功能,集成SSH库是唯一选择
一键解决方案
如果你需要开箱即用的SSH隧道功能,可以使用我开发的插件:
SimpleSSHTunnel — SSH隧道完整方案
- 基于libssh2 + OpenSSL实现
- 完整蓝图接口
- 支持UE 5.2-5.5
- 仅支持Windows平台(Linux/Mac可按需定制)
获取方式:
Epic Fab商城搜索 SimpleSSHTunnel 或 mengzhishanghun
致谢与开源库
本技术方案基于以下优秀的开源项目:
libssh2 — 成熟的SSH2协议客户端库
- 📦 项目地址: https://github.com/libssh2/libssh2
- 📄 许可证: BSD 3-Clause License
- 💡 功能: SSH连接、用户认证、端口转发
- 🙏 感谢libssh2团队提供如此优秀的SSH实现
OpenSSL — 行业标准的加密库
- 📦 项目地址: https://github.com/openssl/openssl
- 📄 许可证: Apache 2.0 License
- 💡 功能: SSL/TLS协议、加密算法
- 🙏 感谢OpenSSL项目为网络安全做出的贡献
使用这些库时请遵守相应的开源协议,并在项目中注明来源。
如果在使用中遇到问题,或需要定制功能(如密钥认证、Linux平台支持等),欢迎通过邮箱联系我。
📧 技术交流: mengzhishanghun@outlook.com
本文技术方案已在实际项目中验证,适用于开发/测试环境。生产环境请根据实际安全需求调整。