阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 前端框架中的 CSRF 防护

前端框架中的 CSRF 防护

作者:陈川 阅读数:53180人阅读 分类: 前端安全

CSRF攻击的基本原理

CSRF(Cross-Site Request Forgery)跨站请求伪造是一种常见的Web安全威胁。攻击者诱导用户访问恶意网站时,该网站会向用户已认证的目标网站发起请求,利用用户在目标网站的登录状态完成非法操作。这种攻击之所以能够成功,是因为浏览器会自动携带目标网站的cookie等认证信息。

典型的CSRF攻击流程:

  1. 用户登录银行网站,认证信息保存在cookie中
  2. 用户访问恶意网站
  3. 恶意网站包含向银行转账的请求
  4. 浏览器自动携带银行网站的cookie发送请求
  5. 银行服务器认为这是合法请求并执行操作
<!-- 恶意网站中的攻击代码 -->
<img src="https://bank.com/transfer?to=attacker&amount=10000" width="0" height="0">

前端框架的CSRF防护机制

现代前端框架提供了多种内置或推荐的CSRF防护方案。这些机制主要围绕验证请求来源和添加随机令牌展开。

1. 同源策略与CORS

浏览器同源策略是防御CSRF的第一道防线。前端框架在处理跨域请求时会严格遵守CORS规范:

// Axios配置示例
axios.defaults.withCredentials = true;
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

重要配置项:

  • withCredentials: 控制是否发送凭据
  • Access-Control-Allow-Origin: 指定允许的源
  • Access-Control-Allow-Credentials: 是否允许发送cookie

2. CSRF令牌机制

主流框架推荐的防护方案是在表单或请求中添加CSRF令牌:

React实现示例

// 服务端生成并注入令牌
const csrfToken = generateToken();

// 前端组件
function TransferForm() {
  return (
    <form action="/transfer" method="POST">
      <input type="hidden" name="_csrf" value={csrfToken} />
      {/* 其他表单字段 */}
    </form>
  );
}

Vue实现示例

// 全局拦截器设置
axios.interceptors.request.use(config => {
  config.headers['X-CSRF-TOKEN'] = getCSRFToken();
  return config;
});

3. 双重Cookie验证

现代框架支持通过双重cookie增强防护:

// 设置HttpOnly的认证cookie
document.cookie = `auth_token=${token}; HttpOnly; Secure`;

// 同时设置可读的CSRF token
document.cookie = `csrf_token=${csrfToken}; SameSite=Strict`;

框架特定实现方案

Angular的CSRF防护

Angular内置了XSRF防护机制,默认从cookie读取XSRF-TOKEN并添加到请求头:

// 服务端设置cookie
res.cookie('XSRF-TOKEN', token, { secure: true });

// Angular自动处理
this.http.post('/api/transfer', data).subscribe();

React的防护实践

React应用通常结合Redux管理CSRF状态:

// Redux store初始化
const store = createStore(reducer, {
  csrf: {
    token: window.initialData.csrfToken,
    timestamp: Date.now()
  }
});

// 高阶组件封装
function withCSRF(Component) {
  return function WrappedComponent(props) {
    const csrf = useSelector(state => state.csrf);
    return <Component {...props} csrf={csrf} />;
  }
}

Vue的解决方案

Vue生态通常使用vue-resource或axios插件:

// Vue插件实现
const CSRFPlugin = {
  install(Vue) {
    Vue.prototype.$csrf = {
      getToken() {
        return localStorage.getItem('csrfToken');
      },
      refresh() {
        return axios.get('/csrf-token').then(res => {
          localStorage.setItem('csrfToken', res.data.token);
        });
      }
    };
  }
};

高级防护策略

1. 请求头校验

除了令牌,还可以验证特定请求头:

// 自定义请求头校验
app.use((req, res, next) => {
  if (req.get('X-Request-Source') !== 'web-app') {
    return res.status(403).send('Invalid request source');
  }
  next();
});

2. 行为验证

关键操作前增加二次验证:

// React二次确认对话框
function ConfirmTransfer({ amount, recipient }) {
  const [confirmed, setConfirmed] = useState(false);
  
  return (
    <div>
      {!confirmed && (
        <dialog open>
          <p>确认向{recipient}转账{amount}元?</p>
          <button onClick={() => setConfirmed(true)}>确认</button>
        </dialog>
      )}
      {confirmed && <TransferForm />}
    </div>
  );
}

3. SameSite Cookie属性

现代浏览器支持SameSite属性:

// 严格模式Cookie设置
Set-Cookie: sessionid=xxxx; SameSite=Strict; Secure

实际应用中的注意事项

  1. 令牌存储:避免将CSRF令牌存储在localStorage中,推荐使用HttpOnly Cookie
  2. 令牌刷新:重要操作前应刷新CSRF令牌
  3. 错误处理:统一处理403状态码,引导用户重新认证
  4. 日志记录:记录CSRF验证失败的请求用于安全分析
// 错误处理中间件
app.use((err, req, res, next) => {
  if (err.code === 'EBADCSRFTOKEN') {
    securityLogger.warn(`CSRF验证失败: ${req.ip}`);
    return res.status(403).render('error/csrf');
  }
  next(err);
});

性能与安全的平衡

CSRF防护可能影响应用性能,需要合理优化:

  1. 令牌缓存:对静态资源请求免除CSRF验证
  2. 域白名单:配置可信域减少验证开销
  3. 懒验证:非敏感操作延迟验证
# Nginx配置示例
location ~ ^/api/secure/ {
  add_header X-Frame-Options "DENY";
  add_header X-Content-Type-Options "nosniff";
}

location ~ ^/static/ {
  expires 1y;
  add_header Cache-Control "public";
}

测试与验证

完善的测试方案确保防护有效性:

// Jest测试用例
describe('CSRF防护', () => {
  test('应拒绝缺少CSRF头的POST请求', async () => {
    const res = await request(app)
      .post('/transfer')
      .expect(403);
  });

  test('应接受有效CSRF头的请求', async () => {
    const token = await getCSRFToken();
    const res = await request(app)
      .post('/transfer')
      .set('X-CSRF-TOKEN', token)
      .expect(200);
  });
});

与其他安全措施的协同

CSRF防护需要与其他安全机制配合:

  1. CSP策略:限制外部资源加载
  2. XSS防护:防止令牌被盗取
  3. 速率限制:阻止暴力攻击
<!-- CSP策略示例 -->
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self' 'unsafe-inline'">

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌