ARTICLE DETAIL

资讯详情

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

curl/libcurl CURLOPT_SSH_KEYFUNCTION 深入指南:自定义 SFTP/SCP known_hosts 主机密钥校验回调

curl/libcurl CURLOPT_SSH_KEYFUNCTION 深入指南:自定义 SFTP/SCP known_hosts 主机密钥校验回调 curl/libcurl CURLOPT_SSH_KEYFUNCTION 深入指南自定义 SFTP/SCP known_hosts 主机密钥校验回调【免费下载链接】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导读CURLOPT_SSH_KEYFUNCTION是 libcurl 提供的 SSHSFTP/SCP主机密钥校验扩展点当 libcurl 完成 known_hosts 匹配后允许应用接管决策权自定义密钥是否可信、是否写入 known_hosts、是否拒绝连接等行为。本文以 CURLOPT_SSH_KEYFUNCTION 官方文档 为主线结合 libcurl 源码 中ssh_knownhost的完整实现讲解回调原型、五种返回码语义、默认行为与底层处理流程并给出可直接编译运行的完整示例帮助你为 FTP/SCP 场景构建符合自身安全策略的主机密钥校验方案。回调的定位known_hosts 匹配完成之后的一道闸门libcurl 在使用 libssh2 或 libssh 后端建立 SFTP/SCP 连接时会依据 CURLOPT_SSH_KNOWNHOSTS 指定的 known_hosts 文件对远程主机公钥做匹配检查。匹配结果只会是以下三种enum curl_khmatch取值含义CURLKHMATCH_OK主机与密钥完全匹配CURLKHMATCH_MISMATCH找到主机条目但密钥不一致潜在中间人攻击CURLKHMATCH_MISSING未找到匹配的主机/密钥首次连接或 known_hosts 过期CURLOPT_SSH_KEYFUNCTION设置的回调正是在这一步之后被调用libcurl 把 known_hosts 中的密钥knownkey、远端主机提供的密钥foundkey、匹配状态match以及自定义指针全部交给应用由应用决定如何继续。该回调仅在同时设置了CURLOPT_SSH_KNOWNHOSTS时才会被触发见文档 DESCRIPTION 与 libssh2.c 中no knownhosts file configured 时直接返回的保护逻辑。回调原型与数据结构函数原型int ssh_keycallback(CURL *easy, const struct curl_khkey *knownkey, const struct curl_khkey *foundkey, enum curl_khmatch match, void *clientp);easy当前 easy handle。knownkey来自 known_hosts 文件的密钥若匹配过程中未找到主机条目此参数可能为 NULL源码中以knownkeyp指针传递仅当keycheck LIBSSH2_KNOWNHOST_CHECK_MISMATCH时才赋值见 libssh2.c。foundkey远端主机实际提供的公钥。match上述enum curl_khmatch匹配结果。clientp由 CURLOPT_SSH_KEYDATA 设置的自定义指针可在回调中携带业务上下文如用户确认标志、审计日志句柄等。struct curl_khkeystruct curl_khkey { const char *key; /* len 为 0 时指向以 base64 编码的空终止字符串 否则指向 raw 原始数据 */ size_t len; enum curl_khtype keytype; };len 0表示key是 base64 编码的文本形式known_hosts 文件内保存的形态len 0表示key是二进制原始公钥数据。keytype由enum curl_khtype描述密钥算法libssh2 后端在 convert_ssh2_keytype 附近的映射逻辑会把LIBSSH2_HOSTKEY_TYPE_RSA/ECDSA_256/384/521/ED25519等类型逐一转换为对应的curl_khtype。设置方式CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_KEYFUNCTION, ssh_keycallback);在 setopt.c 中该选项直接写入data-set.ssh_keyfunc注释明确说明传入 NULL 也是合法的——此时后端会自动回退到 libcurl 内部的默认回调。对应的存储字段定义在 urldata.hcurl_sshkeycallback ssh_keyfunc; /* key matching callback */ void *ssh_keyfunc_userp; /* custom pointer to callback */CURLOPT_SSH_KEYDATA则填充ssh_keyfunc_userp见 setopt.c。五种返回码的完整语义回调的返回值是一个enum curl_khstatlibcurl 据此决定连接的去向。下面按文档定义并结合源码逐一展开。CURLKHSTAT_FINE_ADD_TO_FILE接受该主机密钥并在继续连接前将其追加到 known_hosts 文件同时若内存中的 known_host 池没有该条目也会一并加入。CURLKHSTAT_FINE_REPLACE接受新主机密钥并且替换known_hosts 文件中旧的同名主机密钥条目后再继续连接自 7.73.0 起提供。同样会同步更新内存中的 known_host 池。注意两者通用向文件写入数据时libcurl 采用整体重写策略——先把内存中的完整 known_hosts 列表写回文件因此文件权限必须允许写入否则写盘失败源码中仅记录WARNING: writing %s failed见 libssh2.c。CURLKHSTAT_FINE接受主机密钥直接继续连接若内存池中无该条目同样补入但不写盘。CURLKHSTAT_REJECT拒绝该主机密钥连接被关闭、无法继续。CURLKHSTAT_DEFER拒绝该主机密钥但要求保持 SSH 会话存活。典型用法是应用先在回调中记录/提示用户这台主机密钥不可信稍后由用户确认后再重试从而省去重新建立 SSH 会话的开销。源码视角返回码是如何被执行的libssh2 后端在 ssh_knownhost 中完成了匹配 → 回调 → 执行决策的完整链路理解这段代码可以精确把握每个返回码的落地行为取远端密钥并判型libssh2_session_hostkey()取得远端公钥再根据sshkeytype映射出对应的keybit若是不支持的密钥类型keybit 0直接按CURLKHSTAT_REJECT处理L340-L368。检查 known_hostslibssh2_knownhost_checkp()用主机名非标准 22 端口时带[host]:port形式与远端密钥进行匹配得到keychecklibcurl 将 libssh2 的检查结果直接转换为enum curl_khmatch源码注释提醒若两边枚举变更需要引入翻译表见 L397-L402。调用回调在CURL_CBAPI_START/END防护区内调用data-set.ssh_keyfunc未设置时使用内部默认回调sshkeycallback传入 knownkey/foundkey/match/clientpL404-L409。按返回码分派L418-L477REJECT日志记录knownhost check failed会话进入释放流程DEFER同样返回CURLE_PEER_FAILED_VERIFICATION错误但保持 SSH 会话状态不销毁供重试复用FINE_REPLACE先调用libssh2_knownhost_del()删除不匹配的旧条目FINE/FINE_ADD_TO_FILE继续连接先通过libssh2_knownhost_addc()把新主机密钥加入内存池仅当返回码为FINE_ADD_TO_FILE或FINE_REPLACE时再调用libssh2_knownhost_writefile()整文件写回。libssh 后端在 libssh.c 附近同样实现了基于data-set.ssh_keyfunc的信任首次连接TOFU式回调调度逻辑两个后端的对外接口行为保持一致。另外值得留意如果未设置CURLOPT_SSH_KEYFUNCTIONlibcurl 会使用内部的默认sshkeycallbacklibssh2.c它实现了标准的 known_hosts 校验策略——这也解释了为何该选项默认值为NULL也能正常工作。完整可运行示例以下示例改编自文档 EXAMPLE 一节补齐了回调中对match状态的判断并展示了如何结合CURLOPT_SSH_KEYDATA传递自定义上下文#include curl/curl.h struct mine { void *custom; }; static int keycb(CURL *easy, const struct curl_khkey *knownkey, const struct curl_khkey *foundkey, enum curl_khmatch match, void *clientp) { /* clientp points to the callback_data struct */ (void)easy; (void)knownkey; (void)foundkey; (void)clientp; switch(match) { case CURLKHMATCH_OK: /* 完全匹配直接放行 */ return CURLKHSTAT_FINE; case CURLKHMATCH_MISMATCH: /* 密钥不一致最安全的选择是拒绝连接 */ return CURLKHSTAT_REJECT; case CURLKHMATCH_MISSING: default: /* 首次连接接受并把新密钥追加到 known_hosts 文件 */ return CURLKHSTAT_FINE_ADD_TO_FILE; } } int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; struct mine callback_data; curl_easy_setopt(curl, CURLOPT_URL, sftp://example.com/thisfile.txt); curl_easy_setopt(curl, CURLOPT_SSH_KEYFUNCTION, keycb); curl_easy_setopt(curl, CURLOPT_SSH_KEYDATA, callback_data); curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, /home/user/known_hosts); result curl_easy_perform(curl); curl_easy_cleanup(curl); } return 0; }关键点回调必须返回enum curl_khstat中的合法值。源码中未识别的返回值按REJECT处理default: /* unknown return codes is the same as reject */见 libssh2.c因此务必覆盖所有分支。CURLOPT_SSH_KEYDATA是可选的但推荐使用——它让回调可以访问应用状态例如是否已获得用户对陌生主机的确认是实现交互式确认、审计等高级策略的基础。若希望保持默认校验行为直接不设置本选项即可默认值为NULL。默认值、可用性与返回值默认值NULL。未设置时由 SSH 后端使用内部默认回调完成标准 known_hosts 校验。协议仅适用于 SFTP 与 SCP见文档 Protocol 段。可用性自 libcurl 7.19.6 起提供Added-in: 7.19.6CURLKHSTAT_FINE_REPLACE自 7.73.0 起提供。返回值curl_easy_setopt()返回CURLcodeCURLE_OK (0)表示设置成功非零值表示出错错误码详见 libcurl-errors。与其他 SSH 选项的配合CURLOPT_SSH_KEYDATA为本回调提供自定义指针二者通常成对出现。CURLOPT_SSH_KNOWNHOSTSknown_hosts 文件路径本回调生效的前置条件。CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 与 CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256在 libssh2 后端中提供基于指纹的额外校验路径见 ssh_check_fingerprint可作为 known_hosts 校验之外的补充防线。安全提示CURLKHSTAT_FINE_ADD_TO_FILE/FINE_REPLACE属于信任首次连接类策略生产环境中务必结合业务安全模型谨慎使用遇到CURLKHMATCH_MISMATCH时默认拒绝CURLKHSTAT_REJECT是最稳妥的选择。【免费下载链接】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),仅供参考
返回列表