libcurl 的 CURLOPT_SSH_HOST_PUBLIC_KEY_MD5基于 MD5 指纹的 SFTP/SCP 主机公钥校验【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curlCURLOPT_SSH_HOST_PUBLIC_KEY_MD5 是 libcurl 提供的一个 SSH 选项用于在通过 SFTP/SCP 建立连接时用远程主机公钥的 128 位 MD5 校验和32 位十六进制字符串对服务器身份进行强制校验。本文以 docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md 为骨架结合仓库中 libssh2/libssh 两个后端的源码实现与测试用例完整讲解该选项的 API 用法、底层校验流程、命令行对应形式以及安全迁移建议。读完本文你将掌握如何在 libcurl 程序中为 SFTP/SCP 连接固定主机指纹并理解连接级一次性校验的语义以及它与 knownhosts、host key 回调等其他验证机制的关系。一、选项概览是什么、解决什么问题在 SSH 协议中客户端与服务器建立会话时服务器会出示自己的公钥。如果客户端不做任何校验攻击者可以通过中间人MITM手段伪装成目标服务器。CURLOPT_SSH_HOST_PUBLIC_KEY_MD5允许应用程序预先提供一个预期的服务器公钥 MD5 指纹libcurl 在建立 SSH 连接时将其与服务器实际出示的公钥指纹做比对不一致则直接中止连接返回CURLE_PEER_FAILED_VERIFICATION。适用协议SFTP、SCP引入版本7.17.1选项类型字符串指针CURLOPTTYPE_STRINGPOINT在 include/curl/curl.h 中定义枚举值为 162默认值NULL不启用该检查该选项与另外两个 SSH 选项密切相关CURLOPT_SSH_HOST_PUBLIC_KEY_SHA2567.80.0 引入的推荐替代方案和 CURLOPT_SSH_KNOWNHOSTSknownhosts 文件校验后文会详细说明它们之间的优先级关系。二、API 原型与参数格式#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, char *md5);参数md5必须指向一个包含32 个十六进制字符的字符串即远程主机公钥 128 位 MD5 校验和的 ASCII 十六进制表示。例如afe17cd62a0f3b61f1ab9cb22ba269a7。需要注意字符串生命周期libcurl 会在内部复制该字符串通过Curl_setstropt应用程序在设置该选项后无需保留这个字符串可以随时释放。覆盖语义重复设置该选项时最后一次设置的值会覆盖之前的值。禁用方式将该选项设置为NULL即可再次禁用它。格式校验从源码看libcurl 并不会单独校验md5字符串的长度——lib/vssh/libssh2.c 中的注释明确指出This does NOT verify the length of pubkey_md5 separately, which makes the comparison below fail unless it is exactly 32 characters。也就是说长度不合法时校验会自然失败连接被拒绝。对应地tests/data/test632 专门用语法上非法的 host key 验证了这一失败路径。三、核心行为连接级一次性校验语义文档中特别强调了一个容易被忽视的语义该选项只在 libcurl 创建新 SSH 连接时生效。具体规则如下新连接校验当 libcurl 建立一条全新 SSH 连接时如果设置了该选项会执行 MD5 指纹比对。已验证连接的复用一旦某条连接建立成功并通过了 MD5 校验这条连接就被视为可信vetted的之后可能被 libcurl 直接复用连接池复用不会再次执行 MD5 校验——即使你之后修改、禁用该选项或切换到 CURLOPT_SSH_KNOWNHOSTS、CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 等其他校验机制这些变更只影响未来的新连接不影响已经建立的连接。互斥性当某条连接启用了 MD5 校验时libcurl 使用 MD5 检查代替该连接的 knownhosts/host key 回调校验路径。不要假设同一连接上 MD5 检查和 knownhosts/host key 回调校验会被同时执行。这一语义在 libssh2 后端的ssh_check_fingerprint()函数中体现得十分直接lib/vssh/libssh2.c若设置了 MD5 或 SHA256 指纹且匹配成功直接return CURLE_OK并注释as we already matched, we skip the check for known hosts若两者都未设置才走 host key 回调ssh_hostkeyfunc或 knownhosts 文件ssh_knownhost()路径。四、源码实现剖析选项如何存、如何校验4.1 选项的存储与解析选项枚举在 include/curl/curl.h 中声明字符串槽位定义在 lib/urldata.hSTRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ASCII hex */仅当构建时启用 SSH 支持即#ifdef USE_SSH设置入口在 lib/setopt.c通过Curl_setstropt(data, STRING_SSH_HOST_PUBLIC_KEY_MD5, ptr)完成字符串的复制存储选项元数据表在 lib/easyoptions.c类型为CURLOT_STRING供curl_easy_getinfo的 option 枚举体系与curl --libcurl等工具使用。4.2 libssh2 后端ssh_check_fingerprint在 lib/vssh/libssh2.c 的ssh_check_fingerprint()中MD5 校验流程为调用libssh2_hostkey_hash(sshc-ssh_session, LIBSSH2_HOSTKEY_HASH_MD5)取服务器公钥的 MD5 原始哈希注意该指纹指向静态存储不能free()逐字节用curl_msnprintf(md5buffer[i * 2], 3, %02x, ...)格式化为 32 位十六进制小写字符串与用户设置的pubkey_md5做curl_strequal大小写不敏感比较lib/vssh/libssh2.c不匹配或指纹不可用时调用failf()输出形如Denied establishing ssh session: mismatch MD5 fingerprint. Remote %s is not equal to %s的错误信息并返回CURLE_PEER_FAILED_VERIFICATION。日志输出可通过CURLOPT_VERBOSE观察libcurl 会依次打印SSH: MD5 public key ...和SSH: MD5 fingerprint ...匹配成功时打印SSH: MD5 checksum match。4.3 libssh 后端myssh_is_known在 lib/vssh/libssh.c 的myssh_is_known()中验证优先级注释明确写为设置了 SHA256 哈希推荐设置了 MD5 哈希注释直言是 90s style auth, not sure we should have it here即老式 90 年代风格的认证设置了ssh_keyfunc回调trust on first use以上都没有则只接受 known hosts 中存在的条目。MD5 分支的实现lib/vssh/libssh.c使用ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5, hash_md5, hlen_md5)计算服务器公钥的 MD5 哈希要求hlen_md5 16字节格式化为 32 位十六进制后与用户字符串做curl_strequal比较失败时同样返回SSH_ERROR并最终映射为CURLE_PEER_FAILED_VERIFICATION。五、命令行对应--hostpubmd5curl 命令行工具提供了同名能力--hostpubmd5 md5见 docs/cmdline-opts/hostpubmd5.md其参数解析入口在 src/tool_getparam.cC_HOSTPUBMD5并在 src/config2setopts.c 中通过MY_SETOPT_STR(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, config-hostpubmd5)映射为 libcurl 选项。命令行示例# 固定 SFTP 服务器公钥的 MD5 指纹不匹配则拒绝连接 curl --hostpubmd5 e5c1c49020640a5ab0f2034854c321a8 sftp://example.com/ # 同样适用于 SCP curl --hostpubmd5 e5c1c49020640a5ab0f2034854c321a8 scp://example.com/file注意命令行侧src/config2setopts.c有一个细节当既未提供--hostpubmd5也未提供--hostpubsha256时curl 会尝试从环境推断一个可能可用的 knownhosts 文件路径作为兜底验证手段。六、测试用例验证仓库测试集提供了多组针对该选项的验证用例位于 tests/data 目录tests/data/test630SFTP 场景使用错误的--hostpubmd5 00000000000000000000000000000000验证 host key 错误时连接被拒绝tests/data/test631SCP 场景同样的错误指纹验证拒绝路径tests/data/test632SFTP 场景语法上非法的 host keytests/data/test1725SCP 场景下--proto-default SCP与错误 host key 的组合验证tests/data/test2007SFTP 场景中使用%SSHSRVMD5测试框架注入的正确服务器指纹配合-Q命令验证正确指纹下连接正常建立。这些测试尤其是%SSHSRVMD5变量也提示了一个实用的运维技巧可以先不设指纹执行一次连接从 verbose 日志中读取服务器实际指纹再将其固化到代码或脚本中。七、完整代码示例以下示例取自 docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md展示了完整的 API 用法int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, sftp://example.com/file); curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, afe17cd62a0f3b61f1ab9cb22ba269a7); result curl_easy_perform(curl); curl_easy_cleanup(curl); } }更完整的工程化写法建议包含CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, sftp://example.com/file); curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, afe17cd62a0f3b61f1ab9cb22ba269a7); /* 注意一旦该连接通过校验并被复用后续请求即使不设此选项 也不会重新校验连接级一次性校验语义 */ result curl_easy_perform(curl); if(result ! CURLE_OK) { /* 校验失败时此处为 CURLE_PEER_FAILED_VERIFICATION */ fprintf(stderr, curl_easy_perform() failed: %s\n, curl_easy_strerror(result)); } curl_easy_cleanup(curl); }八、返回值与错误处理curl_easy_setopt()总是返回CURLcodeCURLE_OK (0)设置成功非零值发生错误具体含义参见 libcurl-errors仓库对应文档为 docs/libcurl/libcurl-errors.md。值得区分两个阶段的错误阶段返回值/现象设置选项本身失败CURLE_BAD_FUNCTION_ARGUMENT等非零CURLcode例如参数类型不合法连接建立时指纹校验失败curl_easy_perform()返回CURLE_PEER_FAILED_VERIFICATION且 verbose 日志打印 Denied establishing ssh session: mismatch MD5 fingerprint ...九、安全建议尽快迁移到 SHA256文档明确警告MD5 是弱算法MD5 is a weak algorithm强烈建议改用 CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 替代。这与源码注释的态度一致lib/vssh/libssh.c 将其称为 90s style auth。两者的关键差异对比项MD5 版本SHA256 版本选项名CURLOPT_SSH_HOST_PUBLIC_KEY_MD5CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256引入版本7.17.17.80.0哈希算法128 位 MD5SHA256编码格式32 位十六进制小写Base64含填充推荐程度不推荐弱算法推荐/* 推荐的迁移写法 */ curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, NDVkMTQxMGQ1ODdmMjQ3MjczYjAyOTY5MmRkMjVmNDQ);从 lib/vssh/libssh2.c 的ssh_check_fingerprint()可以看出若同时设置了 SHA256 和 MD5SHA256 分支会优先执行两者都未设置时才回退到 knownhosts 文件或 host key 回调。在生产环境中建议优先使用 SHA256 指纹仅在必须兼容老版本 libcurl早于 7.80.0时再考虑 MD5 方案。十、总结CURLOPT_SSH_HOST_PUBLIC_KEY_MD5为 SFTP/SCP 场景提供了一种硬编码服务器指纹的身份校验手段适合在指纹事先已知、需要对抗中间人攻击的自动化场景中使用。使用时务必牢记三点32 位十六进制格式、连接级一次性校验语义、以及与 knownhosts/host key 回调的互斥关系。鉴于 MD5 的已知弱点新代码应优先采用 CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256并把 knownhosts 文件校验CURLOPT_SSH_KNOWNHOSTS作为可扩展的补充方案。【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考