使用 OAuth 1.0 生成签名时出现问题
Posted
技术标签:
【中文标题】使用 OAuth 1.0 生成签名时出现问题【英文标题】:Problem generating signature with OAuth 1.0 【发布时间】:2021-06-10 11:18:43 【问题描述】:我在 powershell 中生成有效的 HMAC-SHA1 签名时遇到问题,我最终希望将其与 Flickr API 一起使用。我已经坚持了几个星期,所以如果有人请告诉我我做错了什么,那将不胜感激。谢谢你:)
这是我写的代码:
$oauth_signature_method = 'HMAC-SHA1'
[string]$oauth_nonce = New-Guid
[int]$oauth_timestamp = [int](Get-Date -UFormat %s -Millisecond 0)
$oauth_version = '1.0'
$oauth_consumer_key = 'e1d618f39j69s6a87443b182a1e91084' #NOT REAL KEY
$oauth_consumer_secret = 'dd6jjff7423acb3a' # NOT REAL KEY
$url = 'https://www.flickr.com/services/oauth/request_token'
$method = 'GET'
$oauth_callback = 'oob'
$signature_key = [System.Uri]::EscapeDataString($oauth_consumer_key)+"&"+[System.Uri]::EscapeDataString($oauth_consumer_secret);
$method = $method.ToUpper()
$response=""
$oauth_signature = ""
# Build the signature
$SignatureBase = "$([System.Uri]::EscapeDataString($url))&"
$SignatureParams = @
'oauth_callback' = [System.Web.HttpUtility]::UrlEncode($oauth_callback);
'oauth_consumer_key' = $oauth_consumer_key;
'oauth_nonce' = $oauth_nonce.replace("-","");
'oauth_signature_method' = $oauth_signature_method;
'oauth_timestamp' = $oauth_timestamp;
'oauth_version' = $oauth_version;
$SignatureParams.GetEnumerator() | Sort Name |foreach $SignatureBase += [System.Uri]::EscapeDataString("$($_.Key)=$($_.Value)&")
$SignatureBase = [System.Uri]::EscapeDataString("$method&")+$SignatureBase.TrimEnd('%26')
$SignatureBase = [System.Uri]::EscapeDataString($SignatureBase)
########################################################################################
# At this point:
# $SignatureBase = GET%2526https%253A%252F%252Fwww.flickr.com%252Fservices%252Foauth%252Frequest_token%26oauth_callback%253Doob%2526oauth_consumer_key%253De1d618f39j69s6a87443b182a1e91084%2526oauth_nonce%253D080a4203ff7e428bb898086dd
13a6697%2526oauth_signature_method%253DHMAC-SHA1%2526oauth_timestamp%253D1615550853%2526oauth_version%253D1.0
# $Signature_key = e1d618f39j69s6a87443b182a1e91084&dd6jjff7423acb3a
########################################################################################
$hmac = New-Object System.Security.Cryptography.HMACSHA1
$hmac.key = [System.Text.Encoding]::UTF8.GetBytes($Signature_key)
$oauth_signature = $hmac.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($SignatureBase));
$oauth_signature = [System.Convert]::ToBase64String($oauth_signature)
########################################################################################
# At this point, $oauth_signature = tcKfNZmmRsGhnMmBaIuxRIINJfI=
########################################################################################
#Add the signature into the hashtable
$SignatureParams += @'oauth_signature'=$oauth_Signature
# Reconstruct the URL to include the new signature
$callurl = $url+"?"
$SignatureParams.GetEnumerator() | Sort Name | foreach $callurl += "$($_.Key)=$($_.Value)&"
$callurl = $callurl.TrimEnd('&')
########################################################################################
# At this point, this is the URL to get a token:
# https://www.flickr.com/services/oauth/request_token?oauth_callback=oob&oauth_consumer_key=e1d618f39j69s6a87443b182a1e91084&oauth_nonce=080a4203ff7e428bb898086dd13a6697&oauth_signature=tcKfNZmmRsGhnMmBaIuxRIINJfI=&o
auth_signature_method=HMAC-SHA1&oauth_timestamp=1615550853&oauth_version=1.0
########################################################################################
# Send the request to the oAuth server
try $response = Invoke-RestMethod -uri $callurl -method $method -Headers $APIHeader
当签名被发送到 Flickr 时,服务器拒绝它,声明“oauth_problem=signature_invalid”。
我错过了一步吗?
谢谢。
【问题讨论】:
【参考方案1】:看看Flickr's docs中的示例payload:
GET&https%3A%2F%2Fwww.flickr.com%2Fservices%2Foauth%2Frequest_token&oauth_callback%3Dhttp%253A%252F%252Fwww.example.com%26oauth_consumer_key%3D653e7a6ecc1d528c516cc8f92cf98611%26oauth_nonce%3D95613465%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1305586162%26oauth_version%3D1.0
现在与您的脚本生成的有效负载字符串 ($SignatureBase
) 进行比较:
GET%2526https%253A%252F%252Fwww.flickr.com%252Fservices%252Foauth%252Frequest_token%26oauth_callback%253Doob%2526oauth_consumer_key%253De1d618f39j69s6a87443b182a1e91084%2526oauth_nonce%253D0e014a368e2845f4860e27e87f6c5d01%2526oauth_signature_method%253DHMAC-SHA1%2526oauth_timestamp%253D1615561837%2526oauth_version%253D1.0
这告诉我们什么?好吧,您似乎过度转义正在签名的有效负载。
改变这个:
$SignatureParams.GetEnumerator() | Sort Name |foreach $SignatureBase += [System.Uri]::EscapeDataString("$($_.Key)=$($_.Value)&")
$SignatureBase = [System.Uri]::EscapeDataString("$method&")+$SignatureBase.TrimEnd('%26')
$SignatureBase = [System.Uri]::EscapeDataString($SignatureBase)
只是:
$SignatureParams.GetEnumerator() | Sort Name |foreach $SignatureBase += [System.Uri]::EscapeDataString("$($_.Key)=$($_.Value)&")
$SignatureBase = "$method&" + ($SignatureBase -replace '%26$')
现在剩下的就是通过更改这一行来逃避生成的签名:
$SignatureParams += @'oauth_signature'=$oauth_Signature
到:
$SignatureParams += @ 'oauth_signature' = [uri]::EscapeDataString($oauth_Signature)
【讨论】:
谢谢,这两种方法我都试过了。即使将字符串设置为“GET&https%3A%2F%2Fwww.flickr.com%2Fservices...”,正在计算的签名仍然被拒绝 @Lee 您仍然需要转义最终签名(我已经更新了答案) 谢谢。使用实时 api 密钥,在进行上述更改后,转义签名现在看起来像...&oauth_signature=47jBUIguxrrjJYVk%2BtQbhuv79TY%3D&oauth_signature_method=HMAC-SHA1...
。不幸的是,flickr 仍然不喜欢它。
@Lee 那我恐怕没有好主意了:-)
是的,我也是。感谢您的帮助。【参考方案2】:
我同意马蒂亚斯的观点。
您最初在签名库中转义 url,然后在将所有元素连接到签名库之前转义所有元素。
然后在这里,你转义了整个构造的字符串:
$SignatureBase = [System.Uri]::EscapeDataString($SignatureBase)
这是用百分比转义码 (%25) 替换每个先前转义字符的百分比符号。
省略上面提到的代码行。正如文档所述,每个元素都应该在与 & 号连接之前进行转义。
https://oauth.net/core/1.0a/#anchor13
另外,我会将 $signatureParams 哈希表转换为字符串数组,然后转换为 -join '&'
。这样就无需稍后去除尾随编码的“&”。
我认为您不需要对 sigKey 进行 UTF8 编码。你的 ::EscapeDataString()
方法应该可以处理这个问题。
请注意,在您对 $ouath_signature 进行 base64 编码后,必须先对其进行转义(URL 编码),然后再将其分配给 AuthZ 标头中的“oauth_signature”参数。
我建议使用 Postman 测试您的授权,并比较生成的签名。
https://www.postman.com/
他们有一个关于如何使用 Postman 的 OAuth 1.0 文档:https://learning.postman.com/docs/sending-requests/authorization/#oauth-10
【讨论】:
以上是关于使用 OAuth 1.0 生成签名时出现问题的主要内容,如果未能解决你的问题,请参考以下文章
OAuth 1.0 在 POSTMAN 和 PHP 代码中生成签名差异
生成签名的 apk 时出现 TaskExecutionException
使用预签名 URL 将文件上传到 Amazon S3 时出现 CORS 错误