使用 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 标头成员和isssubaud 声明与exp 声明一样重要。 另外,只有创建时使用的私钥才能验证签名的说法是错误的。公钥足以满足此目的。 @Stanimir Stoyanov 我没有就 RSA 或 ECDSA 加密发表任何声明,它们具有私钥和公钥。在这种情况下,您是对的,公钥可用于验证签名。在这种情况下,他使用的是 HS256,它只有密钥。 @onik 你说得对,我忽略了 OP 使用 HS256 的事实。

以上是关于使用 JWT 进行 PHP 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Apple 登录“invalid_client”,使用 PHP 和 openSSL 签署 JWT 进行身份验证

使用JWT身份验证缓存API请求

在 Django 中使用 JWT 进行身份验证

使用 JWT 进行身份验证的最佳实践

使用护照 jwt 进行身份验证

使用 Airflow API 进行 JWT 身份验证