You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:PHP/cURL实现AWS S3对象DELETE请求(Signature V4签名错误)

解决AWS S3 DELETE请求签名不匹配问题

核心问题排查与修复

以下是导致The request signature we calculated does not match the signature you provided错误的关键原因及修复方案:

  1. 未定义变量引发Canonical URI错误
    代码中定义了$object_key = '/filename.jpg',但构建Canonical Request时误用了未定义的$new_object_key,直接导致Canonical URI无效,这是签名不匹配的常见诱因。

  2. 请求URL未指向目标对象
    删除S3对象的DELETE请求必须将URL指向具体对象,而非仅桶地址。正确的URL格式应为https://examplebucket.s3.amazonaws.com/filename.jpg,而非仅https://examplebucket.s3.amazonaws.com。

  3. Canonical URI编码不规范
    对象键需严格按照AWS SigV4规范进行URL编码:仅编码特殊字符,保留路径斜杠,且需单独编码路径中的每个分段(如folder/filename.jpg需分别编码folder和filename.jpg后再拼接)。可使用rawurlencode()实现规范编码。

  4. 请求头顺序一致性问题
    Canonical Headers必须按字母顺序排序,虽然原代码中数组顺序恰好符合要求,但显式使用ksort()排序能避免因数组顺序变化导致的签名错误。

修复后的完整代码

/*
* AWS S3 SigV4认证实现
*/

// 替换为你的实际配置参数
$access_key = '你的Access Key';
$secret_key = '你的Secret Key';
$region = 'us-east-1'; // 桶所在区域,需与实际一致
$bucket_host = 'examplebucket.s3.amazonaws.com';
$object_key = 'filename.jpg'; // 目标对象键,无需开头斜杠

$date_long = gmdate('Ymd\THis\Z');
$date_short = gmdate('Ymd');
$credential = $access_key . '/' . $date_short . '/' . $region . '/s3/aws4_request';

// 规范生成Canonical URI:编码对象键,处理路径分段
$encoded_key_parts = array_map('rawurlencode', explode('/', $object_key));
$canonical_uri = '/' . implode('/', $encoded_key_parts);

// DELETE请求无payload,使用空字符串的SHA256哈希
$hashed_payload = strtolower(hash("sha256", ""));

// 按字母顺序排序请求头,确保Canonical Headers顺序正确
$request_headers = array(
    'host' => $bucket_host,
    'x-amz-content-sha256' => $hashed_payload,
    'x-amz-date' => $date_long,
);
ksort($request_headers);

$signed_headers_string = strtolower(implode(';', array_keys($request_headers)));

// 构建Canonical Request
$canonical_request = "DELETE\n";
$canonical_request .= $canonical_uri . "\n";
$canonical_request .=  "\n"; // 无查询参数,留空行

foreach ($request_headers as $header => $value) {
    $canonical_request .= strtolower($header) . ':' . trim($value) . "\n";
}

$canonical_request .= $signed_headers_string . "\n";
$canonical_request .= $hashed_payload;

// 构建String to Sign
$string_to_sign = "AWS4-HMAC-SHA256\n";
$string_to_sign .= $date_long . "\n";
$string_to_sign .= $date_short . '/' . $region. "/s3/aws4_request\n";
$string_to_sign .= hash('sha256', $canonical_request);

// 生成签名密钥(二进制哈希)
$sig_key = hash_hmac('sha256', $date_short, 'AWS4' . $secret_key, true);
$sig_key = hash_hmac('sha256', $region, $sig_key, true);
$sig_key = hash_hmac('sha256', 's3', $sig_key, true);
$sig_key = hash_hmac('sha256', 'aws4_request', $sig_key, true);
$signature = hash_hmac('sha256', $string_to_sign, $sig_key);

// 构建cURL请求头
$curl_headers = array(
    "Authorization: AWS4-HMAC-SHA256 Credential={$credential},SignedHeaders={$signed_headers_string},Signature={$signature}",
);

foreach($request_headers as $header => $value) {
    $curl_headers[] = "{$header}: {$value}";
}

// 初始化cURL请求
$curl = curl_init();
$request_url = "https://{$bucket_host}{$canonical_uri}";

curl_setopt_array($curl, array(
  CURLOPT_URL => $request_url,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLINFO_HEADER_OUT => true,
  CURLOPT_HEADER => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'DELETE',
  CURLOPT_HTTPHEADER => $curl_headers
));

$response = curl_exec($curl);
curl_close($curl);

// 调试用:输出响应内容
var_dump($response);

额外调试建议

  • 开启S3服务器访问日志,对比AWS计算的Canonical Request与本地生成的内容,找出差异点
  • 打印$canonical_request和$string_to_sign,与AWS官方示例的格式、内容逐一核对
  • 确认$region与桶实际所在区域完全一致(如us-east-1不可简写为us-east)
  • 验证Access Key拥有目标对象的s3:DeleteObject权限

内容的提问来源于stack exchange,提问作者Dave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 04:17:05