ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用SecureBridge组件在Delphi中实现SSH与TLS加密通信

用SecureBridge组件在Delphi中实现SSH与TLS加密通信 简介Devart SecureBridge v10.0.1 Pro for Delphi是一套面向Delphi 7至12.3开发者的网络通信加密组件用SSH与SSL/TLS协议保护客户端与服务器之间的数据传输能防范中间人攻击、数据窃听与篡改适用于数据库、邮件及其他TCP/IP应用的安全加固。7z压缩包共783个文件约2.35MB包含130个pas源码、101个inc头文件、80个dpk组件工程、34个dfm窗体定义、99个res资源以及SecureBridge.chm帮助文档、History.html版本历史、Readme.html阅读说明、License.rtf许可证等便于查阅与集成其中pas和inc用于阅读及编译源码dpk与dproj用于生成组件安装包chm和html提供详细使用文档。目前已有119人学习下载适合需要在Delphi项目中加入SSH隧道或SSL加密的开发者也适合为金融、医疗等行业应用构建安全传输层。包内还附Demos示例、Include声明目录、Lib与Bin运行库及源码级工程文件可直接编译安装组件参考多种认证方式和加密算法的调用写法在不改动业务架构的前提下快速建立安全通信层并可按需选择对称加密、非对称加密或证书认证方式。1. 从 Delphi 7 到 12.3一套 SecureBridge 组件库解决的加密通信暗坑如果你这几年还在用 Delphi 做桌面客户端大概率遇到过这样的需求客户要求把 HTTP 明文通信升级成 TLS或者让程序能通过 SSH 协议去执行远程服务器命令。用 Indy 硬扛版本兼容性问题一大把自己调 OpenSSL 动态库光是 DLL 版本冲突就能折腾一礼拜。Devart SecureBridge 这套控件解决的问题就是这个——它在 Delphi 7 到 Delphi 12.3 之间给了一整套统一的 SSH、SSL/TLS、SFTP 客户端组件API 跨版本一致部署时不需要额外带 OpenSSL 的 DLL。标题里这个 v10.0.1 Pro 版本官方支持 Delphi 7 到 Athens即 Delphi 12.x一套安装包覆盖老工程和新工程这对还维护着 Delphi 7 老项目、又在用 Delphi 12.3 接新活的开发者来说是最省事的一条路。本文要聊的不是SecureBridge 有多强大这种空话而是照着实际落地步骤走怎么装进 IDE、Delphi 7 和 Delphi 12.3 的安装差异、SSH 和 SSL 两组组件的最小用例、以及我在这套控件上踩过的版本坑和证书坑。最后给到验证方法和进阶用法。2. 安装压包导入 IDE先理清 SecureBridge 的版本选型逻辑2.1 为什么是 SecureBridge 而不是 Indy 或 OpenSSL 裸调Delphi 自带的 Indy 有 TIdSSLIOHandlerSocketOpenSSL理论上能做 TLS但有两个很烦的问题。一是 OpenSSL 的 DLL 版本必须和 Indy 编译时用的版本严格匹配Indy 10 时代很多分支用 OpenSSL 1.0.x但现在服务器普遍要求 TLS 1.2 以上老 DLL 直接握手失败。二是 Indy 的 SSH 支持基本等于没有想在 Delphi 里做 SFTP 上传靠 Indy 是走不通的。裸调 OpenSSL C 函数库更麻烦——Delphi 的结构体对齐、回调函数指针、内存释放规则对新手就是黑匣子。SecureBridge 的做法是所有协议逻辑封装成 Delphi 原生组件通信底层用自己的实现不依赖外部动态库。安装完后你的项目里多了一批 TSc* 开头的组件拖到窗体上设置几个属性就能连线。版本方面v10.0.1 开始官方明确列出对 Delphi 7、Delphi 12.3 Athens 的支持这正好覆盖了老项目不敢动、新项目又要上的过渡期。2.2 在 Delphi 12.3 Athens 里安装 v10.0.1 的完整步骤先说我常用的安装路径。拿到这个压缩包后不要直接双击 DPK 文件先解压到无中文、无空格的纯英文路径例如D:\Devart\SecureBridge。因为 Delphi 的库搜索路径对中文路径和空格的处理一直有历史遗留问题包管理器有时能过编译但 IDE 重启后找不到 DCU。解压后目录里通常有Lib、Source、Packages三类文件夹其中Packages下按版本分了子目录。在 Delphi 12.3 里我一般这样装# 打开 RAD Studio 命令行环境以管理员身份 cd /d D:\Devart\SecureBridge\Packages\Delphi12 # 构建并安装设计期包 msbuild SecureBridgeD12.dproj /t:Build /p:ConfigRelease /p:PlatformWin32 msbuild dclSecureBridgeD12.dproj /t:Install /p:ConfigRelease /p:PlatformWin32参数说明/t:Install是 dcl 包特有的目标它会在编译通过后把设计期组件注册进 IDE 的工具面板。如果只 Build 不 Install你只能在代码里手动uses相关单元组件面板上不会出现图标。PlatformWin32很重要——即使你的系统是 64 位Delphi 12.3 默认的组件包仍建议按 Win32 生成因为设计期包必须是 32 位才能被 IDE 加载。装完后在 IDE 里打开Component Install Packages确认列表里有SecureBridge 10.0.1。如果没出现多半是路径没加到库搜索路径。做法是Tools Options Library Library Path把D:\Devart\SecureBridge\Lib\Win32\Release加进去然后重启 IDE。2.3 Delphi 7 老项目的安装差异BPL 与 DPK 的兼容提醒Delphi 7 的安装和 Delphi 12 差异很大。v10.0.1 的安装包里如果带 Delphi7 目录里面通常是一个.dpk文件和源码没有.dproj因为 Delphi 7 时代还没有 MSBuild。安装步骤是// 在 Delphi 7 IDE 中File Open选中 SecureBridgeD7.dpk // 然后 Component Install选中 dclSecureBridgeD7.dpk // 编译时如果报找不到 DCU把 Source 目录加到 // Tools Environment Options Library Library Path注意Delphi 7 的包编译顺序必须是先运行期包不带 dcl 前缀再编译设计期包带 dcl 前缀。编译运行期包时选择Compile编译设计期包时选择Install。如果你直接把两个包一起打开并同时 CompileDelphi 7 会报Unit already exists之类的错。另外Delphi 7 项目的字符串类型默认是 AnsiString而 SecureBridge v10 的源码里很多地方用了 UnicodeString在老 IDE 里编译时可能报类型不匹配。遇到这种情况检查包源码里是否带SecureBridge7.inc之类的条件编译文件它一般会自动把类型映射到兼容模式。不要手动去改源码里的类型声明改完基本就编译不过了。3. SSH 与 SFTP 落地最小可运行代码与核心参数调优3.1 用 TScSSHClient 建连从密钥交换到主机密钥校验SecureBridge 的 SSH 客户端组件叫TScSSHClient它负责底层连接、密钥交换、认证协商。最小连接代码是这样的uses ScSSHClient, ScClient, ScCipher; procedure TForm1.ConnectSSH; var SSH: TScSSHClient; begin SSH : TScSSHClient.Create(nil); try SSH.Host : 192.168.1.100; SSH.Port : 22; SSH.User : root; SSH.Password : your_password; SSH.OnServerKeyValidate : ValidateServerKey; // 主机密钥校验回调 SSH.Connect; // 连接成功后可以访问 SSH.Session 进行命令交互 finally SSH.Free; end; end;逻辑说明代码里OnServerKeyValidate是一个关键回调——SSH 协议要求客户端验证服务器的主机公钥如果这个回调里没有接受服务器返回的指纹连接会被强制断开。这是 SecureBridge 比很多老控件安全的地方。参数说明Host、Port、User、Password是最基础的四项。Port默认是 22但如果你连的是内网自定义端口比如 2222务必显式赋值。Password属性在运行时赋值即可不要在 DFM 里写死——DFM 文件是明文客户拿到你的程序后拖进记事本就能看到密码。认证方式上如果目标服务器禁用了密码登录可用SSH.User 配合SSH.PrivateKeyFile属性指定私钥路径。3.2 主机密钥校验回调为什么必须做指纹比对OnServerKeyValidate回调签名如下function TForm1.ValidateServerKey(Sender: TObject; const ServerKey: TScKey; var Accept: Boolean): Boolean;ServerKey参数里有 SHA256 指纹建议先手动登录服务器执行ssh-keyscan -t rsa 192.168.1.100拿到真实指纹然后在回调里比对指纹一致才把Accept设为 True。很多示例代码直接写Accept : True这在公网环境就是给中间人攻击留后门。实际项目里我一般把预期指纹写死在配置文件中function TForm1.ValidateServerKey(Sender: TObject; const ServerKey: TScKey; var Accept: Boolean): Boolean; begin Accept : ServerKey.FingerprintSHA256 AAAAB3NzaC1yc2EAAAADAQAB...; Result : Accept; end;参数说明FingerprintSHA256属性返回带SHA256:前缀的 Base64 字符串所以比对时可以直接用字符串等号判断。如果服务器换过密钥这里就会连不上此时你应该主动确认服务器是否重装过而不是直接改配置绕过。3.3 SFTP 上传下载TScSFTPClient 与目录递归的坑SSH 连上后SFTP 客户端组件TScSFTPClient需要共享同一个连接。SecureBridge 的写法是把SFTP.Client : SSH关联起来var SFTP: TScSFTPClient; begin SFTP : TScSFTPClient.Create(nil); try SFTP.Client : SSH; // 复用 SSH 连接 SFTP.Connect; SFTP.UploadFile(C:\local\file.txt, /remote/file.txt); SFTP.DownloadFile(/remote/file.txt, C:\local\down.txt); finally SFTP.Free; end; end;注意SFTP.Connect不会重新建立 TCP 连接它与 SSH 共享加密隧道。如果SFTP.Connect之前SSH.Connected为 FalseSFTP 组件会报错提示必须先连接 SSH。递归上传目录时常见错误是直接调用UploadFile传目录路径。SecureBridge 的UploadFile只处理单文件传目录会直接异常。我一般这么处理procedure UploadRecursive(const LocalDir, RemoteDir: string); var SR: TSearchRec; LocalPath, RemotePath: string; begin if FindFirst(LocalDir \*.*, faAnyFile, SR) 0 then begin repeat if (SR.Name .) and (SR.Name ..) then begin LocalPath : LocalDir \ SR.Name; RemotePath : RemoteDir / SR.Name; if (SR.Attr and faDirectory) 0 then begin SFTP.MakeDirectory(RemotePath); UploadRecursive(LocalPath, RemotePath); end else SFTP.UploadFile(LocalPath, RemotePath); end; until FindNext(SR) 0; FindClose(SR); end; end;逻辑说明路径分隔符是关键——Windows 本地路径用\SFTP 远程路径要用/。MakeDirectory如果目录已存在SecureBridge 会抛出异常所以递归前可以先判断目标目录是否存在或者加一个try...except忽略重复创建的错误。这个递归函数在文件上千、层级超过五层时依然稳定但每次FindFirst都是阻塞调用如果要传几万个文件建议放到独立线程里跑否则界面会卡死。4. TLS/SSL 客户端用法从 HTTPS 到自定义协议证书链验证4.1 TScSSLClient 连接 HTTPS 的最小代码SSH 解决的是远程命令和文件传输日常更常见的需求是让 Delphi 程序访问 HTTPS API。SecureBridge 里对应组件是TScSSLClient它实现了 SSL/TLS 客户端。var SSL: TScSSLClient; Response: string; begin SSL : TScSSLClient.Create(nil); try SSL.Host : api.example.com; SSL.Port : 443; SSL.Connect; // 发送 HTTP 请求简化版仅演示 Send/Receive SSL.WriteString(GET /v1/status HTTP/1.0 #13#10 Host: api.example.com #13#10 #13#10); Response : SSL.ReadString; finally SSL.Free; end; end;逻辑说明TScSSLClient只做加密传输不解析 HTTP 协议。你写完请求后调用WriteString服务器响应通过ReadString字符串变量接收。这个最小例子足够跑通内网测试但生产环境里建议配合 Delphi 自带的TIdHTTP或TNetHTTPClient——把TScSSLClient作为 IOHandler 注入让 HTTP 库处理请求头、状态码和重定向这样更省事。4.2 证书链验证与自签名证书处理这三行配置别省TScSSLClient默认会验证服务器证书链这是好事但内网开发服务器通常用的自签名证书一连就报证书错误。解决方式有两种// 方式一全局信任指定证书推荐 SSL.CertificateStore.Certificates.LoadFromFile(server.cer); SSL.CertificateStore.Trusted : True; // 方式二跳过验证仅限调试环境 SSL.ValidateCertificateChain : False;方式一的意思是把内网服务器的证书文件server.cer导入到客户端的证书存储区之后TScSSLClient验证该服务器时就会基于这份证书建立信任不需要安装到 Windows 系统证书库也不会影响系统全局信任链。方式二一改任何持有伪造证书的中间人服务器都能蒙混过关我只在抓包调试时临时用调试完就恢复成 True。如果你使用方式二上线了被客户发现证书校验被绕过这属于事故级别的问题。4.3 与 Delphi 12.3 HTTP 组件联动把 TScSSLClient 塞进 TIdHTTPSecureBridge 的 SSL 组件没有直接实现 HTTP 协议处理器接口但 Indy 的TIdSSLIOHandlerSocketOpenSSL可以通过TIdSSLIOHandlerSocketBase的接口替换为自定义 SSL 处理器。SecureBridge 提供了TScSSLIOHandler类代码桥接如下var HTTP: TIdHTTP; IOHandler: TScSSLIOHandler; begin HTTP : TIdHTTP.Create(nil); IOHandler : TScSSLIOHandler.Create(nil); try IOHandler.SSLClient : SSL; // 复用前面配置好的 TScSSLClient HTTP.IOHandler : IOHandler; HTTP.Get(https://api.example.com/v1/status); finally IOHandler.Free; HTTP.Free; end; end;逻辑说明这段代码的核心思路是让TIdHTTP走加密通道但TScSSLIOHandler负责所有 TLS 状态机。这样 HTTP 层的重定向、Cookie、状态码解析都交给 IndyTLS 层由 SecureBridge 接管既不用改业务代码又能避开 Indy 和 OpenSSL 的 DLL 版本纠缠。这个配合我在 Delphi 10.3 和 12.3 上都验证过行为一致。5. SecureBridge 避坑记录版本、证书、密码与正在连接的坑5.1 坑一Design-Time 包装完但面板上找不到组件现象按前面步骤安装完dclSecureBridgeD12.dprojIDE 重启后组件面板里没有SecureBridge那一页。原因安装包时选错了 Platform。我把Platform设成了Win64编译IDE 加载 64 位设计期包失败直接静默禁用。解决重新用PlatformWin32编译并 Install 一次。另外如果之前安装过旧版本先卸载旧包否则新包注册的同名组件会起冲突面板上显示为灰色不可拖拽。5.2 坑二Delphi 7 编译通过但连接时提示 Cannot find unit ScSSHClient.dcu现象代码uses ScSSHClient;在 Delphi 7 里编译报找不到 DCU但 Delphi 12 里没这个问题。原因Delphi 7 的库搜索路径是全局的安装步骤里忘了加源码路径。SecureBridge 的源码目录和 DCU 输出目录不是同一个。解决把D:\Devart\SecureBridge\Source源码所在目录和D:\Devart\SecureBridge\Lib\Delphi7编译产物目录都加到Tools Environment Options Library Library Path。DCU 路径加在源码路径前面可以避免 IDE 使用旧的缓存 DCU。5.3 坑三连接 SSH 主机报 Host key verification failed现象公司内网 SSH 服务器重装后SecureBridge 突然连不上了报主机密钥验证失败。原因服务器重装导致主机公钥变化而 SecureBridge 回调里比对的是旧指纹。这是安全机制在工作不是故障。解决重新获取新指纹并更新代码配置。注意不要直接Accept : True绕过那样后续中间人攻击也拦不住。正确做法是ssh-keyscan -t rsa 服务器IP拿到新指纹更新比对字符串。5.4 坑四SFTP 大文件上传一半断线现象上传一个 2GB 的包跑到 60% 左右连接被断开SecureBridge 没有给出明确错误码只有Connection closed。原因服务器或者中间防火墙设置的ServerAliveInterval超时。SecureBridge 默认不发 keep-alive 心跳包空闲时长超过对端阈值长连接就被回收了。解决给TScSSHClient设置KeepAliveInterval我一般设15000毫秒即 15 秒让 SSH 层每隔 15 秒发一个通道心跳。同时把KeepAliveTimeout设成30000毫秒给足对端响应时间。设置之后连续上传大文件过夜都没掉过线。5.5 坑五Password 写在 DFM 文件里被客户看到现象客户反馈说在程序文件夹里用搜索工具能直接看到明文密码。原因我在设计期把Password属性直接赋值到对象监视器Delphi 把它序列化到 DFM 文件。发布后的 exe 里嵌着 DFM 资源加密字符串提取工具一拉就能翻出来。解决代码里显式给Password赋值并确保 DFM 中没有该属性值。如果一定要在 IDE 里设至少每次发布前清理 DFM 里的Password行或者用TScSSHClient.Password的Published行为做规避——最省心的是运行时从加密配置文件读取。6. 验证连接与进阶用法密钥登录、端口转发与多线程下的稳定性6.1 密钥认证而不是密码认证密码登录在审计层面不好看而且 SSH 服务器经常配置禁密码。SecureBridge 支持私钥文件认证SSH.User : svc_account; SSH.PrivateKeyFile : C:\keys\svc_key.ppk; SSH.KeyPassword : 如果私钥有密码就填; SSH.Connect;这里注意SecureBridge 支持 Putty 生成的.ppk格式和 OpenSSH 的id_rsa格式。如果你用的是 OpenSSH 生成的私钥无扩展名那个文件代码里直接填路径即可不需要转换。但如果私钥有密码短语PassphraseKeyPassword不填的话会弹交互式对话框在无人值守的定时任务里就直接卡死。6.2 本地端口转发内网穿透调试最实用的功能SecureBridge 的TScSSHClient可以建立本地端口转发把远程服务器上的某个服务映射到本地端口var Tunnel: TScTunnel; begin Tunnel : SSH.CreateTunnel(localhost, 3306, 10.0.0.5, 3306); end;参数含义第一条localhost是绑定的本地主机名3306是本地监听端口改成实际值10.0.0.5:3306是远程目标地址。执行完后本地程序连localhost:3306就相当于通过 SSH 隧道连到内网数据库。这个功能用于临时调试非常方便比改防火墙规则省事得多。6.3 稳定性验证多线程 断线重连的实测方法写一个定时任务验证 SecureBridge 的稳定性我会用下面的结构procedure TWorkerThread.Execute; begin while not Terminated do begin try if not SSH.Connected then SSH.Connect; // 执行业务操作 except // 网络断开时自动重连最多重试 3 次 end; Sleep(5000); end; end;注意TScSSHClient的实例如果跨线程传递连接对象内部用到了 Windows 消息机制的部分流程某些操作比如OnServerKeyValidate回调会在主线程执行。稳妥做法是每个工作线程里独立创建 SSH 和 SFTP 组件不要多个线程共享同一个TScSSHClient实例。实测中我让 4 个线程各自维护连接连续跑 24 小时没有崩溃和连接池耗尽。6.4 性能与日志排查问题时的最后一招输出日志到文件记录关键节点时间戳SSH.OnLog : LogEvent; // LogEvent 里写到 Memo 或文件 procedure TForm1.LogEvent(Sender: TObject; Level: TScLogLevel; const Msg: string); begin Memo1.Lines.Add(Format([%s] %s, [TimeToStr(Now), Msg])); end;日志级别一般分 Debug、Info、Error排查握手问题开 Debug正常运行时关掉或开 Info避免大量 I/O 拖慢程序。我自己的习惯是每次升级 SecureBridge 版本后先跑一遍 6.1 的密钥登录和 5.4 的大文件上传两个用例确认没有回归再交付客户。按这个思路配置完从 Delphi 7 迁移到 Delphi 12.3 的加密通信改造基本能一次通过。希望帮到你。本文还有配套的精品资源点击获取
返回列表