ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Delphi 13.1集成SecureBridge:SSH/SFTP组件安装与避坑指南

Delphi 13.1集成SecureBridge:SSH/SFTP组件安装与避坑指南 简介SecureBridge v11.0.1 专业版是面向 Delphi 与 CBuilder 开发者的网络通信安全组件库基于 SSH/SSL 协议提供数据加密、身份验证和授权机制可嵌入桌面、数据库、Web 及移动应用开发流程解决网络传输中的安全防护问题适合需要高强度通信加密的中高级程序员。压缩包内共 938 个文件大小约 2.86MB涵盖 153 个 Pascal 源码、123 个 inc 头文件、86 个 dpk 工程文件、51 个 dfm 窗体文件以及 Demos 示例、Lib 库、Include 头文件、界面图标和配置脚本等另附 HTML/CHM 帮助文档、安装说明图、许可协议与编译脚本目录结构清晰便于用于组件编译和项目集成。目前已有 33 人学习下载。从源码到示例再到库文件这套资料提供了完整的 SecureBridge 使用链路。开发者既可查阅 Pascal 源码理解加密流程也可运行 Demos 工程快速上手还能利用 Lib 与 Include 完成本地编译减少自行排查环境的时间成本。对于计划在 Delphi 项目中引入 SSH/SSL 安全通信的团队或个人是一份实用性较高的参考包。1. 一个压缩包解决 Delphi 的 SSH/SFTP 缺口前些天客户让 Delphi 程序定时把报表推到内网 Linux 服务器我打开组件面板翻了半天发现引入的 Indy 自带的 SSH 组件根本顶不上用。正当我以为又要用 plink.exe 拉起命令行打工时想起了这个在很多 Delphi 开发者硬盘里躺了很久的压缩包Devart SecureBridge v11.0.1 Professional。它解决的就是这样一件事给 Delphi 13.1RAD Studio 13.1装上一整套 SSH、SFTP、SCP 和端口转发控件装完之后 IDE 组件面板会多出一页从 TScSSHClient 到 TScSFTP 齐全了。你不用再维护外部命令行、解析 stdout、跟不同编码搏斗直接在 Object Pascal 里写连接、传文件、做隧道。这篇按我实际装机和排障的顺序来为什么选它、从 .7z 装进 IDE 面板怎么做、第一段能跑的密码认证代码怎么写以及那几个躲不开的坑。2. 为什么是 SecureBridgeSSH 组件选型要看的 4 个硬指标2.1 原生 Indy 的 SSH 为什么没法直接拿来用很多 Delphi 老用户的第一反应是“Indy 里不是有 TIdSSH 和 TIdSFTP 吗”。确实有但你在 Delphi 13.1 里把 TIdSSH 拖到窗体上再翻一下它的实现会发现这只是一个能碰运气握手的实验组件。Indy 10 的 SSH 协议栈对 SSH2 的支持非常浅比如 KEXINIT 阶段只实现了有限的密钥交换算法现代 OpenSSH 服务器普遍默认的 curve25519-sha256 它处理不了连接就那么卡在协商阶段不抛异常也不返回活脱脱一个黑匣子。其次是 SFTP 通道。Indy 的 TIdSFTP 连目录枚举都做得不够完整文件大小、权限、修改时间这些 SFTP v3 的属性经常丢一个文件传一半连接断了也没有清晰的错误状态给你判断。我曾经接一个项目前期用 Indy 写了半套文件同步逻辑到联调阶段发现服务器根本握手不上最后全部推翻换成 SecureBridge。如果你的业务要求是“能连通、能传文件、能排障”Indy 自带的 SSH 栈只能算脚手架够不到生产标准。2.2 与 IPWorks、自封装方案的区别组件化和完整协议栈是两回事另一种常见做法是封装外部 plink.exe 或 ssh 命令行靠解析 stdout 来拿到结果。好处是零安装坏处一堆无法拿到进度回调、多会话要起多个进程、密钥缓存和 passphrase 处理麻烦Windows 的控制台编码还能让你在输出中文文件名时翻车。用下来你会发现这套工作不省事最终还是要找一个进程内的协议实现。SecureBridge 的差别在于把 SSH 协议栈原生编进 Delphi 单元连接、认证、通道、 SFTP 全部在你进程内完成事件回调直接触发在 VCL 消息循环里它也支持异步模式。还有 IPWorks SSH 这类跨语言产品支持平台多但对 Delphi 特定版本的跟进和打包体验未必有 Devart 这么同步。SecureBridge 和 Devart 自家的 SQL Server、MySQL 数据访问组件同系命名风格一致TScSSHClient、TScSFTP、TScSSHTunnel、TScSSHLog用起来基本不突兀。如果你刚开始学 Delphi想通过真实组件理解 SSH 握手流程也可以去读它自带的 Ssh*.pas 源码头那比看 RFC 好懂。顺带提一句Lazarus 生态里也有类似选择但你在 Delphi 13.1 下做生产系统SecureBridge 的安装和升级路径明显更平滑。2.3 隧道、证书与日志专业版真正值钱的三件事v11.0.1 Professional 和标准版、免费版拉开距离的不是“能不能连”而是这三件事。第一是 SSH 隧道即端口转发。生产环境里最常见的是远程 MySQL 只监听 127.0.0.1不允许外网直连你用 TScSSHTunnel 把服务器的 3306 映射到本机 localhost:3306数据库客户端直接连本地端口就能走 SSH 加密信道访问服务不需要在防火墙上开 3306。同理调试远程应用或访问内网 Web 服务也可以用这个思路。第二是证书管理。SecureBridge 能加载 OpenSSL 生成的 PEM 私钥也能读 PuTTY 的 .ppk并支持 Passphrase密钥轮换时只需要改配置路径不用重编译。第三是日志。连不上服务器时TScSSHLog 可以把握手过程、认证结果、密钥协商细节写到文件你不再靠猜排查。选型时如果只是临时传一次文件标准版够用如果是周期性任务、多环境部署、要定位线上问题Professional 的隧道和日志这两项能回本。3. 从 .7z 到 IDE 面板SecureBridge v11.0.1 的完整安装步骤先说一句止损的建议如果你的 Delphi 是从 13.1 升到 13.2 这种小版本更新SecureBridge 通常也能识别新版本但最好先在旧版本上反激活再在 13.2 里重装激活这是免去注册表残留的后悔药。3.1 解压 .7z 后的包结构先分清编译期与运行期文件解压这个 .7z 后你会看到安装程序和若干子目录一般命名里会区分 x86、x64 平台。这里有个容易翻车的点Delphi 13.1 的 IDE 本身是 64 位的但 SecureBridge 运行库同时提供 32 位和 64 位版本因为同一个 IDE 可以编译出 32 位和 64 位的目标程序。装的时候别只看 IDE 位数还要看你后续要部署的目标平台。用 7-Zip 解压到一个固定目录比如 D:\Components\SecureBridge不要散落到 Delphi 安装目录里。安装前关闭 Delphi 和其他使用 bpl 的程序否则安装程序写注册表时可能遇到文件占用。如果安装程序检测不到 Delphi 13.1非默认安装路径时会这样手动指定 IDE 根目录通常就是 Program Files 下的 Embarcadero 目录安装日志里会写出它最终找到的 Delphi 版本号。安装程序默认会探测系统已安装的 RAD Studio 版本并要求选择目标 IDE。确认勾选了 Delphi 13.1 后下一步会让你挑选组件一般默认全选即可。这里值得一提的是源码与 DCU 的区别普通安装包会带上编译好的 DCU 和运行时 bpl写代码时足够若你以后想跟踪 SecureBridge 内部行为Professional 通常带源码源码版安装后需要在 IDE 里手动编译 dcl 包耗时多一些但可控性强。3.2 源码安装Library Path 与 Tool Palette 的配置顺序无论你用的是安装版还是源码版装完第一步不是急着写代码而是检查两个路径IDE 的 Library Path 和工程的 Search Path。前者让 IDE 在设计期认识这些单元并显示组件后者让编译期能找到 DCU/PAS。很多“装成功了但编译报 SshClient.dcu not found”的情况都是因为这一步没做。操作顺序我一般这样走打开 Tools Options IDE Library把 SecureBridge 的 Source 目录加入 Library Path如果你的编译目标包含 Win64还要确认 Win64 的 DCU 输出目录也被包含。随后打开 Component Install Packages点击 Add选择安装目录里以 dcl 开头的设计期包文件确定后工具面板会出现“SecureBridge”这一页。如果这一页空无一物多半是你 Add 的 bpl 和你当前 IDE 平台不匹配——64 位 IDE 必须加载 64 位设计包。最后验证新建一个 VCL 工程从组件面板拖一个 TScSSHClient 到窗体按 F9 编译。能过说明库路径没问题。若报 File not found 错误回到上一步重新核对路径。这里要提醒有些选手图省事直接把目录加到系统 PATH那对 IDE 无用必须在 Library 里配置。3.3 激活与版本验证注册码不是填完就结束SecureBridge Professional 安装完成后需要激活。启动 Delphi 后第一次在设计期使用控件时会弹激活对话框填入授权序列号后它会在注册表写入许可信息。如果激活失败表现很刁钻编译能通过但程序一运行、创建 TScSSHClient 实例时就抛异常提示包含 “License” 字样。遇到这种情况先别急着重装按三个顺序排查第一确认 Delphi 是否以管理员权限运行激活写注册表很容易受 UAC 影响第二检查系统时间是否准确激活服务对时间偏移比较敏感第三若你之前在多台机器装过确认反激活已经在旧机器上做完激活次数用完会直接拒绝新机激活。激活成功后你可以拖入一个 TScSSHClient在设计器里双击打开连接编辑器能看到 Host、Port、UserName、Password 等属性说明设计期状态正常。到这里 SecureBridge v11.0.1 Professional 才算真正接入了 Delphi 13.1可以开始干活了。4. 最小复现用 TScSSHClient 跑通 SSH SFTP 上传代码部分。直接在一个按钮的 Click 事件里写先用密码认证把 SSH 握手跑通这是最基础的验证。4.1 最小连接密码认证跑通 SSH 握手procedure TForm1.BtnConnectClick(Sender: TObject); var Client: TScSSHClient; begin Client : TScSSHClient.Create(nil); try Client.HostName : 192.168.1.10; Client.Port : 22; Client.UserName : root; Client.Authentication : atPassword; Client.Password : 你的密码; Client.Timeout : 10; // 10 秒内连不上就抛出异常 Client.Connect; // 连接成功后打印服务器版本顺便验证会话真实可用 ShowMessage(Client.ServerVersion); finally Client.Free; end; end;代码逻辑很直接创建客户端对象填主机、端口、用户名、认证方式再调用 Connect 阻塞执行。Connect 返回意味着 SSH 握手、密钥交换、用户认证全部完成此时 ServerVersion 属性会带上远程服务器的软件版本比如 OpenSSH_8.9p1这行信息在排障时很有用。这里有两个关键参数。第一个是 Authentication它决定走密码还是公钥流程如果服务器只接受公钥你在密码认证阶段就会收到异常日志里会写认证方式不匹配。第二个是 Timeout单位秒默认值可能为 0 即无限等待我建议生产代码显式设置10 到 30 秒都行避免网络黑洞里永久阻塞。同步 Connect 在 VCL 主线程里会让界面冻结真实项目建议用 TTask 包一层或者启用 Client 的异步模式后面会展开。4.2 公钥认证与 .ppk 格式转换密码认证只适合临时联调自动化任务要换公钥。SecureBridge 对 OpenSSL PEM 格式的支持要看版本而 v11.0.1 这类专业版处理较新的 OPENSSH PRIVATE KEY 时也并非总是顺利。我最常用的做法是先用 PuTTYgen 做一次格式转换打开 PuTTYgenFile Load 载入 OpenSSL 生成的私钥输入原 passphrase然后 Save private key 存成 .ppk 文件。转好后在代码里这样写Client.Authentication : atPublicKey; Client.PrivateKeyFile : C:\keys\deploy_key.ppk; Client.KeyPassphrase : 私钥口令; // 没设置就留空字符串 Client.Connect;逻辑上SecureBridge 从 PrivateKeyFile 读取密钥材料用 KeyPassphrase 解密出私钥再参与公钥认证公钥由私钥推导不需要你显式传公钥文件服务器端只要把对应公钥放进 authorized_keys 即可。这里有一个常见误会代码里同时填了 Password 和 PrivateKeyFile认证结果只取决于 Authentication 当前值不会自动做密码优先、密钥兜底的流程。若你想要回退得自己 catch 异常后换认证方式重新连。另一个注意点是私钥文件路径不要放在网盘或共享目录文件锁会影响读取本地副本是最稳的。4.3 SFTP 上传下载的 3 个关键参数连接建立后传文件用 TScSFTP它必须挂在同一个 SSH 会话上避免重复握手。var SFTP: TScSFTP; begin SFTP : TScSFTP.Create(nil); try SFTP.SSH : Client; // 复用 4.1 的 Client 连接 SFTP.Connect; SFTP.Timeout : 30; // 单次 SFTP 操作超时 SFTP.OverwriteMode : omOverwrite; // 覆盖远程同名文件 SFTP.Put(C:\tmp\report.pdf, /home/user/report.pdf); SFTP.Get(/home/user/backup.zip, C:\tmp\backup.zip); SFTP.Disconnect; finally SFTP.Free; end; end;第一个关键参数是 Timeout。SFTP 的每个底层请求都受它控制网络抖动时如果保持默认无限等待任务就会卡死。我的习惯是 SSH 层超时设 10 秒SFTP 层超时设 30 秒两者错开既不互相干扰又能快速暴露问题。第二个是 OverwriteMode决定远程存在同名文件时是报错、覆盖还是追加定时任务建议显式指定覆盖否则文件冲突会让任务静默失败日志里啥也没有。第三个是 Compression适合大文件或慢链路压缩开启后传输量明显减少代价是 CPU 占用升高目标服务器负载高时慎用。想观察传输进度可以挂 OnProgress 事件在事件里更新 UI 进度条。Put/Get 是同步阻塞调用放在 UI 线程会卡界面我会用 TThread 或 TTask 把整个 SFTP 会话丢到后台界面只接收进度回调。4.4 顺手封装一个执行远程命令的通道除了传文件SecureBridge 的 TScSSHChannel 可以在同一会话上执行远程命令。举一个高频场景SFTP 上传之前先远程建目录避免 Put 到不存在路径时报错。var Ch: TScSSHChannel; Output: string; begin Ch : TScSSHChannel.Create(nil); try Ch.SSH : Client; // 复用同一 SSH 会话 Ch.ChannelType : ctSession; Ch.Connect; Ch.WriteString(mkdir -p /home/user/data#10); Output : Ch.ReadString; // 读取命令输出便于确认结果 Ch.Disconnect; finally Ch.Free; end; end;这段代码和 SFTP 的复用关系很关键TScSSHChannel 和 TScSFTP 共享一个 TScSSHClient 的底层连接不会多一次握手也不会多一个会话。ChannelType 指定为 ctSession 表示这是一条普通执行命令的会话通道写命令时记得在末尾加换行符这是 shell 识别命令结束的标志。ReadString 会阻塞到有输出返回如果命令本身耗时长注意同样受 Timeout 约束。用这个通道可以串起“建目录、传文件、执行后续脚本”的完整自动化不用再额外拉起 SSH 进程。5. 避坑SecureBridge 在 Delphi 13.1 下最容易翻车的 5 个地方5.1 现象 1拖控件后编译报 DCU not found现象是组件面板里看得到 TScSSHClient拖到窗体也没问题一编译就报 File not found: SshClient.dcu。原因基本都是 Delphi 的 Library Path 只覆盖了运行时包输出目录而你在代码里直接 uses 了 SshClient 单元搜索路径里却没有包含 SecureBridge 的源码目录。解决打开 Tools Options IDE Library把 SecureBridge 的 Source 目录加进去同时在 Project Options Delphi Compiler Search Path 再添加一次保存后完整 Build。如果依然报错去确认当前活动目标平台和你安装的运行库位数一致32 位工程去引 64 位 DCU 同样会报这个错。5.2 现象 2连接超时像黑匣子一样卡死现象是 Connect 调用后界面失去响应迟迟不返回TScSSHLog 没有写出任何有效信息。原因多半是 Timeout 默认无限等待SecureBridge 在首包丢失时不会主动中断只能等系统 TCP 超时那段时间可能长达几分钟期间 UI 完全冻结。解决连接前显式设置 Client.Timeout : 10对 Connect 包一层 try/except异常消息里通常能看到具体原因。同时把 TScSSHLog 挂上日志级别设置到最详细那一档复现一次后看日志停在哪个阶段——是 DNS 解析、TCP 建连还是密钥交换。这一步做完超时就不再是黑匣子了。5.3 现象 3密钥连不上密码却能连现象同一个服务器密码认证正常换成公钥认证后报错或直接被断开。原因有三层按出现频率排第一私钥格式不兼容OpenSSL 新的 OPENSSH PRIVATE KEY 格式在部分版本里识别不完整第二私钥文件路径错误或没有读取权限第三服务器端 authorized_keys 里存放的公钥与客户端私钥不匹配OpenSSH 在公钥无法验证时会直接拒绝而不会告知你具体原因。解决先用 PuTTYgen 把 OpenSSL 私钥导入另存为 .ppk然后确认 PrivateKeyFile 指向的是文件而不是目录如果有 Passphrase 必须显式赋给 KeyPassphraseSecureBridge 不会弹框问你。服务器端排查时去看 /var/log/auth.log 里有没有 “Authentication refused” 字样能区分是密钥无效还是客户端根本没发过来。5.4 现象 4SFTP 传大文件时中途断开现象小文件传输一切正常传 300MB 以上的文件时进度条走到一半提示连接断开。原因网络路径中的防火墙或设备会把空闲的 TCP 连接掐掉。SecureBridge 传输大文件时如果中间有较长的沉默期会话保活没启用连接就被中间设备回收了。解决在 TScSSHClient 上设置一个合理的 KeepAliveInterval常见做法是 15 秒左右同时把 SFTP.Timeout 稍微放大但 SSH 层 Timeout 不要跟着放大两层职责不同一个是会话保活一个是单次操作容忍。另外SFTP 中断后默认不支持续传我一般先把文件下载到临时文件名传完再改名这样即使中断目标目录里也不会出现半截文件被其他程序误用。5.5 现象 532 位编译正常切到 64 位运行崩溃现象32 位 Debug 跑得好好的切到 64 位目标平台运行一创建 TScSSHClient 就访问违例。原因安装时没有选择安装 64 位运行库或者 Library Path 里只配了 32 位 DCU64 位编译时链接了错误位数的单元。解决重新运行安装程序确认勾选了 x64 相关组件查看 IDE Library 设置中 Win64 的 DCU 输出目录是否在搜索路径内最后打开 Project Manager确认当前活动平台是 64 位然后执行一次 Clean 再 Build。验证方法是直接用 Process Explorer 查看进程加载的 dll/bpl路径应指向 x64 子目录而不是 x86。6. 把隧道和私钥匹配封装成自己的工具函数SecureBridge 装好、代码跑通不等于这事就完了。最后分享两个我长期沉淀在自己公共单元里的工具函数一个是私钥自动匹配一个是隧道封装。私钥自动匹配主要用于密钥轮换期。团队里总有人把新私钥放到服务器上但本地还没同步或者反之与其每次手工试不如写一个函数function TryConnectWithKeys( const AHost: string; APort: Integer; const AUser: string; const AKeys: array of string; var AClient: TScSSHClient): Boolean; var I: Integer; begin Result : False; AClient : nil; for I : 0 to High(AKeys) do begin AClient : TScSSHClient.Create(nil); try AClient.HostName : AHost; AClient.Port : APort; AClient.UserName : AUser; AClient.Authentication : atPublicKey; AClient.PrivateKeyFile : AKeys[I]; AClient.Timeout : 15; AClient.Connect; Result : True; Exit; // 连接成功AClient 交还给调用方 except AClient.Free; // 失败必须释放本次实例 AClient : nil; end; end; end;调用时把多组私钥路径传进去谁先握手成功就用谁失败的一方在循环内释放掉避免内存泄漏。这个函数帮我省掉了好几次深夜加班。隧道封装更实用。把 TScSSHTunnel 和 SSH 客户端绑定把远程的 MySQL 3306 转发到本地然后数据库工具直连 127.0.0.1:3306 就能访问内网数据库。封装时注意两点LocalPort 不要占用系统已监听端口RemoteHost 在隧道模式下指向服务器视角的主机名多半是 127.0.0.1。停隧道时先 Active : False再断开 SSH 会话这个顺序我反着操作过一次结果 Windows 上端口句柄被占用清理起来相当麻烦。我自己现在用 SecureBridge 养成了一个固定习惯任何 SSH 客户端强制设 Timeout连接成功后先读 ServerVersion 并写进日志所有私钥统一转成 .ppk同时保留一份 OpenSSL 原始 PEM 作为备份隧道和连接函数固定在公共单元里不再散落在业务工程中。这套习惯帮我减少了很多重复排障也希望帮到你减少踩坑的时间。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进