📜  什么是SameSite Cookies和CSRF保护?(1)

📅  最后修改于: 2023-12-03 14:49:10.731000             🧑  作者: Mango

SameSite Cookies和CSRF保护介绍

同站点 Cookie(SameSite Cookies)和跨站请求伪造(CSRF)保护是现代web应用程序保护用户免受网络攻击的两种重要方式。

SameSite Cookies

同站点 Cookie 是为了提高web应用程序的安全性而设计的一种 Cookie,允许服务器限制浏览器何时发送 Cookie。 它们可以用来防止一些常见的攻击,例如XSS、CSRF等。

同站点 Cookie 作为一个新特性已经包括在HTTP状态码中,用于指定请求来自同一个站点的资源。因此,同站点 Cookie 在页面被跨站点访问时会被浏览器自动屏蔽,这样就可以有效地防止第三方 Cookie 攻击。

CSRF保护

跨站请求伪造(CSRF)是一种攻击方式,攻击者利用用户在访问某些受信任网站时的身份验证,尝试发送针对该网站的恶意请求。这种攻击的具体方式是,攻击者利用用户的身份向受攻击网站发送一些非预期的请求,从而获取敏感信息或在用户不知情的情况下执行某些操作。

为了保护web应用程序免受CSRF的攻击,我们可以采用以下预防措施:

  • 验证 Referer
  • 在表格中使用随机令牌
  • 在cookie中设置SameSite属性
示例代码

以下是一个Node.js示例程序,展示了如何使用bcrypt.js库来保护登录验证表单免受安全威胁的攻击。此程序采用了上述3种预防措施:

const express = require('express');
const bodyParser = require('body-parser');
const bcryptjs = require('bcryptjs');
const csrf = require('csurf');
const cookieParser = require('cookie-parser');

const app = express();

// 解析表单数据
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

// 设置 SameSite 属性
app.use((req, res, next) => {
  res.cookie('cookieSameSite', 'example', { sameSite: 'lax' });
  next();
});

// 初始化 csrf 防御
const csrfProtection = csrf({ cookie: true });

// 登录页面路由
app.get('/login', csrfProtection, (req, res) => {
  res.render('login', { csrfToken: req.csrfToken() });
});

// 登录验证路由
app.post('/login', csrfProtection, async (req, res) => {
  const username = req.body.username;
  const password = req.body.password;

  // 模拟从数据库中获取用户信息
  const user = { name: 'example', hash: '$2a$10$wQeyoRuNvR8iNnNz9lLcROhbIlh/3q3iAmKAHV0D2wYIdmE0jy.5m' };

  // 验证用户信息
  const match = await bcryptjs.compare(password, user.hash);

  if (match) {
    // 登录成功,将用户信息存储在session中
    req.session.user = { name: user.name };

    res.redirect('/dashboard');
  } else {
    // 登录失败
    res.render('login', { csrfToken: req.csrfToken() });
  }
});

// 防止CSRF攻击的中间件
app.use((err, req, res, next) => {
  if (err.code !== 'EBADCSRFTOKEN') return next(err);

  // csrf攻击了
  res.status(403).send('表单会话已经过期或无效!');
});

app.listen(3000, () => {
  console.log('服务器正在监听3000端口...');
});