问题
I'm trying to update my Google AMP pages in the Google AMP Cache, but get an URL signature verification error.
My code:
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)
Encoding function:
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
I try to call Google AMP cache with this URL.
Now, I get a 403 error:
Your client does not have permission to get URL /update-cache/c/s/www.example.com/articles/278/myarticle/amp?amp_action=flush&_ts=1523016476&_url_signature=U2lzdGVtLkJ5dGVbdQ. URL signature verification error. That’s all we know.
I find the Google example code not clear enough: https://developers.google.com/amp/cache/update-cache
My questions are around the signature URL:
- do I use the article AMP URL or the regular URL?
- do I need to include the querystring parameters
amp_action
andamp_ts
in my signature URL? Or do I append these later after I've signed the URL? - should I prepend the
ampBaseUrl
above to mysignatureUrl
variable or is this not needed?
UPDATE 1
Based on @CodeFuller's recommendations, I checked the URL and am getting a Verified OK
message. I've also taken care of step 2:
- APIkeys match: https://www.toptrouwen.nl/.well-known/amphtml/apikey.pub matches https://www-toptrouwen-nl.cdn.ampproject.org/r/s/www.toptrouwen.nl/.well-known/amphtml/apikey.pub
- Serving apikey.pub from my server as text/plain
- serving apikey.pub over https and publicly
- Added disallow in robots: User-agent: * Disallow: /.well-known/amphtml/apikey.pub
UPDATE 2
Yes, with the new code I also get Verified OK
on verification.
This URL is generated:
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==
Then I get error Required query parameter 'amp_url_signature' missing.
(related to earlier issue where amp_
parameters get botched.
I then renamed URL parameters to their correct names: 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==
Then I get: 404 Failed to decode amp_url_signature
, I thought this was because there are +
and \
characters in the URL. When I remove those I get the error URL signature verification error
again.
I don't think the UTC timestamp is currently an issue, because I've seen before that Google will throw an error if the timestamp is incorrect.
回答1:
There are two most frequent reasons for URL signature verification error
:
Incorrect calculation of the signature.
So the first thing to is to verify that signature is actually valid. Save signed URL and result signature to some files:
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)
Then verify the signature with openssl tool:
openssl.exe dgst -sha256 -signature signature.bin -verify publickey.pem url.txt
If the output is
Verified OK
then your signature is OK and you should search the problem in other place (see item #2).
If the output is
Verification Failure
then you should recheck the routine of signature calculation.
publickey.pem in command above is the public key in PEM format. It should start with the following line:
-----BEGIN PUBLIC KEY-----
If you have certificate file (starting with
-----BEGIN CERTIFICATE-----
), you could get PEM for it with the following command:openssl.exe x509 -pubkey -noout -in publickey.cer > publickey.pem
If signature was verified successfully, then you should check whether your public key is accessible over the Web. Update AMP Content states following requirement:
For signature verification, you must serve the public RSA key at a fixed location on the AMP document's domain (to generate the key, see Generate the RSA key). For example:
https://example.com/.well-known/amphtml/apikey.pub
The public key must not be roboted.
The URL must be HTTPS.
The domain must be the exact domain that you want to update, not a sub or super domain.
You must publish the key in PEM format and serve the key with the content-type "text/plain".
So if your AMP base URL is
https://www.test.com
, check that your public key is accessible at following URL:https://www.test.com/.well-known/amphtml/apikey.pub
Here are answers to your other questions:
do I need to include the querystring parameters amp_action and amp_ts in my signature URL? Or do I append these later after I've signed the URL?
Yes, you should include amp_action
and amp_ts
into the URL for which signature is calculated.
should I prepend the ampBaseUrl above to my signatureUrl variable or is this not needed?
As stated Update AMP Content article:
The AMP Cache hostname (cdn.ampproject.org) is excluded from the signature to allow submitting the same signed request to multiple AMP Cache operators.
So you should not include ampBaseUrl
into the URL for which signature is calculated.
UPDATE
I have found another error in the code where you append signature to the URL:
Dim AMPURLSignature As String = EncodeTo64(sig.ToString)
sig.ToString
will result to passing of "System.Byte[]"
string to EncodeTo64
, instead of actual signature bytes. As result incorrect signature was appended to update cache URL. Replace above call with the following (EncodeTo64
is not required anymore):
Dim AMPURLSignature As String = System.Convert.ToBase64String(sig)
Another possible problem is that timestamp you use does not satisfy following requirement:
The value should be the current time in seconds, which must be within 1 minute before or after the current time.
You pass DateTime.Now
to GetUnixTimeStampFromDateTime()
but it should be UTC time, not local time. Try replacing tStamp
calculation with:
Dim tStamp As String = CInt((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds).ToString
Also make sure you call update-cache
URL just after it was generated, so that current time is within 1 minute interval comparing to timestamp. And your sytem time should be precise.
Please recheck whether signature verification passes after above fixes.
UPDATE 2 (Regarding +
and /
characters in signature)
AMP cache update signature should go in variation of base4 encoding:
Encode the binary RSA signature using the web-safe variant of base64
So another required fix is to replace +
and /
charcters with -
and _
.
Change following call
Dim AMPURLSignature As String = System.Convert.ToBase64String(sig)
with:
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
UPDATE 3
Here is the final code that should produce correct update-cache
URL (based on 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
Sample Project on GitHub
It produces following 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_action=flush&_ts=1523188941&_url_signature=bZJTE4IjlxGhlU79etivzUPpGFoyKvCxqPO1IOPHfzDKQVt-fA8Mte20SeXjTQs24Uy4RD9lmbS2aXlcCTpOYatF2l8PQ-31kR-lKVnuduSZIrg93g2YrvO7x-a6dr19hN74LywgBw4C_JfuocCuGfVvr-mD40tuwkBrsLgmI9E=
This signature is verified successfully with opensll tool however getting this URL still returns URL signature verification error.
. However now everything seems fine on our side. I have found related issue on github. There is following statement from AMP project contributor:
First of all, I determined that AMP Cache does not handle HTTP refresh correctly for update-cache verification keys: if you issue an update-cache request and then swap /.well-known/amphtml/apikey.pub with a different key, we keep using the old key material indefinitely. To make things worse, 404 responses are also cached forever :-(
I filed an internal bug report, but it might take some time for the fix to roll out to production. Meanwhile, I can flush invalid keys manually. Just send me a private message either on GitHub or on amphtml.slack.com. Apologies for not discovering this sooner.
Seems like it's a root cause of current error. You have tried updating the cache while there was no public key available at https://www.toptrouwen.nl/.well-known/amphtml/apikey.pub
(When I checked it first time it was resulted to 404 error). Google has cached this result and now even when certificate is avaiable it's not actually used.
Seems like the only possible workaround for this moment is to contact codewiz and ask him to flush the cached key error. Until AMP system uses valid public key, signature verification is not possible.
来源:https://stackoverflow.com/questions/49692957/update-google-amp-cache-url-signature-verification-error