更新谷歌 AMP 缓存网址签名验证错误



我正在尝试更新 Google AMP 缓存中的 Google AMP 网页,但收到网址签名验证错误。

我的代码:

Dim tStamp As String = GetUnixTimeStampFromDateTime(DateTime.Now).ToString
Dim ampBaseUrl As String = "https://www-example-com.cdn.ampproject.org"
Dim signatureUrl As String = "/update-cache/c/s/www.example.com/articles/278/myarticle/amp?amp_action=flush&amp_ts=" + tStamp
Dim rsa As RSA = certificate.GetRSAPrivateKey()
Dim data() As Byte = System.Text.Encoding.Unicode.GetBytes(signatureUrl)
Dim sig() As Byte = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
Dim AMPURLSignature As String = EncodeTo64(sig.ToString)

编码功能:

Public Shared Function EncodeTo64(ByVal toEncode As String) As String
Dim toEncodeAsBytes As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode)
Dim returnValue As String = System.Convert.ToBase64String(toEncodeAsBytes)
Return returnValue
End Function

我尝试使用此网址调用谷歌AMP缓存。

现在,我收到一个 403 错误:

您的客户端无权获取 URL/update-cache/c/s/www.example.com/articles/278/myarticle/amp?amp_action=flush&amp_ts=1523016476&amp_url_signature=U2lzdGVtLkJ5dGVbdQ。网址签名验证错误。这就是我们所知道的。

我发现谷歌示例代码不够清晰:https://developers.google.com/amp/cache/update-cache

我的问题与签名 URL 有关:

  1. 我使用的是文章 AMP 网址还是常规网址?
  2. 是否需要在签名 URL 中包含amp_actionamp_ts的查询字符串参数?还是在对 URL 进行签名后再附加这些内容?
  3. 我应该将上述ampBaseUrl附加到我的signatureUrl变量中还是不需要?

更新 1

根据@CodeFuller的建议,我检查了 URL,并收到了一条Verified OK消息。我还处理了第 2 步:

  1. API密钥匹配:https://www.toptrouwen.nl/.well-known/amphtml/apikey.pub 匹配 https://www-toptrouwen-nl.cdn.ampproject.org/r/s/www.toptrouwen.nl/.well-known/amphtml/apikey.pub
  2. 从我的服务器以文本/纯文本形式提供 apikey.pub
  3. 通过HTTPS和公开提供APIKEY.pub
  4. 在机器人中添加了禁止:用户代理:* 禁止:/.well-known/amphtml/apikey.pub

更新 2

是的,使用新代码,我也得到了验证Verified OK

此网址生成: https://www-toptrouwen-nl.cdn.ampproject.org/update-cache/c/s/www.toptrouwen.nl/artikelen/132/het-uitwisselen-van-de-trouwringen-hoe-voorkom-je-bloopers/amp?amp_action=flush&_ts=1523138180&_url_signature=tKPO3k624ybwxoEynqN8oI3/UDxhq1TF8jX9aKeVyL0IWLUODXuMB7ansP0t1+/5Lm2V7RYZbUWxt2Whh7+LFEmfQFGJJE/iPtoBVsqrdb5356QwiIrDHOzY+3z5dASZxYlAwlfzUFdonGyDsh/UlCjjvvNahFEWzHOpB5JQxJQ1Wn0kGLQUF1v2u47abbae6cNQBm3YB/0Z1FLfTJLM1oOEOSDh9vQH1SqO/6SoYtUhSQjSrYdl/g5O0QJ7A9pKUxOPfgVJM0l8Sgb66cVeWWoWq0WIFe24RPXUMl9tIFFZ1TY2R+ZpIMvpEAPDjCsdGPo7KTWqGb4qfoTBINJmtQ==

然后我得到错误Required query parameter 'amp_url_signature' missing.(与amp_参数拙劣的早期问题有关。

然后,我将 URL 参数重命名为正确的名称:https://www-toptrouwen-nl.cdn.ampproject.org/update-cache/c/s/www.toptrouwen.nl/artikelen/132/het-uitwisselen-van-de-trouwringen-hoe-voorkom-je-bloopers/amp?amp_action=flush&amp_ts=1523138180&amp_url_signature=tKPO3k624ybwxoEynqN8oI3/UDxhq1TF8jX9aKeVyL0IWLUODXuMB7ansP0t1+/5Lm2V7RYZbUWxt2Whh7+LFEmfQFGJJE/iPtoBVsqrdb5356QwiIrDHOzY+3z5dASZxYlAwlfzUFdonGyDsh/UlCjjvvNahFEWzHOpB5JQxJQ1Wn0kGLQUF1v2u47abbae6cNQBm3YB/0Z1FLfTJLM1oOEOSDh9vQH1SqO/6SoYtUhSQjSrYdl/g5O0QJ7A9pKUxOPfgVJM0l8Sgb66cVeWWoWq0WIFe24RPXUMl9tIFFZ1TY2R+ZpIMvpEAPDjCsdGPo7KTWqGb4qfoTBINJmtQ==

然后我得到:404 Failed to decode amp_url_signature,我认为这是因为URL中有+字符。当我删除它们时,我再次出现错误URL signature verification error

我不认为 UTC 时间戳目前是一个问题,因为我之前已经看到如果时间戳不正确,谷歌会抛出错误。

有两个最常见的URL signature verification error原因:

  1. 签名计算不正确。

    因此,首先要验证签名是否确实有效。将签名的 URL 和结果签名保存到某些文件:

    Dim signatureUrl As String = "/update-cache/c/s/www.example.com/articles/278/myarticle/amp?amp_action=flush&amp_ts=" + tStamp
    ' ...
    Dim sig() As Byte = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
    File.WriteAllText("url.txt", signatureUrl)
    File.WriteAllBytes("signature.bin", sig)
    

    然后使用 openssl 工具验证签名:

    OpenSSL.exe DGST -SHA256 -签名签名.bin -验证 公钥.pem 网址.txt

    如果输出为

    已验证正常

    那么你的签名是可以的,你应该在其他地方搜索问题(见项目#2)。

    如果输出为

    验证失败

    然后,您应该重新检查签名计算的例程。

    上面命令中的公钥.PEM是PEM格式的公钥。它应以以下行开头:

    -----BEGIN PUBLIC KEY-----

    如果您有证书文件(以-----BEGIN CERTIFICATE-----开头),则可以使用以下命令获取它的 PEM:

    openSSL.exe x509 -pubkey -noout -in publickey.cer> publickey.pem

  2. 如果签名验证成功,则应检查您的公钥是否可通过 Web 访问。更新 AMP 内容符合以下要求:

    要进行签名验证,您必须在 AMP 文档网域上的固定位置提供公共 RSA 密钥(要生成密钥,请参阅生成 RSA 密钥)。例如:

    https://example.com/.well-known/amphtml/apikey.pub

    • 公钥不得是机器人。

    • 网址必须是 HTTPS。

    • 该域必须是您要更新的确切域,而不是子域或超级域。

    • 您必须以 PEM 格式发布密钥,并使用内容类型"文本/纯文本"提供密钥。

    因此,如果您的 AMP 基本网址https://www.test.com,请检查您的公钥是否可通过以下网址访问:https://www.test.com/.well-known/amphtml/apikey.pub

以下是您其他问题的答案:

我是否需要在签名 URL 中包含查询字符串参数amp_action和amp_ts?还是在对 URL 进行签名后再附加这些内容?

是的,您应该在计算签名的 URL 中包含amp_actionamp_ts

我应该将上面的ampBaseUrl附加到我的signatureUrl变量中,还是不需要这样做?

如前所述,更新AMP内容一文:

AMP 缓存主机名 (cdn.ampproject.org) 已从 签名,允许向多个 AMP 提交相同的签名请求 缓存运算符。

因此,不应将ampBaseUrl包含在计算签名的 URL 中。

更新

我在将签名附加到 URL 的代码中发现了另一个错误:

Dim AMPURLSignature As String = EncodeTo64(sig.ToString)

sig.ToString将导致"System.Byte[]"字符串传递给EncodeTo64,而不是实际的签名字节。因此,在更新缓存 URL 时附加了不正确的签名。将上述调用替换为以下内容(不再需要EncodeTo64):

Dim AMPURLSignature As String = System.Convert.ToBase64String(sig)

另一个可能的问题是您使用的时间戳不满足以下要求:

值应为当前时间(以秒为单位),该时间必须在当前时间之前或之后 1 分钟。

您将DateTime.Now传递给GetUnixTimeStampFromDateTime()但它应该是 UTC 时间,而不是本地时间。尝试将tStamp计算替换为:

Dim tStamp As String = CInt((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds).ToString

此外,请确保在生成 URL 后立即调用update-cache以便当前时间与时间戳相比在 1 分钟间隔内。而且您的系统时间应该精确。

请在上述修复后重新检查签名验证是否通过。

更新 2(关于签名中的+/字符)

AMP 缓存更新签名应采用 base4 编码的变体:

使用 base64 的 Web 安全变体对二进制 RSA 签名进行编码

因此,另一个必需的修复方法是将+/字符替换为-_.

更改以下调用

Dim AMPURLSignature As String = System.Convert.ToBase64String(sig)

跟:

Dim AMPURLSignature As String = ToWebSafeBase64(sig)
' ...
Private Function ToWebSafeBase64([data]() As Byte) As String
Dim base64 = System.Convert.ToBase64String(data)
base64 = base64.Replace("+", "-")
base64 = base64.Replace("/", "_")
Return base64
End Function

更新 3

以下是应生成正确update-cacheURL 的最终代码(基于可用文档):

Module MainModule
Sub Main()
Dim tStamp As String = CInt((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds).ToString
Dim ampBaseUrl = "https://www-toptrouwen-nl.cdn.ampproject.org"
Dim signatureUrl As String = "/update-cache/c/s/www.toptrouwen.nl/artikelen/132/het-uitwisselen-van-de-trouwringen-hoe-voorkom-je-bloopers?amp_action=flush&amp_ts=" + tStamp
Dim data() As Byte = System.Text.Encoding.ASCII.GetBytes(signatureUrl)
Dim certificate = New X509Certificate2("d:tempkeyskeys.pfx", "12345")
Dim rsa As RSA = certificate.GetRSAPrivateKey()
Dim sig() As Byte = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
Dim ampUrlSignature As String = ToWebSafeBase64(sig)
Dim url As String = ampBaseUrl + signatureUrl + "&amp_url_signature=" + ampUrlSignature
Console.WriteLine(url)
End Sub
Private Function ToWebSafeBase64([data]() As Byte) As String
Dim base64 = System.Convert.ToBase64String(data)
base64 = base64.Replace("+", "-")
base64 = base64.Replace("/", "_")
Return base64
End Function
End Module

GitHub 上的示例项目

它生成以下网址:

https://www-toptrouwen-nl.cdn.ampproject.org/update-cache/c/s/www.toptrouwen.nl/artikelen/132/het-uitwisselen-van-de-trouwringen-hoe-voorkom-je-bloopers?amp_action=flush&amp_ts=1523188941&amp_url_signature=bZJTE4IjlxGhlU79etivzUPpGFoyKvCxqPO1IOPHfzDKQVt-fA8Mte20SeXjTQs24Uy4RD9lmbS2aXlcCTpOYatF2l8PQ-31kR-lKVnuduSZIrg93g2YrvO7x-a6dr19hN74LywgBw4C_JfuocCuGfVvr-mD40tuwkBrsLgmI9E=

此签名已使用 opensll 工具成功验证,但获取此 URL 仍返回URL signature verification error.。然而,现在我们这边似乎一切都很好。我在 github 上发现了相关问题。AMP项目参与者有以下声明:

首先,我确定AMP缓存不处理HTTP刷新 正确用于更新缓存验证密钥:如果您发出 update-cache request,然后交换/.well-known/amphtml/apikey.pub 使用不同的密钥,我们会无限期地继续使用旧的密钥材料。 更糟糕的是,404 个响应也被永久缓存:-(

我提交了内部错误报告,但可能需要一些时间 修复以推出到生产环境。同时,我可以刷新无效密钥 手动地。只需在GitHub上或上给我发送私人消息 amphtml.slack.com。很抱歉没有早点发现这一点。

似乎是当前错误的根本原因。您尝试在https://www.toptrouwen.nl/.well-known/amphtml/apikey.pub没有可用的公钥的情况下更新缓存(当我第一次检查它时,它导致 404 错误)。谷歌已经缓存了这个结果,现在即使证书可用,它也没有被实际使用。

似乎目前唯一可能的解决方法是联系codewiz并要求他刷新缓存的密钥错误。在 AMP 系统使用有效的公钥之前,无法进行签名验证。

最新更新