使用 HMAC 或 OpenSSL 进行 URL 签名
我对网址签名感兴趣(例如 http://.../? somearg=value&anotherarg=anothervalue&sig=aSKS9F3KL5xc),但我有一些要求,这让我还没有解决方案。
- 我将使用
PHP
或Python
来创建页面,因此我需要能够使用两者之一来签署和验证签名。 - 我的计划是使用 priv/pub 密钥方案来签署一些数据,并能够验证签名是否有效,但这就是事情变得复杂的地方:
- 验证发生时数据是未知的(它不仅仅是 < code>somearg=value&anotherarg=anothervalue)
我的第一反应是使用 OpenSSL,例如使用 RSA 密钥对,通过以下方式执行类似签名的操作:openssl rsautl -sign -inkey private.pem -insensitive-out privsigned 并仅基于 privsigned
数据和密钥进行验证:openssl rsautl -verify -inkey public.pem -in privsigned -pubin
代码>.
使用 PHP 的 openssl_get_privatekey()
和 openssl_sign()
对数据进行签名就可以了,但我需要知道(解密的!)数据才能验证(我不会这样做) ): openssl_get_publickey()
和 openssl_verify($data, $signature, $pubkeyid);
来自 http://php.net/openssl_verify。
或者我在这里遗漏了什么?
因此,我研究了 HMAC,但是尽管 Python
和 PHP
中都提供了许多哈希函数,但我对如何处理验证哈希值。 PHP
的 hash_hmac()
允许我使用“键”(或者在本例中为字符串键)创建哈希。但是我该如何验证哈希值是否有效(即 &sig=
不仅仅是由最终用户 &sig=abcdefg1234
手动输入的。
总结一下(抱歉这个长问题):我如何验证我的服务器的(证书/字符串)密钥是否已生成签名/哈希(假设我无法通过重做所述数据的哈希来验证)?对于我应该选择哪条路线,Priv/pub-key 还是 HMAC,您有什么偏好吗?
非常感谢任何大大小小的指示! 预先感谢,
- 乔什
I'm interested in url signing (e.g. http://.../?somearg=value&anotherarg=anothervalue&sig=aSKS9F3KL5xc), but I have a few requirements which have left me without a solution yet.
- I'll be using either
PHP
orPython
for pages, so I'll need to be able to sign and verify a signature using one of the two. - My plan was to use a priv/pub key scheme to sign some data, and be able to verify that the signature is valid, but here's where it gets complicated:
- The data is not known when the verification is happening (it is not just
somearg=value&anotherarg=anothervalue
)
My first instinct was to use OpenSSL, e.g. with a RSA keypair, to do something along the lines of signing by: openssl rsautl -sign -inkey private.pem -in sensitive -out privsigned
and verifying based on the privsigned
data and key ONLY: openssl rsautl -verify -inkey public.pem -in privsigned -pubin
.
Using PHP's openssl_get_privatekey()
and openssl_sign()
signs the data just fine, but I need to know the (decrypted!) data in order to verify (which I will not have): openssl_get_publickey()
and openssl_verify($data, $signature, $pubkeyid);
from http://php.net/openssl_verify.
Or am I missing something here?
So I looked into HMAC, but although many hash function are available in both Python
and PHP
, I'm baffled as to how I'd go about verifying the hash.PHP
's hash_hmac()
allows me to create a hash using a "key" (or in this case a string-key). But how do I go about verifying that a hash is valid (i.e. &sig=
hasn't just been manually put in by the end user &sig=abcdefg1234
.
So to sum up (sorry for the long question): How can I verify that a signature/hash has been made by my server's (cert/string)key (given I can not verify by redoing the hash of said data)? And do you have any preferences as to which route I should chose, Priv/pub-key or HMAC?
Any pointers big or small is greatly appreciated!
Thanks in advance,
- Josh
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
正如 Henning Makholm 指出的那样,HMAC 是比公钥更好的选择。您应该针对您的特定场景考虑一些最佳实践,这些实践将影响您的选择:
计算签名时,您需要以 URL 友好的方式对其进行编码(base64 和 base32 是流行的选择)并选择 HMAC 算法(例如 SHA-256),并决定要使用多少位签名保留(将 HMAC 值截断一半通常是安全的)。如果您选择 base64,请注意 url 安全与非 url 安全实现使用的不同字母。
这是用于签名路径 + 查询字符串的伪代码实现(没有错误检查或加盐等):
建议使用 HMAC SHA256,并且可用于所有常见语言。
Java:
Python:
PHP:
As Henning Makholm pointed out, HMAC is a better choice than public key. There are some best practices you should consider for your particular scenario that will impact your choices:
When computing the signature, you'll need to encode it in a URL-friendly way (base64 and base32 are popular choices) and choose an HMAC algorithm (such as SHA-256), and decide how many bits of the signature you want to keep (truncating the HMAC value in half is usually safe). If you choose base64, beware of the different alphabets used by url-safe vs non-url-safe implementations.
Here is a pseudocode implementation (w/o error checking or salting etc) for signing path + query string:
HMAC SHA256 is recommended and is available in all common languages.
Java:
Python:
PHP:
HMAC是一种对称算法,因此没有单独的创建和检查算法。要进行检查,您只需计算最初应该计算的哈希值,并检查结果是否等于您实际从客户端获得的结果。安全性取决于仅存在于您的服务器上的 HMAC 密钥。
除非您需要不知道密钥的人可以验证签名,否则出于效率原因,HMAC 可能是比公钥系统更好的选择。创建或验证公钥签名可能需要几毫秒的时间(几年前,我将一次实现的时间安排为每次操作 15 毫秒),而 HMAC 的速度相当快。
(哦,如果不知道任何类型的签名应该签名的数据,你就无法验证任何类型的签名。据我所知,这没有任何意义)。
HMAC is a symmetric algorithm, so there is no separate creation and checking algorithm. To check, you simply compute the hash as it should have been computed originally, and check that the result equals what you actually got from the client. The security rests on the HMAC key only existing on your server.
Unless you need the signatures to be verifiable by someone who doesn't know the secret key, HMAC is probably a better choice than public-key systems, for reasons of efficiency. It can take several milliseconds to create or verify a public-key signature (some years ago I timed one implementation at 15 ms per operation), whereas HMAC is quite fast.
(Oh, and you cannot verify any kind of signature without knowing the data it's supposed to sign. That wouldn't make any sense, as far as I can see).
如果您想使用 HMAC 和 Python,则:
$ pip install ska
在客户端
生成的 URL 如下所示。
<一href="http://e.com/api/?valid_until=1378045287.0&auth_user=user&signature=YlZpLFsjUKBalL4x5trhkeEgqE8%3D ">http://e.com/api/?valid_until=1378045287.0&auth_user=user&signature=YlZpLFsjUKBalL4x5trhkeEgqE8%3D
在服务器端
请注意,下面的示例中给出了
request.GET
作为示例。它很可能与您框架中使用的内容有所不同(除非您使用 Django)。validate_signed_request_data 生成一个 SignatureValidationResult 对象,该对象基本上包含两个属性:
If you want to use HMAC and Python, then:
$ pip install ska
On the client side
Produced URL looks like as follows.
http://e.com/api/?valid_until=1378045287.0&auth_user=user&signature=YlZpLFsjUKBalL4x5trhkeEgqE8%3D
On the server side
Note, that in example below
request.GET
is given as example. It will most likely vary from what's used in your framework (unless you use Django).The validate_signed_request_data produces a SignatureValidationResult object, which basically holds two properties: