使用 jwt 有效负载进行某些授权是否安全?

use*_*557 1 node.js jwt

例如,当我登录时,我使用有效负载{ 'userId': 1, '2fa': false}/login路由)创建一个访问令牌,然后我执行另一条路由“/login/auth”,例如检查一次性密码是否正确,如果是,我创建了另一个jwt,但是这个2fa 设置为 true 的时间。然后后续的routes会检查2fa是否正确运行。如果没有,就会出错。这是执行此操作的正确方法还是hacky?

// middleware
const auth = (req, res, next) => {
  const token = req.header('access-token');
  if (!token) return res.status(401).json('Not Authorized');

  try {
    const payload = jwt.verify(token, 'secret1');
    req.payload = payload
    next();
  } catch (ex) {
    res.status(400).json('Invalid.');
  }
};

// routes

router.post(
  '/login',
  async (req, res) => {
    try {

        /* login database stuff goes here if successful creates access token

         */

        const token = jwt.sign(
          { userId, twoFactorAuthenticated: false },
          'secret1',
        );
        res.status(200).json(token);

    } catch (e) {
      console.log(e);
      return res.status(500).json(e);
    }
  },
);


router.post(
  '/login/auth2',
  auth,
  async (req, res) => {
    try {
        /* verifying two factor auth logic goes here 
         *  if succesful approves the 2fa
         */ 

        const token = jwt.sign(
          { userId, twoFactorAuthenticated: true },
          'secret1',
        );
        res.status(200).json(token);

    } catch (e) {
      console.log(e);
      return res.status(500).json(e);
    }
  },
);


router.post(
  '/some-route',
  auth,
  async (req, res) => {
    try {
        if(!req.payload.twoFactorAuthenticated) 
           return res.status(400).json('user has not completed second factor auth')
    } catch (e) {
      console.log(e);
      return res.status(500).json(e);
    }
  },
);
Run Code Online (Sandbox Code Playgroud)

我的用例实际上并不需要登录授权,但对于不同但相同的概念适用。

Gab*_*abe 5

您建议的流程可行,但可以改进。

\n

设置 JWT 声明

\n

由于 JWT 的有效负载未加密,因此它仅用于存储在验证过程中有用的非敏感信息。尽管有效负载未加密,但它已签名,并且在不知道秘密或私钥的情况下无法更改。

\n

除了您自己的自定义声明之外,还有许多可能有用的标准声明twoFactorAuthenticated。您始终应该为您的令牌设置过期时间 (exp)。对于此,userId您可以使用主题声明 (sub)。

\n

使用中间件进行路由验证

\n

完成两因素身份验证后,您需要检查所有受保护路由上的 JWT。现在,您已将检查放入 \xe2\x80\x98some-route\xe2\x80\x99 控制器本身,但如果您有多个受保护的路由,最好为此定义中间件。

\n

使用仅 http 的 cookie 来存储生命周期较短的 JWT

\n

在您的解决方案中,您将令牌发送到客户端,并让客户端将其添加到身份验证标头中。这可能意味着令牌将存储在本地存储中。为此,使用安全的 http cookie可能更安全,其生命周期较短,例如 10 分钟左右。这意味着,如果令牌被泄露,您的 API 容易受到攻击的时间最多为 10 分钟。对于用户来说,每 10 分钟必须进行一次身份验证是一种可怕的用户体验。因此,\xe2\x80\x99 就是您可能想要实现刷新令牌的原因。

\n

使用刷新令牌并且仅使用一次

\n

在您的示例中,验证双因素身份验证后,您发回一个设置为 的twoFactorAuthenticated令牌true。正如之前所建议的,您可以将其发送到生命周期较短的安全 cookie 中。同时,您生成一个具有更长过期时间的刷新令牌,例如 4 小时。当cookie在10分钟后过期时,客户端可以使用刷新令牌一次来获取新的cookie和新的刷新令牌。

\n

重要的:

\n
    \n
  • 刷新令牌只能用于获取新的 cookie,不能用于其他路由。它可以存储在本地存储中并作为不记名令牌在身份验证标头中发送。
  • \n
  • 刷新令牌可能只能使用一次,因此它需要有一个唯一的id,并且需要将id存储在服务器端。如果使用刷新令牌,请将其设置为无效。
  • \n
  • 如果使用刷新令牌,请检查之前是否未使用过。如果第二次使用,就会发生奇怪的事情,因为使用新的 cookie,用户也会获得新的刷新令牌。此时,您只需将用户的所有有效刷新令牌设置为无效即可。您确信在 cookie 过期后,他们必须在所有设备上重新登录。
  • \n
\n

这需要在客户端和服务器端进行一些实现,但我认为这会使您的身份验证过程更加可靠。

\n