亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

Node.js安全登錄策略:最佳實踐與核心技巧

本文介绍了一些针对 Node.js 的安全登录策略,通过采用多种安全措施来保护用户的登录凭证、会话安全和账户访问等方式。

一些关键的安全功能

1. 加盐的密码哈希

密码使用强哈希算法(例如,bcrypt)以及每个密码的随机盐进行哈希。这可以确保即使哈希后的密码被泄露,也无法轻易还原成原始密码。

为什么它这么重要

  • 防止以明文形式保存密码。
  • 加盐处理让攻击者难以通过预计算散列表(如彩虹表)来猜测密码。

实施方案:

    import bcrypt from 'bcrypt';

    const 加密密码 = async (password: string): Promise<string> => {
      const saltRounds = 10;
      const salt = await bcrypt.genSalt(saltRounds);
      return await bcrypt.hash(password, salt);
    };

    // 创建用户并保存到数据库
    const newUser = new User({ username, password: 加密密码 });
    await newUser.save();

    // 登录 API
    const { username, password } = req.body;

    const user = users.find((u) => u.username === username);
    if (!user) return res.status(400).send('找不到该用户');

    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) return res.status(400).send('密码不正确');

全屏查看 全屏退出

2. 基于令牌的认证。

JWT(JSON Web Token),用于令牌验证,实现客户端与服务器之间的无状态认证。用户登录后会获得一个JWT,然后在每个后续请求的Authorization头中发送此JWT。

为什么它很重要呢:

  • 无状态:无需在服务器上保存会话状态。
  • 令牌可以携带声明(claims,如用户 ID、roles)而不暴露敏感信息。

实施:

    import jwt from 'jsonwebtoken';

    const generateToken = (userId: string) => {
      // 生成一个基于用户ID的JWT令牌,有效期为1小时
      return jwt.sign({ userId }, process.env.JWT_SECRET, { expiresIn: '1h' });
    };

切换到全屏模式 | 退出全屏

3. 刷新 token

刷新代币用于无需用户重新登录的情况下获取新的访问代币。这确保了用户可以享受顺畅的体验,同时也保障了安全性。

这里有一个使用JWT认证并通过HTTP-only Cookie存储刷新令牌的GitHub仓库

为什么这很重要?

  • 通过使用短期访问令牌(access token)来减少暴露。
  • 刷新令牌(refresh token)更安全地存储(例如存储在数据库或 HTTP-only cookie 中)。

实施:

请注意,根据上下文可能需要在“实施”后面添加一个冒号(:),以保持与英文原文结构一致。如果上下文确定了这一点,最终翻译应为:

实施:

// 生成刷新令牌的函数
const generateRefreshToken = (userId: string) => {
  return jwt.sign({ userId }, process.env.REFRESH_SECRET, { expiresIn: '7d' });
};

切换到全屏 退出全屏

4. HTTP-only(仅HTTP)Cookies

将敏感令牌(如刷新令牌)存储在 HTTP-only 的 cookie 中。这可以防止 JavaScript 访问令牌,从而保护它们不受 XSS(跨站脚本)攻击的影响。

为什么它很重要?

  • 保护令牌免受恶意脚本窃取。
  • 降低令牌因客户端代码泄露的风险。

实现:

响应对象设置cookie('refreshToken', refreshToken, {
  httpOnly: true,
  secure: "安全: 生产环境中为true",
  sameSite: "同一站点策略: '严格'",
});

全屏 退出全屏

5. JWT 黑名单

JWT 令牌本身并不具备撤销功能。为了使令牌失效(比如用户退出时),会使用 JWT 黑名单。通常会使用数据库或 Redis 来存储这些已失效的令牌,直到它们自然过期。

为什么它很重要。

  • 防止已发放的令牌在注销或账户被篡改后仍被使用。

实施阶段:

    const 黑名单令牌处理 = async (token: string) => {
      await redisClient.set(token, '列入黑名单', 'EX', tokenExpirationTime);
    };

点击全屏进入,点击退出全屏

6. 一次会话。

确保任何时候一个用户只有一个会话处于活动状态。当创建一个新的会话时,失效之前的 tokens 或会话。

为什么它很重要?

  • 防止从多个设备或地点同时登录,提高账户安全性。

实施:

    // 用户表的Schema:
    sessionId: { type: String, unique: true }

    // 登录API
    const newSessionId = generateAccessToken(user);
    user.sessionId = newSessionId;
    await user.save();

    // 认证API
    const decodedToken: any = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET!); // 请使用您的JWT密钥替换
    const sessionIdFromToken = decodedToken.sessionId;

    if (user.sessionId !== sessionIdFromToken) {
          return res.status(403).json({ message: '会话已失效。您已在其他设备上登录。' });
    }

全屏 退出全屏

7. 理想的会话超时时间

会话会在一段时间的不活动后自动过期。实施一个会话过期计时器,在用户长时间不活跃后自动登出用户。

为什么它很重要?

  • 减少因用户忘记注销而导致未授权用户访问登录会话的风险。

实现:

    const sessionExpirationTime = 15 * 60 * 1000; // 15分钟(900000毫秒)
    const IDLE_TIMEOUT = 15 * 60 * 1000;

    // 用户模式定义
    lastActivity: { type: Date, default: Date.now }, // 记录最后活动时间戳

    // 在认证中间件里
    const now = new Date();
    const idleTime = now - new Date(user.lastActivity);

    if (idleTime > IDLE_TIMEOUT) {
      // 会话因长时间无活动而过期,尽管令牌仍然有效
      return res.status(401).json({ message: '会话因长时间无活动而过期' });
    }

    // 否则,更新最后活动时间戳
    user.lastActivity = now;
    await user.save();

进入全屏 退出全屏

8. 账号锁定机制。

通过在几次登录失败尝试后锁定账户来防止暴力破解攻击。实行基于时间的锁定,在多次登录失败后暂时锁定账户。

为什么它很重要?

  • 通过限制登录次数来防止暴力破解尝试。

实施:

    // Schema
    failedLoginAttempts: { type: Number, default: 0 },
    lockoutUntil: { type: Date, default: null }, // 跟踪锁定时间

    const MAX_ATTEMPTS = 3;
    const LOCK_TIME = 15 * 60 * 1000; // 15分钟
    // MongoDB和Mongoose示例
    const handleFailedLogin = async (email: string) => {
      const user = await User.findOne({ email });
      if (!user) return false;

      if (user.lockoutUntil 且 user.lockoutUntil 在当前时间之后) {
        return true; // 账户仍然被锁定
      }

      user.failedLoginAttempts += 1;

      if (user.failedLoginAttempts >= MAX_ATTEMPTS) {
        user.lockoutUntil = new Date(Date.now() + LOCK_TIME); // 锁定30分钟
      }

      await user.save(); // 保存用户数据
      return user.lockoutUntil 且 user.lockoutUntil 在当前时间之后; // 返回账户是否被锁定
    };

    // 如果登录成功则重置登录尝试次数

全屏, 退出全屏

9. 安全的密码重置程序

用户可以通过一个安全的过程来重置密码。使用一次性有效令牌(OTP)通过电子邮件发送给用户,来重置密码。确保该令牌在短时间内失效。

为什么它很重要。

  • 为用户提供找回账户的同时确保账户安全。

实施:

    // 用户模式定义
    resetPasswordToken: String,
    resetPasswordExpires: Date,

    /* 使用 crypto.randomBytes() 生成一个安全的十六进制值,而不是使用 Math.random(),因为 Math.random() 生成的十六进制值更容易被攻击者猜测或暴力破解。这样做更安全,不容易被破解。*/
    const generateResetToken = () => {
      return crypto.randomBytes(20).toString('hex');
    };

    const token = generateResetToken();
    user.resetPasswordExpires = Date.now() + 3600000; // 一小时后

进入全屏 退出全屏

10. 密码过期及限制最近三个密码

这就是怎么回事。

  1. 密码历史记录:
  • 系统会保存用户密码历史记录中的最后三个哈希化密码。
  • 当用户尝试更改密码时,系统会将新密码与之前的密码进行比较,以防止密码重复。
  1. 密码过期:
  • 系统会跟踪用户使用当前密码的时间长度。

  • 一个月后,系统会发送通知提示用户更改密码。

  • 如果在规定的宽限期内没有更新密码,访问可能会被限制,直到用户设置了新密码。
    // 模式

    passwordHistory: [{ type: String }], // 用于存储最近三个密码哈希的数组
    passwordUpdatedAt: { type: Date, default: Date.now }, // 密码最后更新的时间

    // 你可以在登录时检查密码是否过期,或者通过定时任务来查找并通知用户有关过期密码的信息。

进入全屏模式 退出全屏

11. 实施强密码政策

强密码策略有助于防止未授权访问,并减少暴力破解、字典攻击和凭证填充的风险。

实现:

    import validator from 'validator';

    const password = 'User@1234';
    if (
      !validator.isStrongPassword(password, {
        minLength: 8,
        minLowercase: 1,
        minUppercase: 1,
        minNumbers: 1,
        minSymbols: 1,
      })
    ) {
      throw new Error('密码强度不足,请确保它包含足够的字母、数字和符号。');
    }

全屏,退出 全屏

12. 用户专属令牌撤销

这指的是在不影响其他用户的情况下,使某一用户的令牌失效的过程。

在这样的情况下很有用:

  • 检测到账户的可疑活动
  • 用户因安全需要请求撤销令牌
  • 账户被停用或暂停
  • 令牌被偷或泄露

它是怎么工作的:

  1. 令牌的结构:

令牌(比如 JWT)包含用户数据和令牌版本。令牌版本存储在数据库中,用于跟踪用户令牌的有效性。

  1. 令牌检查:

当接收到请求时,服务器会解码该令牌并比较令牌中的 token 版本与数据库中存储的版本号。如果版本号匹配,令牌有效;否则令牌无效。

  1. 令牌撤回:

要撤销某个用户的全部令牌,只需在数据库中将令牌版本递增。所有旧版本的令牌将自动失效。

实施:

    // Schema: token_version INT DEFAULT 1

    // JWT 生成
    const createToken = (user) => {
      const payload = { userId: user.id, tokenVersion: user.tokenVersion };
      return jwt.sign(payload, SECRET_KEY, { expiresIn: '1h' });
    };

    // 令牌版本不匹配,无效
    if (user.tokenVersion !== decoded.tokenVersion) {
      throw new Error('令牌版本不匹配,无效');
    }

    // 要撤销,增加 tokenVersion
    user.tokenVersion++;

切换到全屏模式 退出全屏

13. 跨源资源共享 (CORS) 设置

配置 CORS 以限制哪些来源可以访问您的 API。只有受信任的域名才能向您的后端服务发送请求。

为什么它很重要:

  • 阻止未经授权的网站向您的服务器发起请求。
  • 防范跨站请求伪造(CSRF)。

实施:


实施步骤:

实施部分:

导入 cors 模块并设置允许的源,如下所示:
import cors from 'cors';

app.use(
  cors({
    origin: 'https://your-frontend-domain.com',
    credentials: true,
  })
);


进入全屏模式,退出全屏

也可以看看《基于角色的访问控制与功能导向方法》([原文链接](https://dev.to/sushantrate/role-based-access-control-rbac-with-feature-centric-approach-oj5))

看看我的GitHub主页,在这里:<https://github.com/sushantrahate>

希望这份指南对你有帮助。祝你编写代码开心!😄
點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消