使用HMAC或OpenSSL进行URL签名
我对url签名感兴趣(例如),但我有一些要求,这些要求使我还没有解决方案使用HMAC或OpenSSL进行URL签名,url,verification,signing,private-key,hmac,Url,Verification,Signing,Private Key,Hmac,我对url签名感兴趣(例如),但我有一些要求,这些要求使我还没有解决方案 对于页面,我将使用PHP或Python,因此我需要能够使用这两种方法之一对签名进行签名和验证 我的计划是使用priv/pub密钥方案对一些数据进行签名,并能够验证签名是否有效,但这是它变得复杂的地方: 进行验证时,数据未知(不仅仅是somearg=value&anotherarg=anothervalue) 我的第一反应是使用OpenSSL,例如使用RSA密钥对,通过以下方式进行签名:OpenSSL rsautl-si
- 对于页面,我将使用
或PHP
,因此我需要能够使用这两种方法之一对签名进行签名和验证Python
- 我的计划是使用priv/pub密钥方案对一些数据进行签名,并能够验证签名是否有效,但这是它变得复杂的地方:
- 进行验证时,数据未知(不仅仅是
)somearg=value&anotherarg=anothervalue
OpenSSL rsautl-sign-inkey private.pem-in sensitive-out privsigned
,并仅基于privsigned
数据和密钥进行验证:OpenSSL rsautl-verify-inkey public.pem-in privsigned-pubin
使用PHP的openssl\u get\u privatekey()
和openssl\u sign()
可以很好地对数据进行签名,但我需要知道(解密的!)数据以便进行验证(我不会有):openssl\u get\u publickey()
和openssl\u verify($data,$signature,$pubkeyid)代码>从
还是我在这里遗漏了什么
因此,我研究了HMAC,但尽管在Python
和PHP
中都有许多散列函数可用,但对于如何验证散列,我感到困惑。
PHP
的hash\u hmac()
允许我使用“键”(或者在本例中是字符串键)创建哈希。但是我如何验证散列是否有效(即,&sig=
并不是由最终用户手动输入的)
总而言之(很抱歉问了这么长的问题):我如何验证我的服务器的(证书/字符串)密钥是否已进行了签名/哈希(假设我无法通过重做所述数据的哈希进行验证)?对于我应该选择哪种路由,Priv/pub密钥还是HMAC,您有任何偏好吗
非常感谢任何大大小小的指针!
提前感谢,
- 乔希
HMAC是一种对称算法,因此没有单独的创建和检查算法。要进行检查,只需按照最初计算的方式计算哈希值,并检查结果是否等于从客户端实际获得的结果。安全性取决于仅存在于服务器上的HMAC密钥
除非您需要签名由不知道密钥的人验证,否则出于效率考虑,HMAC可能是比公钥系统更好的选择。创建或验证公钥签名可能需要几毫秒的时间(几年前,我将一个实现的时间定为每次操作15毫秒),而HMAC速度相当快
(哦,你不知道任何一种签名都不知道它应该签署的数据。据我所知,这是没有任何意义的。
< P>),正如Henning Makholm指出的,HMAC是比公钥更好的选择。对于你的选择会影响你的选择的一些最佳实践:
您想在签名中考虑主机名和方案(HTTP/HTTPS)吗?也许。
<>你想考虑签名中的路径吗?可能。
您想考虑签名中的查询字符串吗?可能。
- 是否要在签名之前规范化参数顺序和转义?通常不会
- 是否要嵌入签名时间等(以创建有时间限制的URL)
- 是否要将已签名的URL绑定到其他用户状态,例如cookie
- 您是否直接在HMAC中使用用户生成的或用户可见的内容?如果是,您应该使用针对每个请求随机化的值来“盐”键
在计算签名时,您需要以URL友好的方式对其进行编码(base64和base32是常用的选择),并选择HMAC算法(如SHA-256),并决定要保留多少位签名(将HMAC值截断一半通常是安全的)。如果选择base64,请注意url安全实现与非url安全实现使用的字母表不同
下面是签名路径+查询字符串的伪代码实现(不带错误检查或salt等):
const secret = ...;
def sign(path, querystring):
return path + "?" + querystring + "&sig=" + url_encode(base64_encode(hmacsha256(secret, path + "?" + querystring).truncate(16)))
def verify(path, querystring):
querystring_without_sig = remove_query_parameter(querystring, "sig")
sig = base64_decode(url_decode(get_query_parameter(querystring, "sig")))
if hmacsha256(secret, path + "?" + querystring_without_sig)[:16] != sig:
raise "invalid sig"
建议使用HMAC SHA256,并提供所有通用语言版本
爪哇:
Python:
hmac.new(secret, input, hashlib.sha256).digest()
PHP:
如果要使用HMAC和Python,则:
$pip安装ska
在客户端
生成的URL如下所示
在服务器端
注意,在下面的示例中,request.GET
作为示例给出。它很可能与框架中使用的内容不同(除非您使用Django)
validate_signed_request_数据生成SignatureValidationResult对象,该对象基本上包含两个属性:
- 结果(bool):如果数据有效,则为True;否则为False
- 原因(列表):字符串列表,指示验证错误
谢谢你澄清这一点。我认为简单地对“静态”进行散列是不安全的,例如散列(url)(或散列(salt+url))。在哈希中使用时间将非常困难,参数最终会被知道。好吧,这取决于您试图防范的是什么,这在您的问题中并不清楚。通常情况下,URL中会有一个生成时间参数,该参数包含在哈希输入中并经过检查,以便您可以拒绝过时的URL。
hmac.new(secret, input, hashlib.sha256).digest()
hash_hmac("sha256", value, secret);
from ska import sign_url
signed_url = sign_url(
auth_user='user',
secret_key='your-secret_key',
url='http://e.com/api/'
)
from ska import validate_signed_request_data
validation_result = validate_signed_request_data(
data = request.GET, # Note, that ``request.GET`` is given as example.
secret_key = 'your-secret_key'
)