前端安全:CSRF攻击与防御

CSRF(Cross-Site Request Forgery,跨站请求伪造)攻击是一种允许攻击者通过受害者的身份执行非预期操作的安全威胁。为了防御这种攻击,前端开发者通常需要结合后端验证和特定的前端策略。

令牌验证:

这是最常用的防御手段,通常涉及生成一个CSRF令牌,并将其在客户端和服务器之间交换。

服务器生成令牌:

在用户登录成功后,服务器生成一个CSRF令牌,并将其存储在用户的会话中。

   # Python 示例
   from flask import Flask, session
   app = Flask(__name__)

   @app.route('/login')
   def login():
       session['csrf_token'] = generate_csrf_token()
       return render_template('login.html', csrf_token=session['csrf_token'])
客户端使用令牌:

将令牌嵌入到每个需要防护的表单中,或者作为HTTP头的一部分。

   <!-- HTML 示例 -->
   <form action="/protected" method="POST">
     <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
     <!-- ...其他表单字段... -->
   </form>
   // JavaScript 示例(使用Fetch API)
   fetch('/protected', {
     method: 'POST',
     headers: {
       'Content-Type': 'application/x-www-form-urlencoded',
       'X-CSRF-Token': window.csrfToken
     },
     body: formData
   });

检查Referer头:

虽然不完全可靠,因为Referer头可以被浏览器禁用或篡改,但通常可以作为辅助防御措施。

   # Python 示例(Flask中间件)
   from flask import request

   @app.before_request
   def check_referer():
       if request.method in ['POST', 'PUT', 'DELETE']:
           if not request.referrer or request.referrer != app.config['APP_BASE_URL']:
               return abort(403)

双因素认证:

要求用户在提交敏感操作前进行二次确认,例如通过弹窗或验证码。

SameSite Cookie属性:

设置Cookie的SameSite属性为LaxStrict,限制跨站提交。Lax模式允许在top-level导航中发送,而Strict模式则更严格,只在同一站点内的请求中发送。

   # Python 示例(使用Flask-Session扩展)
   from flask_session import Session
   from flask import Flask

   app = Flask(__name__)
   Session(app)
   app.session_interface.cookie_samesite = 'Lax'

POST-only接口:

对于敏感操作,只接受POST请求,不使用GET请求,因为GET请求容易被浏览器书签、链接预加载或第三方脚本滥用。

前端代码中,防御CSRF通常涉及在表单提交或Ajax请求时附带CSRF令牌。确保在后端验证令牌的有效性是至关重要的,因为前端的防御措施可以被绕过。

以下是一个Node.js + Express + CSRF保护的示例:

// server.js
const express = require('express');
const bodyParser = require('body-parser');
const csrf = require('csurf');
const app = express();

// 使用cookie-parser中间件解析cookie
app.use(require('cookie-parser')());

// 使用中间件生成和注入CSRF令牌
const csrfProtection = csrf({ cookie: true });
app.use(csrfProtection);

// 保护路由
app.post('/protected', csrfProtection, (req, res) => {
  // 验证令牌并执行操作
  if (req.csrfToken() === req.body.csrfToken) {
    // 安全的操作
  } else {
    // CSRF令牌无效,返回错误
    res.status(403).send('CSRF token mismatch');
  }
});

// 响应HTML页面,包含CSRF令牌
app.get('/', (req, res) => {
  res.send(`
    <form action="/protected" method="POST">
      <input type="hidden" name="csrfToken" value="${req.csrfToken()}">
      <button type="submit">Submit</button>
    </form>
  `);
});

app.listen(3000);

使用CSP(Content Security Policy)

内容安全策略(CSP)是一种网络安全策略,通过指定哪些外部资源可以被加载或执行,来减少跨站脚本攻击的风险。虽然CSP主要针对XSS攻击,但它也能间接帮助防御CSRF,特别是当CSP配置得当,限制了第三方网站对你的应用发起请求的能力时。

// 在Express应用中设置CSP头部
app.use((req, res, next) => {
  res.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline'");
  next();
});

验证HTTP请求头的Origin字段

尽管不如使用CSRF令牌可靠,但在某些场景下检查Origin头部也可以作为一种辅助防御措施。如果请求来自不受信任的源,服务器可以选择拒绝该请求。

# Flask示例
from flask import request

@app.before_request
def verify_origin():
    if request.method == 'POST':
        allowed_origins = ['https://your-trusted-origin.com']
        origin = request.headers.get('Origin')
        if origin not in allowed_origins:
            return 'Unauthorized', 401

HSTS(HTTP Strict Transport Security)

强制浏览器只通过HTTPS与服务器通信,可以防止中间人攻击,从而降低CSRF攻击的风险,因为攻击者更难以拦截或修改HTTPS通信。

# Flask示例
@app.after_request
def apply_hsts(response):
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    return response

使用Web应用防火墙(WAF)

Web应用防火墙可以提供额外的防护层,检测并阻止恶意请求,包括CSRF攻击。WAF可以是硬件设备、软件服务或云服务,通常基于签名匹配、行为分析或机器学习算法来识别和阻止攻击。

限制敏感操作的频率

限制用户执行敏感操作的速率可以帮助防止大规模的CSRF攻击。例如,限制用户在一分钟内只能提交几次更改密码或删除账户的请求。

// 使用JavaScript实现简单的速率限制
let lastRequestTime = null;
const LIMIT = 60 * 1000; // 一分钟

function submitSensitiveAction() {
  const currentTime = Date.now();
  if (lastRequestTime && currentTime - lastRequestTime < LIMIT) {
    alert('Too many requests, please try again later.');
    return;
  }
  
  // 提交请求...
  lastRequestTime = currentTime;
}

避免使用GET请求进行敏感操作

虽然POST请求通常被认为比GET请求更安全,但某些情况下,GET请求可能不可避免。在这种情况下,确保URL不会被缓存或记录在浏览器历史记录中,以降低CSRF风险。例如,使用动态生成的随机参数,而不是直接暴露敏感信息。

# Django示例
from django.http import HttpResponseBadRequest

def sensitive_get_view(request):
    if not request.GET.get('random_token') == request.session.get('random_token'):
        return HttpResponseBadRequest('Invalid token')

    # 执行敏感操作...

    # 清除随机令牌,防止重放攻击
    request.session.pop('random_token', None)

考虑使用OAuth 2.0或JWT

现代Web应用经常使用OAuth 2.0或JSON Web Tokens (JWT)进行身份验证。这些协议提供了内置的机制来验证请求的来源和授权状态,从而降低CSRF攻击的风险。然而,正确实现这些协议同样至关重要,因为它们也有自己的安全挑战。

保持框架和库的更新

确保你使用的前端框架、后端库和服务器软件都保持最新,以便获得最新的安全补丁和修复。

安全编码和测试

遵循安全编码最佳实践,如输入验证、输出编码、错误处理和日志记录,可以帮助发现和修复潜在的漏洞。此外,定期进行安全测试,如渗透测试和代码审查,可以确保应用在发布之前是安全的。

  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天涯学馆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值