【问题标题】:Issue decrypting Alexa request signature using openssl_public_decrypt使用 openssl_public_decrypt 解密 Alexa 请求签名
【发布时间】:2026-02-10 13:10:01
【问题描述】:

我正在为validating incoming requests from Amazon Alexa 实施验证器。我在第 5 步和第 6 步,其中状态:

5) base64-decode 请求上的 Signature 头值以获得加密的签名。

6) 使用从签名证书中提取的公钥解密加密的签名以生成断言的哈希值。

我已经成功地从 PEM 编码的 X.509 证书中提取了公钥:

$publicKey = openssl_pkey_get_public($pem);
$keyData = openssl_pkey_get_details($publicKey);

返回我的公钥。然后我尝试像这样解密签名:

openssl_public_decrypt(base64_decode($this->signature), $decryptedSignature, $keyData['key']);

 

这应该返回我请求正文的sha1 哈希,以便我与实际请求正文进行比较,但我从$decryptedSignature 返回的似乎不是sha1 哈希。我希望我遗漏了一些明显的东西,但我看不到它。

为了让事情变得更简单,这是从 Alexa 的测试服务返回的真实生活中的 base64_encoded 签名标头:

DElCRMK3sXkhmnmu3D2HzVyuLHJ3JkABuBy2LCRX + winUhV6pSC9p1ASKFi9DzESsCyQ74izlFSvi3zECbSbT45bI38JpARJlal81YpWKxz2zTX + y6Qi +我们/ bFHHpU4gZO7nTTVQDWG4ua6EuWDTt3jL4B + hPOzO1OKix0jHKQldaTd9meyanttZ5QK7WotBeS6xU + PUM / dmiQ + LM39NERUCrCRyeU07PUdQt + L5PI8MehMz5ClHFOTWgyjE / J / b4zrX4weppb / KJhqQVmbw79BWMPuaSwf6BIHyf + 4 + / NSMmoaJ2WMKKEXf1aV7ac71QFFx9pw4P0BX7DK / hqy98Q == P>

这是从https://s3.amazonaws.com/echo.api/echo-api-cert-4.pem提取的公钥:

-----开始公钥----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnK+zBruRA1TnbgQGxE+b 4XiTTZyDkGwJ6068AGsXQmgt9lVhC8CTTC4wdR5NXosboV6/63worQCNo412csBV jUy3H1/VEs+5Kv+AiAOUuKoBfEU8zAvHCc7GmOKUgNidcDA0MSpx3ZTMSGGbkfaL ikRzne6nFZ6jNOnkqTtGD6SrCIYgLNArScYoPzIcXEypHFrognzrR4Ee0YcefGZy S81Yqev/lli01dAgRvpnAty68rYTmxkNhzUSG6IIbFHIxXJKAETAkGiKJcgZpfG2 1Ok5Dk3yGrESY/ID5OnxvMxiXSnXwht8JD6bd15ui0tPDa85B0jpZLloqQZe26oR owIDAQAB -----结束公钥-----

【问题讨论】:

    标签: php alexa pem php-openssl


    【解决方案1】:

    好的,我已经意识到我的错误了。解密后的签名以二进制形式返回,所以我需要这样做:bin2hex($decryptedSignature) 以获取 sha1 哈希。奇怪的是,返回的签名哈希前面有 30 个额外的字符,所以实际的 Alexa 哈希比较需要是:

    public function compareHashes($pem) {
    
      $publicKey = openssl_pkey_get_public($pem);
    
      openssl_public_decrypt(base64_decode($this->signature), $decryptedSignature, $publicKey);
    
      $decryptedSignature = hex2bin($decryptedSignature);
    
      return sha1($this->responseBody) === substr($decryptedSignature, 30);
    }
    

    无论如何,一旦我通过了 Alexa 认证,我将开源我的 Alexa 验证类并在此处添加一个链接。

    编辑

    我现在通过了认证,所以这是我为 Alexa 验证编写的课程:https://github.com/craigh411/alexa-request-validator

    【讨论】:

    • 您好,您的技能通过认证了吗?我正在使用这个库github.com/MayBeTall/Alexa-PHP-Endpoint 你能帮我如何进行证书验证吗?请。谢谢。
    • @gowri 是的,我的技能通过了认证,我已将传入 Alexa 请求的验证器放在我的github page 上,您可以免费使用。实际上,我之所以写这个,是因为我找不到所需验证的任何其他正确实现;有些只进行了任意检查,有些是意大利面条代码(并且遗漏了某些方面),有些没有正确验证签名链 url 或哈希。
    • 谢谢回复。还有一件事,我应该补充一点,所有意图中的验证器都只在enters 意图中。而且我正在以http_response_code(400) 之类的所有意图返回HTTP 状态代码,这是正确的。