我正在尝试更新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&_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&_ts=1523016476&_url_signature=U2lzdGVtLkJ5dGVbdQ。 URL签名验证错误。这就是我们所知道的。
我发现Google示例代码不够清晰:https://developers.google.com/amp/cache/update-cache
我的问题围绕着签名网址:
amp_action
和amp_ts
?或者我在签署网址后稍后添加这些内容?ampBaseUrl
添加到我的signatureUrl
变量中,还是不需要?更新1
根据@ CodeFuller的建议,我检查了网址并收到Verified OK
消息。我也照顾了第2步:
更新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&_ts=1523138180&_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会抛出错误。
答案 0 :(得分:1)
URL signature verification error
有两个最常见的原因:
签名计算不正确。
所以首先要验证签名是否真正有效。将签名的URL和结果签名保存到某些文件中:
Dim signatureUrl As String = "/update-cache/c/s/www.example.com/articles/278/myarticle/amp?amp_action=flush&_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
如果验证签名成功,则应检查您的公钥是否可通过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
以下是您的其他问题的答案:
我是否需要在签名网址中包含查询字符串参数amp_action和amp_ts?或者在我签署网址后稍后添加这些内容?
是的,您应该将amp_action
和amp_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:
对二进制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&_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 + "&_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
它产生以下网址:
使用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系统使用有效公钥之前,无法进行签名验证。