【问题标题】:CloudFront "MalformedPolicy" error with signed URLs带有签名 URL 的 CloudFront“MalformedPolicy”错误
【发布时间】:2017-08-18 13:58:09
【问题描述】:

我需要使用 PHP 创建带有自定义策略的签名 CloudFront URL,但无论我做什么,我的策略显然都是“格式错误的”。 这是函数中生成的示例策略:

{"Statement":{"Resource":"https://d15xojelh58w5d.cloudfront.net/memo/kwz/cvyhkfdqn5oz0z1dz5at4z4s1jsn.kwz","Condition":{"DateLessThan":{"AWS:EpochTime":1490463203},"IpAddress":{"AWS:SourceIp":"1.2.3.4/32"}}}}

生成的网址:

https://d15xojelh58w5d.cloudfront.net/memo/kwz/cvyhkfdqn5oz0z1dz5at4z4s1jsn.kwz?Policy=eyJTdGF0ZW1lbnQiOnsiUmVzb3VyY2UiOiJodHRwczovL2QxNXhvamVsaDU4dzVkLmNsb3VkZnJvbnQubmV0L21lbW8va3d6L2N2eWhrZmRxbjVvejB6MWR6NWF0NHo0czFqc24ua3d6IiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNDkwNDYzMjAzfSwiSXBBZGRyZXNzIjp7IkFXUzpTb3VyY2VJcCI6IjEuMi4zLjQvMzIifX19fQ__&Signature=MmBPtpipFLuNwaPliGLJajG4gJ7INwD0ptFdxPFYQP9CT-luq6W0SrAs9O9CqbJPHoukXwDzG~c88Rr5I2I9KP5QwD8MHpogGh~3SM3gBYm8ao0Zm7a5C9tWnBVRCtzuGrCrFstK-qLswWmqo6tNiOynSuFpvm9uDe3C8oWE2RzSZavEXoL35D3F8y98NeM0aOJe37EeSpdz3lrZZxei2TugoO-OmnApXa2YYJR2HiQ2l0t8paxcb3xyhCK1c1AR51uOpWLm63k~d0eNZJGo3x0Y6bx0GBqafdvV6jiUv6PbhiMC1ZcTxGnZhLmsz3~ONsEvaR1jyyOPt6y9Nos8yA__&Key-Pair-Id=APKAJ6RV6ACUX5M5IAOQ

代码:

function cloudfront_sign($url, $expiry = null, $ipLock = true) {
    $policy = array(
        'Statement' => array(
            'Resource' => $url,
            'Condition' => array(),
        ),
    );

    if(!$expiry || $expiry <= time()) $expiry = 2147483647; // CloudFront *requires* an expiry date, so set to 03:14:07 UTC on Tuesday, 19 January 2038 if one is not provided
    $policy['Statement']['Condition']['DateLessThan'] = array('AWS:EpochTime' => $expiry);
    if($ipLock) $policy['Statement']['Condition']['IpAddress'] = array('AWS:SourceIp' => $_SERVER['REMOTE_ADDR'].'/32');

    $signer = new Aws\CloudFront\UrlSigner($_config['keyID'], $_config['keyPath']);

    $jsonPolicy = json_encode($policy, JSON_UNESCAPED_SLASHES);

    $url = $signer->getSignedUrl($url, null, $jsonPolicy);

    return $url;
}
$url = kaeru_cloudfront_sign('https://d15xojelh58w5d.cloudfront.net/memo/kwz/cvyhkfdqn5oz0z1dz5at4z4s1jsn.kwz', 1490463203);

【问题讨论】:

    标签: php aws-sdk amazon-cloudfront aws-access-policy


    【解决方案1】:

    我可以确切地告诉你发生了什么,但我不能告诉你原因,除非这是你(显然)使用的 SDK 版本中的错误。

    政策文件确实格式不正确,签名也是。

    看来实际上并没有做错什么。

    我假设您熟悉 base64,其中 8 位数据扩展为每八位字节 6 位,以允许通过使用 64 个符号(其中 64 是 2^ 6,6位离散值的个数)。

    0-9A-Za-z 组成 10 + 26 + 26 = 62 个必要符号,然后有 +/ 使总符号达到 64,但由于可能有最后一个八位字节的输出只有 2 或 4 位输入编码,第 65 个符号 = 用于“填充”表示先前符号中有未使用的位不代表输入数据。因此,任何 base64 表示总是以 0、1 或 2 个= 符号结尾。出于这个原因,base64 编码的值在任何地方都不能有=,除非在末尾。事实证明这很重要,如下所示。

    符号 + / = 的选择对于 URL 来说是很糟糕的,因为许多用户代理(浏览器和 HTTP 客户端库)在 url 转义(也称为 url-encoding 或 percent-encoding)。

    + 有时被认为等同于%20(空格),有时它被转义为%2B...= 用于分隔查询字符串中的字段,因此一些用户代理会转义它是%3D... 有时/ 可能会转义为%2F... 所有这些都会导致互操作性的噩梦。

    (即使 S3 本身也至少有与不正确的 url-escaping 相关的错误,该错误已经存在太久无法修复,现在,因为它会破坏为预测 S3 的错误行为而编写的所有代码.但这与手头的问题无关。)

    CloudFront 的设计人员巧妙地解决了这个问题。

    CloudFront 将三个可能有问题的字符音译如下:

    + => -
    / => _
    = => ~
    

    这是因为字符 - _ ~ 在 URL 中不太容易出错。

    但不知何故,在您的代码中,这种翻译是错误的。

    &Signature=...~ONsEvaR1jyyOPt6y9Nos8yA__&Key-...
    

    这绝对是错误的。签名中间的~ 不可能是有效的。如上所述,~=,并且只能在 base64 编码的 end 处有效。这意味着签名和策略末尾的__也是错误的,实际上应该是~~

    ?Policy=ey...X19fQ__&Signature=
    

    您可以通过更换它们来部分确认这一点。将策略末尾的__ 更改为~~,您会发现不再看到Malformed Policy 错误,因为这似乎是策略的唯一问题。

    不幸的是,由于该策略不包含任何 ~-,因此无法得出关于需要哪些字符替换才能使签名有效的结论 - 并不是说​​这是正确的解决方案,但它应该确实有效。问题是,我们不知道是只有~_相互转置,还是三个(包括-)都不正确。

    但这显然是生成最终 URL 的实际代码的问题,不是您提供给它的 JSON 策略文档的问题。

    【讨论】:

    • 确实,你是对的;最后,我转而使用 Aws\CloudFront\CloudFrontClient 中的 getSignedUrl 函数(基于文档深处隐藏的一些示例代码),这似乎工作正常,很奇怪。不过谢谢!
    猜你喜欢
    • 2015-10-10
    • 2013-01-15
    • 2020-02-26
    • 2016-12-10
    • 2012-07-14
    • 2017-10-03
    • 2023-03-21
    • 2013-07-01
    • 2021-03-22
    相关资源
    最近更新 更多