尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

curl 的 CURLOPT_AWS_SIGV4 选项详解:在 libcurl 中实现 AWS SigV4 请求签名

curl 的 CURLOPT_AWS_SIGV4 选项详解:在 libcurl 中实现 AWS SigV4 请求签名 curl 的 CURLOPT_AWS_SIGV4 选项详解在 libcurl 中实现 AWS SigV4 请求签名【免费下载链接】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_AWS_SIGV4是 libcurl当前仓库 curl 项目提供的 AWS Signature Version 4SigV4认证选项它能让 curl 自动为 HTTP(S) 请求生成标准化的Authorization头、日期头与载荷哈希从而直接访问 AWS 及其兼容云服务的签名 API。读完本文你将掌握该选项的参数格式与推导规则、它与CURLOPT_HTTPAUTH的关系、底层签名计算流程以及如何配合凭据与自定义头完成可实际运行的请求签名。该选项由官方文档 CURLOPT_AWS_SIGV4.md 定义自 curl 7.75.0 起可用仅适用于 HTTP 协议。下文将以其为核心骨架结合仓库内 lib/http_aws_sigv4.c 等源码实现逐层展开。一、选项概览函数签名、默认值与返回值函数原型SYNOPSIS#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_AWS_SIGV4, char *param);默认值DEFAULT默认值为NULL即默认不启用 AWS SigV4 签名。文档明确说明应用传入该选项后无需保留字符串libcurl 内部会复制它多次调用该选项时最后一次设置的值覆盖之前的值传入NULL可再次关闭该功能。返回值RETURN VALUE与所有curl_easy_setopt(3)调用一样返回CURLcodeCURLE_OK (0)表示成功非零表示出错详见 libcurl-errors。二、param 参数格式provider1[:provider2[:region[:service]]]该选项接受一个字符串指针其中包含用于生成出站认证头的一系列参数格式为provider1[:provider2[:region[:service]]]四个字段的含义文档原文要点字段含义缺省时的处理provider1主提供商标识参与生成 Algorithm、date、request type、signed headers 等认证参数必填provider2次提供商标识同样参与上述认证参数的生成省略时复用 provider1region资源集合的地理区域从 URL 主机名中提取service云服务提供的功能名称从 URL 主机名中提取Test:Try 示例每个字段如何影响生成结果文档给出了非常直观的例子当参数为Test:Try时curl 使用算法时会生成Algorithm算法TEST-HMAC-SHA256date日期头x-try-date与X-Try-Daterequest type请求类型test4_requestsigned headers签名头列表SignedHeaderscontent-type;host;x-try-date如果只写test省略 provider2则 test 会被用于每一个生成的字符串例如算法变为TEST-HMAC-SHA256、日期头变为x-test-date等。从源码看参数解析规则在 lib/http_aws_sigv4.c 的parse_sigv4_params第 806858 行中参数按:依次切分并存入provider0、provider1、region、service四个字段provider0 不能为空否则返回CURLE_BAD_FUNCTION_ARGUMENT并报错first aws-sigv4 provider cannot be emptyprovider1 缺省时直接复用 provider0对应文档中 test 用于所有字符串的说法region / service 若未在参数中给出则从 URL 主机名提取见下一节每个字段最长不超过MAX_SIGV4_LEN64 字节源码第 280 行。三、region 与 service 的自动推导从 URL 主机名提取当参数中省略 region 或 service 时它们会从 URL 指定的主机名中提取。文档指出region 是资源集合的地理区域service 是云提供的一个功能二者缺省时均从主机名提取。从源码parse_sigv4_params第 835855 行可以看到具体推导逻辑对于形如service.region.example.com的主机名第一个标签.之前被提取为service若 region 也未给出则继续取下一个标签作为region若主机名中无法提取出 service 或 region分别返回CURLE_URL_MALFORMAT并报错aws-sigv4: service missing in parameters and hostname/aws-sigv4: region missing in parameters and hostname成功推导时会输出类似aws_sigv4: picked service xxx from host的信息日志infof。因此文档示例中https://service.region.example.com/uri配合provider1:provider2时service 与 region 会自动取自主机名而https://example.com/uri这类无法推导的主机名就必须在参数里显式给出region:service。四、与 CURLOPT_HTTPAUTH 的关系AWS_SIGV4 是一种特殊认证方式文档特别强调两点调用本选项会将CURLOPT_HTTPAUTH(3)设置为CURLAUTH_AWS_SIGV4直接用CURLOPT_HTTPAUTH(3)设置CURLAUTH_AWS_SIGV4位等价于用参数aws:amz调用本选项。这两点在 lib/setopt.c 第 20622076 行的case CURLOPT_AWS_SIGV4分支中得到印证result Curl_setstropt(data, STRING_AWS_SIGV4, ptr); /* Basic has been set by default; it needs to be unset here. */ if(CURL_EASY_STR(data, STRING_AWS_SIGV4)) s-httpauth CURLAUTH_AWS_SIGV4; else s-httpauth ~(uint32_t)CURLAUTH_AWS_SIGV4;即设置字符串后直接把httpauth覆盖为CURLAUTH_AWS_SIGV4源码注释也指出默认的 Basic 认证在此被清除置空字符串时则清除该认证位。另外该分支被#ifndef CURL_DISABLE_AWS包裹第 2061 行意味着编译时可用CURL_DISABLE_AWS宏裁剪掉此功能。认证头由谁输出在 lib/http.c 的output_auth_headers第 662668 行中当选中的认证方式为CURLAUTH_AWS_SIGV4且不是代理请求时调用Curl_output_aws_sigv4(data)生成认证头if((authstatus-picked CURLAUTH_AWS_SIGV4) !proxy) { /* this method is never for proxy */ auth AWS_SIGV4; result Curl_output_aws_sigv4(data); ... }可见 SigV4 签名只对目标服务器生效从不用于代理。五、完整示例最小可运行代码文档提供了如下示例此处补充了凭据设置的说明int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, https://service.region.example.com/uri); curl_easy_setopt(curl, CURLOPT_AWS_SIGV4, provider1:provider2); /* service and region can also be set in CURLOPT_AWS_SIGV4 */ curl_easy_setopt(curl, CURLOPT_URL, https://example.com/uri); curl_easy_setopt(curl, CURLOPT_AWS_SIGV4, provider1:provider2:region:service); curl_easy_setopt(curl, CURLOPT_USERPWD, MY_ACCESS_KEY:MY_SECRET_KEY); result curl_easy_perform(curl); curl_easy_cleanup(curl); } }要点凭据通过CURLOPT_USERPWD以access_key:secret_key形式提供源码中签名密钥取自data-state.creds的用户名与密码见 lib/http_aws_sigv4.c 第 1080、1086 行第一段 URL 的主机名service.region.example.com可自动推导 region/service因此参数只写provider1:provider2第二段 URL 无法推导必须在参数中显式给出region:service。命令行curl 工具中对应写法为curl --aws-sigv4 aws:amz:us-east-1:s3 \ --user MY_ACCESS_KEY:MY_SECRET_KEY \ https://bucket.s3.amazonaws.com/key六、签名过程源码级剖析Curl_output_aws_sigv4lib/http_aws_sigv4.c 第 11491230 行是整个签名的总入口按顺序完成以下步骤与 AWS SigV4 规范一一对应前置检查若设置了CURLOPT_PATH_AS_ISpath_as_is直接报错Cannot use sigv4 authentication with path-as-is flag第 11741177 行若用户已通过CURLOPT_HTTPHEADER提供了Authorization头则跳过签名第 11791181 行解析参数parse_sigv4_params解析 provider0/provider1/region/service计算载荷哈希get_payload_hash生成时间戳get_timestamp生成%Y%m%dT%H%M%SZ格式的 16 字节时间戳构造 Canonical Requestmake_canonical_request构造 String to Signmake_string_to_sign派生签名密钥并生成认证头sign_and_set_auth_headers。6.1 规范请求Canonical Requestmake_canonical_request第 925986 行将请求组装为HTTPRequestMethod\n CanonicalURI\n CanonicalQueryString\n CanonicalHeaders\n SignedHeaders\n HashedRequestPayload(hex)其中CanonicalURI由canon_path第 670695 行生成。默认对路径做 URI 编码保留 RFC 3986 非保留字符与/但s3、s3-express、s3-outposts三个服务不做额外 URL 编码见should_urlencode第 263277 行CanonicalQueryString由canon_query第 699804 行对查询串按拆分上限 128 个组件超出返回CURLE_TOO_LARGE、逐键值规范化编码再按键名其次按值排序拼接CanonicalHeaders由make_headers第 369535 行收集Host头、载荷哈希头与用户自定义头统一小写头名、折叠多余空白、按头名大小写敏感的字母序排序并合并重名头SignedHeaders规范头列表对应的头名清单以;连接。6.2 待签字符串String to Signmake_string_to_sign第 9881065 行生成Provider04-HMAC-SHA256\n RequestDateTime\n CredentialScope\n HashedCanonicalRequest源码细节算法行形如%.*s4-HMAC-SHA256其中 provider0先小写拼接再整体转大写第 10391047、10541056 行这就是文档中Test:Try生成TEST-HMAC-SHA256的原因请求类型形如%.*s4_request第 1005 行例如test4_request即文档所说的 request typeCredentialScope 为date/region/service/request_type第 10151020 行。6.3 签名密钥派生与 Authorization 头sign_and_set_auth_headers第 10671147 行签名密钥以%.*s4 密码构造如AWS4 secret keyprovider0 部分转大写第 10901095 行随后按 AWS 标准做四级 HMAC-SHA256 链式派生第 10971105 行先对 date 签名、再对 region、service、request_type、最后对 str_to_sign 签名最终生成认证头并写入data-req.hd_auth第 11111139 行Authorization: PROVIDER04-HMAC-SHA256 Credentialuser/scope, SignedHeaderslist, Signaturehex\r\n X-Provider1-Date: timestamp\r\n与文档中 TEST-HMAC-SHA256、x-try-date/X-Try-Date 的生成规律完全吻合。若x-provider1-date头已由用户通过CURLOPT_HTTPHEADER提供find_date_hdr第 7178 行则复用其时间戳不再重复添加日期头第 458490 行。七、载荷哈希与 x-provider2-content-sha256文档 NOTES 部分说明签名计算使用请求载荷的 SHA-256 校验和作为输入对于 POST 请求是对CURLOPT_POSTFIELDS(3)提供的请求体计算校验和其他请求如 GET使用空缓冲区的校验和对于 PUT 等请求可以自行在名为x-provider2-content-sha256的 HTTP 头中提供校验和。源码对应实现calc_payload_hash第 574592 行对data-set.postfields计算 SHA-256 并转十六进制postfieldsize 0时按strlen计算长度parse_content_sha_hdr第 542572 行先查找形如x-provider2-content-sha256的用户头找到则直接采用其值不再自行计算get_payload_hash第 860896 行载荷哈希以十六进制串形式出现在 Canonical Request 的最后一行以及Authorization头的签名计算输入中。对 aws:s3 的特殊处理x-amz-content-sha256 与 UNSIGNED-PAYLOAD文档特别指出对于aws:s3若请求中尚不存在该头curl 会为每个请求添加x-amz-content-sha256头当 S3 请求载荷未知时该头取特殊值UNSIGNED-PAYLOAD。源码中get_payload_hash第 879885 行判断provider0 aws且service s3时走calc_s3_payload_hash第 596631 行当请求方法为 GET/HEADempty_method、无文件载荷filesize 0或 POST 且载荷在内存中时仍计算真实哈希其他情况回退为字符串UNSIGNED-PAYLOAD宏S3_UNSIGNED_PAYLOAD第 594 行生成的x-provider1-content-sha256: hash头会附加到签名头列表与最终请求中。八、与 CURLOPT_HTTPHEADER / CURLOPT_HEADEROPT 的配合签名过程需要读取用户自定义头因此理解 CURLOPT_HTTPHEADER 的语义有助于正确使用本选项Authorization用户显式提供后libcurl 直接跳过 SigV4 生成lib/http_aws_sigv4.c 第 11791181 行x-provider1-date用户提供后作为时间戳来源不再自动生成日期头find_date_hdrx-provider2-content-sha256用户提供后作为载荷哈希来源PUT 等请求可借此对未知载荷做自定义哈希Host若用户未提供签名头中自动加入Host: [host]:[port]make_headers第 397408 行用户头中形如name:无值用于移除同名内部头、name;用于发送空值头的处理规则同样适用于签名头收集第 417454 行注释。若需在签名头的生成中统一控制这些头的处理方式可参考 CURLOPT_HEADEROPT。九、注意事项与限制NOTES综合文档与源码使用本选项必须注意覆盖其他认证方式设置本选项会覆盖CURLOPT_HTTPAUTH(3)中可能设置的其他认证类型lib/setopt.c 第 20622074 行且该认证方式不能与其他认证类型组合使用仅限非代理签名头只发给目标服务器不会用于代理认证lib/http.c 第 662 行与 CURLOPT_PATH_AS_IS 冲突设置CURLOPT_PATH_AS_IS后使用 SigV4 会返回CURLE_BAD_FUNCTION_ARGUMENT第 11741177 行凭据来源CURLOPT_USERPWD的user:password分别作为 access key 与 secret key时间戳默认取当前 UTC 时间格式YYYYMMDDTHHMMSSZ调试构建下可用环境变量CURL_FORCETIME强制固定时间get_timestamp第 904911 行这也是测试套件依赖 Debug 特性固定时间的原因。十、测试验证仓库如何保证实现正确仓库为 SigV4 提供了大量测试可作为验证与学习参照tests/data/test1933使用单 provider 并通过 URL 携带凭据验证生成的请求头。其期望输出见verify段展示了完整结果GET /%TESTNUMBER/testapi/test HTTP/1.1 Host: 127.0.0.1:9000 Authorization: XXX4-HMAC-SHA256 Credentialxxx/19700101/0/127/xxx4_request, SignedHeaderscontent-type;host;x-xxx-date, Signature3d8e00a02e437211a596143dcd590fcc805b731365c68f7f48951ea6eda39c4f X-Xxx-Date: 19700101T000000Z可以看到XXX4-HMAC-SHA256、xxx4_request、x-xxx-date与X-Xxx-Date的生成规律和文档中 Test:Try 的推导规则完全一致tests/data/test1979 与 tests/data/test1980分别对canon_path与canon_query做单元测试源码中对应函数标注了/* unittest 1979 */与/* unittest 1980 */其余如 tests/data/test1934tests/data/test1938、tests/data/test1955tests/data/test1959 等覆盖了多 provider、S3、代理、重定向等不同场景。十一、相关选项速查选项作用CURLOPT_HTTPAUTH设置认证方式CURLAUTH_AWS_SIGV4与本选项等价CURLOPT_HTTPHEADER自定义 HTTP 头可覆盖 Authorization、日期头、载荷哈希头CURLOPT_HEADEROPT控制自定义头是否作用于代理请求CURLOPT_PROXYAUTH代理认证方式SigV4 不用于代理结语CURLOPT_AWS_SIGV4把 AWS SigV4 的完整签名流程Canonical Request 构造、String to Sign 生成、HMAC 密钥派生、认证头输出封装进 curl 内部。只需提供 provider 组合、凭据与目标 URLlibcurl 就会自动推导 region/service、计算载荷哈希并生成符合规范的签名请求S3 等特殊服务还有UNSIGNED-PAYLOAD与自动x-amz-content-sha256的适配。对于需要对接 AWS 或兼容 SigV4 云服务的应用这是比手动实现签名更可靠、更省力的选择。【免费下载链接】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),仅供参考
返回列表