【发布时间】:2017-03-24 17:13:10
【问题描述】:
我正在尝试在节点服务中创建 JWT(JSON Web 令牌),然后需要在 PHP 服务中进行检查。
据我所知,我正在根据spec 创建令牌,并使用节点crypto 库对签名进行加密。我读过,在这些技术之间可靠工作的唯一算法是aes-128-cbc,所以这是我正在使用的算法。
我在使用mcrypt_decrypt 时遇到了一些运气,但它仍然不是 100% 正确,这仍然是失败的。此外,由于该库已被弃用,我宁愿使用 openssl_decrypt,我根本无法使用它,它只会返回 false。
秘密和初始化向量都存储在数据库中类型为 varchar(16) 的字段中,因此它们在两个代码位中是相同的。我使用的是 16 字节的块大小,因此与 16 字节的秘密和 iv 匹配。
我尝试了二进制、十六进制和 base64 格式的不同组合,但无法让 openssl_decrypt 函数返回除 false 之外的任何内容。
这个问题归结为如何在节点中加密字符串并在 PHP 中解密?或者我目前对这些方法的使用有什么问题?
节点 v7.4.0
var crypto = require('crypto');
var secret = crypto.randomBytes(16);
var iv = crypto.randomBytes(16);
var header = { type:'JWT', alg: 'aes-128-cbc' };
var payload = { iss: 'auth-token', exp: Date.now() + 86400, token: <some uuid> };
var data = new Buffer(JSON.stringify(header)).toString('base64') + '.' + new Buffer(JSON.stringify(payload)).toString('base64');
var cipher = crypto.createCipheriv('aes-128-cbc', secret, iv);
var encrypted = cipher.update(data, 'utf8', 'base64') + cipher.final('base64');
var JWT = data + '.'+ encrypted;
PHP v7.0.13(也尝试过 v7.1.1)
list($header64, $payload64, $sigEnc) = explode('.', $_POST['jwt']);
$header = base64_decode ($header64);
$payload = base64_decode ($payload64);
$signature = openssl_decrypt($sigEnc, 'aes-128-cbc', $secret, null, $iv); // secret and iv are both straight out of the database
更新
我现在在这里改变了我的目标并使用了哈希,这可能是正确的方法。因此,在 Node 服务中,我使用存储在数据库中的随机密钥创建 base64 标头和有效负载的 SHA256 哈希。然后在 PHP 服务中我做同样的事情并比较哈希值。这是一个更好的方法,我以前应该采取的。
但是仍然存在一个问题,如何在 Node 中可靠地加密字符串并在 PHP 中解密?
【问题讨论】:
-
必须有正确实现规范的库。两边都检查了吗?
-
有一些库,但对于应该相当简单的内容来说,它们似乎有点矫枉过正。
-
您的应用程序中的示例明文、密钥、iv 和密文怎么样,以便我们检查您的工作?你也是 FITH CoinOp,还是其他人?
-
问题可能出在任何地方,例如密钥和 IV 的编码。您应该提供一些示例输入和输出。另外,你为什么使用 AES-CBC 作为一种 MAC?通过这样做,您可能会通过填充预言攻击为攻击者提供解密预言。您应该使用适当的 MAC,例如 HMAC。
-
我的印象是,如果你想在 Node 和 PHP 之间进行 2 路加密,那么 aes-128-cbc 是最可靠的算法。但是是的,最后使用哈希更有意义。
标签: php node.js encryption jwt