使用 JWT 进行 PHP 身份验证
Posted
技术标签:
【中文标题】使用 JWT 进行 PHP 身份验证【英文标题】:PHP authentication with JWT 【发布时间】:2018-06-30 10:56:47 【问题描述】:我正在创建一种“社交网络”。现在我正在创建身份验证部分。今天学习了 JSON Web Tokens。
1) 我读到 JWT 可以安全使用,因为它们是用密钥签名的。但后来我在网上找到了一些工具,比如https://jwt.io。我尝试使用 firebase/php-jwt 使用 PHP 构建一些 JWT 令牌。 jwt.io 之类的工具可以提取我放入 JWT 中的数据(如用户 ID)。这怎么可能安全?有人不能使用旧的 JWT 创建一个新的 JWT,但用户 ID 不同吗?
一个例子:我创建了以下令牌:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJNeUFQIiwiaWF0IjoxNTE2NTYzMTM0LCJleHAiOjE1MTY1NjQzNDAsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6ImFkbWluQGV4YW1wbGUuY29tIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOiJmYWxzZSJ9.dCtYVpFXhoQmzOdX_dW1yFHEcZ9aZ1I9MC33lJGapvY
如果您将此令牌粘贴到 jwt.io,您将看到有效负载是“name: John Doe”和“admin: false”。这不是不安全吗?或者它是否安全,因为您需要密钥来重新创建 JWT。
非正式:我猜你不能在 JWT 中存储敏感信息......
2) 如何使用 PHP 和 JWT 的“登录”用户?我创建了一个快速演示,我不确定代码是否“有效”,但我想你会明白我的意思。
if (isset($_POST['submit']))
$user = $_POST['user'];
$pass = $_POST['pass'];
if($user = 'my_username' && $password == 'my_password')
// user is logged in
// create a JWT here
else
// wrong credentials!
现在,问题/问题是:如何存储这个令牌?在饼干里?在会话中?使用 html5 的 localStorage?最安全的方法是什么?
其次:如何验证用户身份?我会这样做:
// my secret key
$secret = 'MY_SECRET_KEY';
// decode the token
$token = JWT::decode($token, $secret, array('HS256'));
// what to do here?
你能把这个令牌与数据库中的一些数据或其他东西相匹配吗?
【问题讨论】:
如果有人修改了token中的数据,签名(token的第三部分)将失效。您可以对从客户端获得的内容进行身份验证,以确保数据和签名匹配。由于这是使用 JWT 时的主要功能,我建议您阅读更多有关它们的信息。 Here's a pretty good article 【参考方案1】:1) JWT token 没有加密,所以里面的数据很容易被读取。但是,它包含一个签名,只能使用您在创建令牌时设置的密钥进行验证。你可以检查签名,看看令牌没有被篡改。
2) 令牌可以存储在任何地方,因为它很小。请记住,令牌可以轻松读取,但不能更改。不要在令牌中存储任何敏感数据。
检查令牌时,要检查的重要事项是签名和exp
时间,以查看令牌是否仍然有效。构造良好的令牌不需要完整的数据库验证,而只需检查用户的权限自发布令牌以来是否未更改,如果有,则使用更新的数据重新创建令牌或强制用户登录再次。
【讨论】:
请注意,JWT 可以加密(参见RFC7516)。此外,您应该提到alg
标头成员和iss
、sub
和aud
声明与exp
声明一样重要。
另外,只有创建时使用的私钥才能验证签名的说法是错误的。公钥足以满足此目的。
@Stanimir Stoyanov 我没有就 RSA 或 ECDSA 加密发表任何声明,它们具有私钥和公钥。在这种情况下,您是对的,公钥可用于验证签名。在这种情况下,他使用的是 HS256,它只有密钥。
@onik 你说得对,我忽略了 OP 使用 HS256 的事实。以上是关于使用 JWT 进行 PHP 身份验证的主要内容,如果未能解决你的问题,请参考以下文章