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

时间:2018-04-06 12:35:59

标签: amp-html google-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

我尝试使用this URL调用Google AMP缓存。

现在,我收到403错误:

  

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

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

我的问题围绕着签名网址:

  1. 我是否使用文章AMP网址或常规网址?
  2. 我是否需要在我的签名网址中包含查询字符串参数amp_actionamp_ts?或者我在签署网址后稍后添加这些内容?
  3. 我应该将上面的ampBaseUrl添加到我的signatureUrl变量中,还是不需要?
  4. 更新1

    根据@ CodeFuller的建议,我检查了网址并收到Verified OK消息。我也照顾了第2步:

    1. APIkeys匹配: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. 从我的服务器以text / plain
    3. 提供apikey.pub
    4. 通过https和公开
    5. 提供apikey.pub
    6. 在机器人中添加了禁用:用户代理:* 禁止:/。well-known / amphtml / apikey.pub
    7. 更新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_参数变得混乱的早期问题有关。

      然后我将网址参数重命名为正确的名称: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 signature verification error

      我认为UTC时间戳目前不是问题,因为我之前看到过,如果时间戳不正确,Google会抛出错误。

1 个答案:

答案 0 :(得分:1)

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 -signature signature.bin -verify   publickey.pem url.txt

    如果输出

      

    验证确定

    然后您的签名就可以了,您应该在其他地方搜索问题(参见第2项)。

    如果输出

      

    验证失败

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

    上面命令中的

    publickey.pem是PEM格式的公钥。它应该从以下行开始:

      

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

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

      

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

  2. 如果验证签名成功,则应检查您的公钥是否可通过Web访问。 Update AMP Content表示以下要求:

      

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

         

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

         
        
    • 不得将公钥自动化。

    •   
    • 网址必须为HTTPS。

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

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

    •   

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

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

      

    我是否需要在签名网址中包含查询字符串参数amp_action和amp_ts?或者在我签署网址后稍后添加这些内容?

    是的,您应该将amp_actionamp_ts包含在计算签名的网址中。

      

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

    如上所述Update AMP Content文章:

      

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

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

    <强>更新

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

    Dim AMPURLSignature As String = EncodeTo64(sig.ToString)
    

    sig.ToString会导致将"System.Byte[]"字符串传递给EncodeTo64,而不是实际的签名字节。结果,错误的签名被附加到更新缓存URL。将以上呼叫替换为以下内容(不再需要EncodeTo64):

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

    另一个可能的问题是您使用的时间戳不满足following requirement

      

    该值应为以秒为单位的当前时间,必须在其中   在当前时间之前或之后1分钟

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

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

    还要确保在生成后立即调用update-cache URL,以便当前时间与时间戳相比在1分钟之内。你的系统时间应该是准确的。

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

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

    在base4编码变体中的AMP缓存更新签名should go

      

    使用web-safe variant of base64

    对二进制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-cache网址的最终代码(基于available documentation):

    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:\temp\keys\keys.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
    

    Sample Project on 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 signature verification error.。但是现在一切似乎都很好。我找到了related issue on github。有以下statement from AMP project contributor

      

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

         

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

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

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