在服务器端生成JWT令牌并将其在响应SON内的注册请求中传递回客户端是否安全?

目前我正在以以下方式生成JWT:

import express from "express";
import jwt from "jsonwebtoken";

const generateToken = (id: any, res: express.Response) => {
    const token = jwt.sign({ id }, process.env.JWT_SECRET as string, {
        expiresIn: "15d",
    });

    return token;
};

export default generateToken;

以下auth.控制器正在使用该命令:

import express from "express";
import User from "../models/user.model";
import bcrypt from "bcrypt";
import generateToken from "../utils/generateToken";

export const signup = async (req: express.Request, res: express.Response) => {
    try {
        const { username, password, email } = req.body;

        // Check if all fields are filled in and been sent
        if (!username || !password || !email) {
            return res
                .status(400)
                .json({ message: "Please fill in all fields" });
        }

        // Check if the user already exists
        const userCheck = await User.findOne({ username });

        if (userCheck) {
            return res.status(400).json({ message: "User already exists" });
        }

        // Check if the email already exists
        const emailCheck = await User.findOne({ email });

        if (emailCheck) {
            return res.status(400).json({ message: "Email already exists" });
        }

        // Hash the password
        const salt = await bcrypt.genSalt(12);
        const hashedPassword = await bcrypt.hash(password, salt);

        // Create a new user
        const newUser = new User({
            username,
            password: hashedPassword,
            email,
        });

        // Generate and send token
        if (newUser) {
            const token = generateToken(newUser._id, res);
            await newUser.save();

            return res.status(201).json({
                user: newUser,
                token: token,
            });
        } else {
            return res.status(500).json({ message: "Something went wrong" });
        }
    } catch (error) {
        console.log(`Error in signup controller: ${error}`);
        return res.status(500).json({ message: "Something went wrong" });
    }
};

如代码所示,我正在生成JWT令牌,并在客户端帖子的响应中将其从后台发送到客户端.

// Generate and send token
if (newUser) {
    const token = generateToken(newUser._id, res);
    await newUser.save();

    return res.status(201).json({
        user: newUser,
        token: token,
    });
} else {
    return res.status(500).json({ message: "Something went wrong" });
}

在客户端中,它将被保存到redux本地存储.

auth:"{\"session\":{\"signedIn\":true,\"token\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY2MWE1Y2U5NjAzYWRhNTMzODA2YjVkZSIsImlhdCI6MTcxMzAwMzc1MywiZXhwIjoxNzE0Mjk5NzUzfQ.v23o2WIIz6bYqxpP_wwG5Q3DZgwXtdPX1pMAnGsDKs4\"},\"user\":{\"avatar\":\"https://via.placeholder.com/150\",\"username\":\"test\",\"email\":\"test@gmail.com\",\"authority\":\"user\"}}"locale:"{\"currentLang\":\"en\"}"_persist:"{\"version\":-1,\"rehydrated\":true}"

Question:这是将其存储在本地存储中足够安全的方法还是需要集头方式?

推荐答案

将JWT令牌存储在本地存储中可能会使您的应用程序面临安全风险,尤其是XSS(跨站点脚本)攻击.如果恶意脚本被注入您的网站,它们可能会访问存储在本地存储中的令牌,从而可能导致未经授权的访问.

一种更安全的方法是使用仅支持HTTPS的cookie来存储JWT令牌.通过在响应标头中将令牌设置为仅支持HTTPS的cookie,可以防止客户端脚本访问它,从而降低XSS攻击的风险.此外,您还可以通过设置cookie的Safe和Samesite属性来增强安全性.

例如

if (newUser) {
    const token = generateToken(newUser._id);
    await newUser.save();

    res.cookie("jwt", token, {
        httpOnly: true,
        secure: true,
        sameSite: "strict"
    });

    return res.status(201).json({
        user: newUser
    });
} else {
    return res.status(500).json({ message: "Something went wrong" });
}

这种方法确保JWT令牌在客户端和服务器之间安全存储和传输,从而降低安全漏洞的风险.但是,请记住实施适当的CSRF(跨站点请求伪造)保护,以防止使用cookie进行身份验证时的CSRF攻击.

Javascript相关问答推荐

reaction如何在不使用符号的情况下允许多行返回?

React:未调用useState变量在调试器的事件处理程序中不可用

我无法在NightWatch.js测试中获取完整的Chrome浏览器控制台日志(log)

从mat—country—select获取整个Country数组

在nextjs服务器端api调用中传递认证凭证

如何为我的astro页面中的相同组件自动创建不同的内容?

切换时排序对象数组,切换不起作用

如何添加绘图条形图图例单击角形事件

如何将数组用作复合函数参数?

如何在DYGRAPS中更改鼠标事件和键盘输入

如何利用CSS中的隐藏元素实现平滑扩展和防止网格行间隙

如何在HTMX提示符中设置默认值?

将基元传递给THEN处理程序

删除元素属性或样式属性的首选方法

如何使用[ModelJSON,ArrayBuffer]调用tf.loadGraphModelSync

按特定顺序将4个数组组合在一起,按ID分组

我们是否可以在reactjs中创建多个同名的路由

我如何才能获得价值观察家&对象&S的价值?

Firefox的绝对定位没有达到预期效果

如何创建一个for循环,用于计算仪器刻度长度并将其放入一个HTML表中?