AWS S3请求SignatureDoesNotMatch问题排查与替代方案求助
问题描述
发起AWS S3请求时遭遇签名不匹配错误:
The request signature we calculated does not match the signature you provided
已遵循AWS文档故障排查步骤,对比生成签名与请求签名显示一致,但仍报错。使用AssumeRoleWithWebIdentity获取的临时凭证,角色、令牌等参数设置正确,且无法使用AWS库或CLI,仅能通过纯HTTP curl发起请求。
已排查内容
- 日期格式一致
- 规范请求字符串符合预期
- 待签名字符串正确
- 签名计算结果匹配
- Authorization头无误
简化后的请求脚本
AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_SESSION_TOKEN= AWS_SERVICE='s3' AWS_REGION="us-east-1" AWS_SERVICE_ENDPOINT_URL="xxxx-xxx.s3-accesspoint.us-east-1.amazonaws.com" AWS_S3_PATH="/xxx/xxx.zip" CURRENT_DATE_DAY="$(date -u '+%Y%m%d')" CURRENT_DATE_ISO8601="${CURRENT_DATE_DAY}T$(date -u '+%H%M%S')Z" HTTP_REQUEST_PAYLOAD_HASH="$(echo -n | openssl dgst -sha256 |cut -d ' ' -f 2)" HTTP_REQUEST_SIGNED_HEADERS="host;x-amz-content-sha256;x-amz-date;x-amz-security-token" HTTP_CANONICAL_REQUEST_URI="${AWS_S3_PATH}" HTTP_CANONICAL_REQUEST_HEADERS="host:${AWS_SERVICE_ENDPOINT_URL}\nx-amz-content-sha256:${HTTP_REQUEST_PAYLOAD_HASH}\nx-amz-date:${CURRENT_DATE_ISO8601}\nx-amz-security-token:${AWS_SESSION_TOKEN}" HTTP_CANONICAL_REQUEST="GET\n${HTTP_CANONICAL_REQUEST_URI}\n\n${HTTP_CANONICAL_REQUEST_HEADERS}\n\n${HTTP_REQUEST_SIGNED_HEADERS}\n${HTTP_REQUEST_PAYLOAD_HASH}" #echo ${HTTP_CANONICAL_REQUEST} # Create the signature. # Usage: # create_signature hmac_sha256() { KEY="$1" DATA="$2" echo -n "$DATA" | openssl dgst -sha256 -mac HMAC -macopt "$KEY" | sed 's/^.* //' } hash_sha256() { echo -n "${1}" | openssl dgst -sha256 | sed 's/^.* //' } DATE_KEY=$(hmac_sha256 key:"AWS4$SECRET_ACCESS_KEY" $CURRENT_DATE_DAY) DATE_REGION_KEY=$(hmac_sha256 hexkey:$CURRENT_DATE_DAY $AWS_REGION) DATE_REGION_SERVICE_KEY=$(hmac_sha256 hexkey:$DATE_REGION_KEY $AWS_SERVICE) HEX_KEY=$(hmac_sha256 hexkey:$DATE_REGION_SERVICE_KEY "aws4_request") # Generate canonical request hash CANONICAL_REQUEST_HASH=$(hash_sha256 ${HTTP_CANONICAL_REQUEST}) #echo ${CANONICAL_REQUEST_HASH} stringToSign="AWS4-HMAC-SHA256\n${CURRENT_DATE_ISO8601}\n${CURRENT_DATE_DAY}/${AWS_REGION}/${AWS_SERVICE}/aws4_request\n${CANONICAL_REQUEST_HASH}" echo ${stringToSign} # Generate signature SIGNATURE=$(hmac_sha256 hexkey:$HEX_KEY ${stringToSign}) #echo ${SIGNATURE} HTTP_REQUEST_AUTHORIZATION_HEADER="AWS4-HMAC-SHA256 Credential=${AWS_ACCESS_KEY_ID}/${CURRENT_DATE_DAY}/${AWS_REGION}/${AWS_SERVICE}/aws4_request, SignedHeaders=${HTTP_REQUEST_SIGNED_HEADERS}, Signature=${SIGNATURE}" echo ${HTTP_REQUEST_AUTHORIZATION_HEADER} echo "Downloading https://${AWS_SERVICE_ENDPOINT_URL}${AWS_S3_PATH} to guid.zip" curl --location "https://${AWS_SERVICE_ENDPOINT_URL}${AWS_S3_PATH}" \ -H "Authorization: ${HTTP_REQUEST_AUTHORIZATION_HEADER}" \ -H "x-amz-content-sha256: ${HTTP_REQUEST_PAYLOAD_HASH}" \ -H "X-Amz-Date: ${CURRENT_DATE_ISO8601}" \ -H "X-Amz-Security-Token: ${AWS_SESSION_TOKEN}" \
排查思路
换行符解析错误
Bash中直接用\n拼接字符串不会被解析为实际换行,会被当作普通字符,而AWS签名要求规范请求/待签名字符串必须用实际换行符分隔。需改用$'...'语法让Bash解析转义字符。HMAC密钥生成逻辑错误
脚本中DATE_REGION_KEY的生成参数错误,应使用DATE_KEY作为密钥,而非$CURRENT_DATE_DAY,这会导致后续签名密钥完全错误。Host头格式问题
检查AWS_SERVICE_ENDPOINT_URL是否包含https://前缀,Host头需仅保留域名部分,不能带协议,否则会导致签名校验失败。URI编码一致性
若S3路径包含特殊字符(如空格、中文),需按AWS规范对Canonical URI进行编码(除/外),确保与实际请求URI完全一致。Session Token完整性
确认规范请求中的x-amz-security-token值与curl请求中发送的完全一致,无空格、截断或转义错误。
替代方案
方案1:使用预签名URL
在具备AWS CLI环境的机器上生成预签名URL,直接用curl访问即可,无需自行计算签名:
aws s3 presign s3://bucket-name/xxx/xxx.zip --endpoint-url https://xxxx-xxx.s3-accesspoint.us-east-1.amazonaws.com --region us-east-1
生成后直接执行curl 预签名URL -o guid.zip完成下载。
方案2:修复脚本核心错误
针对排查到的问题修改脚本关键部分:
# 修正规范请求的换行符处理 HTTP_CANONICAL_REQUEST=$'GET\n'"${HTTP_CANONICAL_REQUEST_URI}"$'\n\n'"${HTTP_CANONICAL_REQUEST_HEADERS}"$'\n\n'"${HTTP_REQUEST_SIGNED_HEADERS}"$'\n'"${HTTP_REQUEST_PAYLOAD_HASH}" # 修正HMAC密钥生成逻辑 DATE_KEY=$(hmac_sha256 key:"AWS4${AWS_SECRET_ACCESS_KEY}" "${CURRENT_DATE_DAY}") DATE_REGION_KEY=$(hmac_sha256 hexkey:"${DATE_KEY}" "${AWS_REGION}") DATE_REGION_SERVICE_KEY=$(hmac_sha256 hexkey:"${DATE_REGION_KEY}" "${AWS_SERVICE}") HEX_KEY=$(hmac_sha256 hexkey:"${DATE_REGION_SERVICE_KEY}" "aws4_request") # 修正待签名字符串的换行符 stringToSign=$'AWS4-HMAC-SHA256\n'"${CURRENT_DATE_ISO8601}"$'\n'"${CURRENT_DATE_DAY}/${AWS_REGION}/${AWS_SERVICE}/aws4_request"$'\n'"${CANONICAL_REQUEST_HASH}"
内容的提问来源于stack exchange,提问作者smootherbug

