拓冰建站拓冰建站
首页 / 资讯中心 / 正文

libcurl CURLOPT_COOKIELIST 详解:内存 Cookie 引擎的注入、批量操作与安全边界

libcurl CURLOPT_COOKIELIST 详解内存 Cookie 引擎的注入、批量操作与安全边界【免费下载链接】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_COOKIELIST是 libcurl 中用于直接操作内存 Cookie 存储的核心选项它既可以把单个 Cookie 以 Netscape 文件行或 HTTPSet-Cookie:头的形式即时注入 Cookie 引擎也可以通过ALL、SESS、FLUSH、RELOAD四条特殊命令批量清空、落盘与重载 Cookie。本文基于当前仓库 docs/libcurl/opts/CURLOPT_COOKIELIST.md 展开结合 lib/setopt.c 与 lib/cookie.c 的源码实现和 tests/libtest/lib506.c 等测试用例讲清四种注入格式、四条管理命令的精确语义以及绕过 Public Suffix ListPSL检查这一关键安全边界帮助你安全、正确地在自己应用中管理会话与持久化 Cookie。选项概览签名、协议与默认值CURLOPT_COOKIELIST通过curl_easy_setopt设置参数是一个char *字符串指针#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_COOKIELIST, char *cookie);生效协议仅 HTTP含 HTTPS。在仓库头文件 include/curl/curl.h 中它被声明为CURLOPT(CURLOPT_COOKIELIST, CURLOPTTYPE_STRINGPOINT, 135)属于字符串指针类选项。引入版本7.14.1ALL命令同期引入SESS于 7.15.4、FLUSH于 7.17.1、RELOAD于 7.39.0 加入详见下文历史沿革。默认值NULL即默认不执行任何注入或命令操作。返回值curl_easy_setopt返回CURLcodeCURLE_OK (0)表示成功非零表示出错见libcurl-errors手册。在编译关闭 cookie 支持CURL_DISABLE_COOKIES/CURL_DISABLE_HTTP时该选项会落到default分支返回CURLE_UNKNOWN_OPTION见 lib/setopt.c。编译器类型检查在启用 GCC 严格类型检查时该选项与CURLOPT_COOKIE、CURLOPT_COOKIEFILE、CURLOPT_COOKIEJAR一样要求字符串参数见 include/curl/typecheck-gcc.h。核心语义一次调用两种身份传递给CURLOPT_COOKIELIST的字符串有且仅有两种处理路径源码 lib/setopt.c 中的cookielist()函数清晰地区分了它们命令字符串当传入的字符串与ALL、SESS、FLUSH、RELOAD精确匹配不区分大小写使用curl_strequal比较时执行对应的批量操作。Cookie 字符串其余任何非 NULL 字符串都被当作一条 Cookie解析并注入内存存储。这一行为同时启用了 Cookie 引擎——即使此前从未调用过CURLOPT_COOKIEFILE注入后该 handle 也会开始参与 Cookie 的接收、保存与发送逻辑。值得注意的实现细节是命令分支中ALL、SESS、FLUSH均先返回CURLE_OK而RELOAD分支直接return Curl_cookie_loadfiles(...)把加载结果作为返回值——即重载失败如内存不足时curl_easy_setopt本身会返回错误码调用方可以据此感知失败。两种可注入的 Cookie 行格式Netscape / Mozilla 文件行格式推荐域名(Tab)是否包含子域(Tab)路径(Tab)Secure标志(Tab)过期时间(Tab)名称(Tab)值例如example.com FALSE / FALSE 0 foo barHTTPSet-Cookie:头格式Set-Cookie: namevalue; Domainexample.com; Path/; ExpiresSat, 02 Feb 2030 11:56:27 GMT为什么官方强烈建议使用 Netscape 格式原文档给出了一条明确的工程建议强烈建议不要从 HTTP 头文件加载 Cookie因为它是劣质的数据交换格式。原因有二若使用Set-Cookie格式且字符串中未指定 Domain则该 Cookie 会被当作任何域名都发送的全局 Cookie即便后续跟随了重定向它也会被发给任意主机而且服务器后续设置的同名 Cookie 无法覆盖它。若服务器设置了一个同名 Cookie或你手动导入了同名 Cookie未来传输到该服务器时两个 Cookie 都会被发送通常不是你期望的结果。规避方法在Set-Cookie中显式设置 Domain注意设置 Domain 会包含其子域或者更优方案——直接使用 Netscape 文件格式因为该格式的域名字段是强制性的。多传输场景的并发注意如果你的程序在同一个进程内发起多次传输使用本选项要格外小心未指定 Domain 的Set-Cookie注入会污染全局发送行为见上文在多个并发 easy handle 共享 Cookie 存储CURLSHOPT_SHARECURL_LOCK_DATA_COOKIE时尤其容易引入难以排查的串扰问题。仓库测试 tests/libtest/lib506.c 就专门构造了注入 → ALL → 注入会话 Cookie → SESS → 多线程共享 Cookie 存储 → FLUSH → RELOAD的完整链路来验证这类交互下的锁与数据一致性。四条管理命令ALL / SESS / FLUSH / RELOAD在 lib/setopt.c 中这四条命令的实现如下命令作用源码实现引入版本ALL清除内存中所有CookieCurl_cookie_clearall(data-cookies)7.14.1SESS清除内存中所有会话 Cookieexpires 0的 CookieCurl_cookie_clearsess(data-cookies)7.15.4FLUSH把当前已知的所有Cookie 写入CURLOPT_COOKIEJAR指定的文件Curl_flush_cookies(data, FALSE)7.17.1RELOAD从CURLOPT_COOKIEFILE指定的文件加载所有CookieCurl_cookie_loadfiles(data, COOKIE_NOPSL \| (cookiesession ? COOKIE_NOSESSION : 0))7.39.0补充说明SESS的判定会话 Cookie 指没有过期时间Netscape 格式第 5 字段为0的 Cookie。Curl_cookie_clearsess遍历全部 hash 桶并释放这类 Cookie持久化 Cookie 则保留。RELOAD与CURLOPT_COOKIESESSION的联动如果在RELOAD之前启用了CURLOPT_COOKIESESSION则该开关会作用于本次加载加载时所有会话 Cookie 会被直接丢弃对应实现中的COOKIE_NOSESSION标志见 lib/cookie.c 附近关于newsession的逻辑。这一语义与原文档完全一致。RELOAD与 PSL 的例外注意RELOAD分支传入COOKIE_NOPSL标志意味着从文件重载 Cookie 时也跳过 PSL 检查与下文的注入路径行为一致。PSL 检查被绕过必须自己把关的安全边界这是原文档着墨最多、也最容易被忽视的一点通过CURLOPT_COOKIELIST注入的 Cookie 会绕过自动 Public Suffix ListPSL检查。原因在实现层面很直接调用发生时 handle 内部的 PSL 引擎尚未初始化。在正常传输中PSL 校验会阻止 Cookie 被设置在宽泛或共享域名上——例如.com、.co.uk、.github.io——因为如果允许无关的子域名就能读取同一份敏感 Cookie 数据形成安全漏洞。验证代码路径lib/cookie.c 中Curl_cookie_add的检查是if(!(flags COOKIE_NOPSL) is_public_suffix(data, co, domain)) goto fail;即只有在未设置COOKIE_NOPSL标志时才做 PSL 校验。而注入路径lib/cookie.c 注释明确写出domain为 NULL 的情况正是从文件加载或CURLOPT_COOKIELIST以及上文RELOAD的COOKIE_NOPSL标志都绕过了这层防护。这并非缺陷而是设计使然——因此调用方必须全权负责域名合法性校验在把 Cookie 注入 handle 之前自行确认其 Domain 属性指向的是一个有效主机且不是公共后缀public suffix。否则可能把你的 Cookie 泄漏给任意子域。实操建议注入前用你自己的 PSL 库或维护的公共后缀清单校验Domain字段测试环境域名如localhost不受此问题影响——仓库测试 tests/libtest/lib3103.c 就展示了向domainlocalhost注入会话 Cookie 的合法用法。完整示例注入、导入、导出的时序语义原文档的示例完整演示了注入的 Cookie 是 live cookie文件导入不会覆盖它这一关键时序。结合 lib/cookie.c 中co-livecookie ci-running;运行中注入的 Cookie 标记为 live该行为在源码层面得到印证/* 以 Netscape 格式内联导入一条 Cookie。 */ #define SEP \t /* Tab 分隔各字段 */ int main(void) { const char *my_cookie example.com /* Hostname域名 */ SEP FALSE /* Include subdomains是否包含子域 */ SEP / /* Path路径 */ SEP FALSE /* Secure是否仅 HTTPS 发送 */ SEP 0 /* Expiry in epoch time format. 0 Session过期时间epoch0 表示会话 Cookie */ SEP foo /* NameCookie 名 */ SEP bar; /* ValueCookie 值 */ CURL *curl curl_easy_init(); if(curl) { CURLcode result; /* my_cookie 通过 CURLOPT_COOKIELIST 被立即导入。 */ curl_easy_setopt(curl, CURLOPT_COOKIELIST, my_cookie); /* cookies.txt 中的 Cookie 直到真正执行传输前才会被导入。 其中与 my_cookie 具有相同 hostname、path 和 name 的 Cookie 会被跳过。 因为 libcurl 已导入了 my_cookie它被视为 live cookie 而 live cookie 不会被文件中读取的 Cookie 替换。 */ curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookies.txt); /* 导入 */ /* Cookie 在 curl_easy_cleanup 之后被导出。 此时服务器可能已新增、删除或修改过 Cookie。 导入时被跳过的 Cookie 不会被导出。 */ curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookies.txt); /* 导出 */ result curl_easy_perform(curl); /* 此期间从 cookies.txt 导入 Cookie */ curl_easy_cleanup(curl); /* 此调用后 Cookie 被导出到 cookies.txt */ } }示例揭示的三个重要时序语义CURLOPT_COOKIELIST注入是即时生效的CURLOPT_COOKIEFILE的导入是惰性的直到传输前才发生。live cookie 优先级高于文件同名hostnamepathnameCookie 若已通过COOKIELIST注入文件导入时不会覆盖它。这源于 lib/cookie.c 中ci-running与livecookie的判定。导出发生在curl_easy_cleanup时且只导出活跃未被跳过的 Cookie 集合。与 Cookie 文件格式的衔接CURLOPT_COOKIELIST注入的单行格式与CURLOPT_COOKIEFILE/CURLOPT_COOKIEJAR使用的 Cookie 文件格式同源Netscape / Mozilla 格式相关背景可进一步阅读仓库 docs/HTTP-COOKIES.md。典型文件行形如# Netscape HTTP Cookie File .example.com TRUE / FALSE 1893456000 foo bar其中字段依次为域名、是否匹配子域TRUE/FALSE、路径、Secure 标志、Unix 时间戳形式的过期时间0 为会话 Cookie、名称、值。这一格式同样适用于命令行工具curl -b cookies.txt -c cookies.txt的场景见 docs/cmdline-opts/cookie.md 与 docs/cmdline-opts/cookie-jar.md。源码级验证测试用例与实现位置如果你想在仓库中亲手验证上述全部行为以下是精确的入口选项分发与命令解析lib/setopt.c 的cookielist()——四种命令的分支、curl_strequal匹配、RELOAD返回值透传。Cookie 解析与入库lib/cookie.c 的Curl_cookie_add()——Netscape/HTTP 头两种解析路径parse_netscape/parse_cookie_header、__Secure-/__Host-前缀校验、PSL 检查、live cookie 标记。文件加载与惰性导入lib/cookie.c 与Curl_cookie_loadfiles——Set-Cookie:前缀剥离、COOKIE_NOEXPIRE | COOKIE_SECURE | COOKIE_NOPSL标志组合。共享存储下的完整链路tests/libtest/lib506.cALL/SESS/FLUSH/RELOAD 共享锁、tests/libtest/lib1905.cmulti 接口中 FLUSH 落盘、tests/libtest/lib3103.c无过期时间的Set-Cookie注入。选项注册与类型include/curl/curl.h、lib/easyoptions.c、include/curl/typecheck-gcc.h。配套选项CURLOPT_COOKIE、CURLOPT_COOKIEFILE、CURLOPT_COOKIEJAR、CURLOPT_COOKIESESSION以及用于反向读取 Cookie 列表的 CURLINFO_COOKIELIST。历史沿革能力引入版本CURLOPT_COOKIELIST与ALL7.14.1SESS7.15.4FLUSH7.17.1RELOAD7.39.0使用前请确认你的 libcurl 版本不低于 7.14.1并留意发行版打包的 libcurl 是否以CURL_DISABLE_COOKIES编译此时该选项返回CURLE_UNKNOWN_OPTION。最佳实践清单优先 Netscape 文件行格式注入 Cookie必须用Set-Cookie时务必显式给出Domain。注入前自行做域名校验确认 Domain 是有效主机名且不是公共后缀.com、.co.uk、.github.io等因为 PSL 检查在此路径被绕过。善用四条命令需要清空状态用ALL只清会话用SESS要在curl_easy_cleanup之前强制落盘用FLUSH需要从文件重建状态用RELOAD。注意RELOAD与CURLOPT_COOKIESESSION的组合先启用CURLOPT_COOKIESESSION再RELOAD会丢弃全部会话 Cookie。记住 live cookie 语义通过COOKIELIST注入的 Cookie 不会被随后COOKIEFILE文件导入的同名 Cookie 覆盖导出COOKIEJAR时只导出活跃集合。多传输共享 Cookie 存储时为ALL/SESS/FLUSH/RELOAD等操作预判其全局影响必要时结合curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE)并实现正确的锁回调参见 tests/libtest/lib506.c 的锁测试。【免费下载链接】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),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门