CSRF攻击防御原理
字数 1681 2025-08-18 11:39:15

CSRF攻击防御原理详解

0x01 前言

CSRF(Cross-Site Request Forgery,跨站请求伪造)是现代浏览器工作机制导致的一种常见WEB攻击形态。本文将从攻击原理和服务器端防御解决方案两方面进行详细阐述。

CSRF是现代WEB程序面临的共性问题,许多流行WEB框架都在框架层面解决了这一问题。本文将介绍基于时间与签名的防护手段,并提供具体代码实现(使用Lua语言)。

0x02 CSRF攻击原理

CSRF概念

CSRF跨站点请求伪造是一种危害巨大的攻击方式,攻击者盗用用户身份,以用户名义发送恶意请求。对服务器而言这些请求完全合法,但实际完成了攻击者期望的操作,如:

  • 以用户名义发送邮件/消息
  • 盗取账号
  • 添加系统管理员
  • 购买商品
  • 虚拟货币转账等

攻击场景

  • Web A:存在CSRF漏洞的网站
  • Web B:攻击者构建的恶意网站
  • User C:Web A的合法用户

攻击过程

  1. 用户C打开浏览器,访问受信任网站A,输入用户名密码登录
  2. 用户信息验证通过后,网站A产生Cookie信息返回给浏览器,用户登录成功
  3. 用户未退出网站A前,在同一浏览器中打开新标签页访问网站B
  4. 网站B返回攻击性代码,并发出访问网站A的请求
  5. 浏览器接收攻击代码后,在用户不知情下携带Cookie信息向网站A发出请求
  6. 网站A认为请求来自用户C,以C的权限处理请求,导致恶意代码执行

0x03 CSRF防御原理

防御核心思想

CSRF防护重点是对"用户凭证"进行校验,判断请求是否合法。由于"用户凭证"存储在Cookie中,防护机制主要处理Cookie数据,需要:

  1. 加入签名校验
  2. 实现数据生命周期(过期)管理

Token机制设计

Lapis框架(基于Moonscript的WEB框架)采用基于时间戳和签名验证的CSRF防护设计:

  1. 创建Token处理机制
  2. Token数据结构与时间、加密签名直接相关
  3. 目的:为"身份凭证"添加时间生存周期管理和签名校验管理

0x04 签名与时间戳防护处理流程

Token生成

Token构成

Token由三部分组成:

  1. 消息(msg)
    • 随机字符串
    • 过期时间戳
  2. 分隔符(separator):使用"."分隔msg和signature
  3. 签名(signature):对"msg消息"用特定算法加密后的串

结构表示:

token = base64(msg)..base64(sha256("秘锁", msg))

加密方法

  1. 使用sha256散列算法
  2. 进行BASE64格式转换
  3. 隐含过期时间设定

Token验证

验证步骤

  1. Token解包

    • 以"."为分隔符,分为msg部分和signature部分
  2. 比对签名

    • 对msg部分base64解码
    • 对解码后的msg明文进行相同加密处理
    • 比较加密结果与客户端传来的signature部分
    • 一致则token有效
  3. 判断时间过期

    • 取出msg中的timestamp字段
    • 与当前系统时间比较
    • 过期时间小于当前时间则token过期

0x05 流程实现(Lua代码)

Token生成函数

local gen_token = function(key, expires)
    -- 设置过期时间戳(默认当前时间+8小时)
    if expires == nil then
        expires = os.time() + 60 + 60 * 8
    end
    
    -- 对msg部分进行base64编码
    local msg = encode_base64(
        json.encode({
            key = key,
            expires = expires
        })
    )
    
    -- 进行sha256哈希
    local signature = encode_base64(hmac_sha256('testkey', msg))
    
    -- 拼接成完整token
    return msg.."."..signature
end

Token验证函数

local val_token = function(key, token)
    -- 输入判空
    if not (token) then
        return nil, 'missing csrf token'
    end
    
    -- 拆分msg和signature
    local msg, sig = token:match("^(.*)%.(.*)$")
    if not (msg) then
        return nil, "malformed csrf token"
    end
    
    sig = encoding.decode_base64(sig)
    
    -- 签名验证
    if not (sig == hmac_sha256('testkey', msg)) then
        return nil, "invalid csrf token(bad sig)"
    end
    
    -- key验证
    msg = json.decode(decode_base64(msg))
    if not (msg.key == key) then
        return nil, "invalid csrf token (bad key)"
    end
    
    -- 过期时间验证
    if not (not msg.expires or msg.expires > os.time()) then
        return nil, "csrf token expired"
    end
    
    return true
end

0x06 核心安全算法库

实现Token机制需要以下库支持:

1. 加密库

LuaCrypto(推荐)

  • 安装:luarocks install luacrypto
  • 是OpenSSL库的前端lua调用
  • 依赖OpenSSL,支持sha256加密
  • 示例代码:
local crypto = require("crypto")
local hmac = require("crypto.hmac")
local ret = hmac.digest("sha256", "abcdefg", "hmackey")
print(ret)

其他选项

  • SecureHashAlgorithm/SecureHashAlgorithmBW:纯lua实现,但依赖lua5.2/5.3
  • Lcrypt:C语言实现,依赖libTomCrypt和libTomMath

2. Base64库

推荐使用:https://github.com/toastdriven/lua-base64

0x07 总结

  1. 现代WEB开发必须重视输入数据的有效性验证
  2. 渗透攻击方式不断演变,防御手段也需要相应更新
  3. 安全人员需要从攻防双重角度理解问题
  4. CSRF防御核心:
    • Token机制
    • 时间戳管理
    • 签名验证
  5. 任何程序都可能存在漏洞,安全是持续的过程

通过这种基于时间和签名的防护机制,可以有效降低CSRF攻击的成功率,为WEB应用提供更安全的防护。

CSRF攻击防御原理详解 0x01 前言 CSRF(Cross-Site Request Forgery,跨站请求伪造)是现代浏览器工作机制导致的一种常见WEB攻击形态。本文将从攻击原理和服务器端防御解决方案两方面进行详细阐述。 CSRF是现代WEB程序面临的共性问题,许多流行WEB框架都在框架层面解决了这一问题。本文将介绍基于时间与签名的防护手段,并提供具体代码实现(使用Lua语言)。 0x02 CSRF攻击原理 CSRF概念 CSRF跨站点请求伪造是一种危害巨大的攻击方式,攻击者盗用用户身份,以用户名义发送恶意请求。对服务器而言这些请求完全合法,但实际完成了攻击者期望的操作,如: 以用户名义发送邮件/消息 盗取账号 添加系统管理员 购买商品 虚拟货币转账等 攻击场景 Web A:存在CSRF漏洞的网站 Web B:攻击者构建的恶意网站 User C:Web A的合法用户 攻击过程 用户C打开浏览器,访问受信任网站A,输入用户名密码登录 用户信息验证通过后,网站A产生Cookie信息返回给浏览器,用户登录成功 用户未退出网站A前,在同一浏览器中打开新标签页访问网站B 网站B返回攻击性代码,并发出访问网站A的请求 浏览器接收攻击代码后,在用户不知情下携带Cookie信息向网站A发出请求 网站A认为请求来自用户C,以C的权限处理请求,导致恶意代码执行 0x03 CSRF防御原理 防御核心思想 CSRF防护重点是对"用户凭证"进行校验,判断请求是否合法。由于"用户凭证"存储在Cookie中,防护机制主要处理Cookie数据,需要: 加入签名校验 实现数据生命周期(过期)管理 Token机制设计 Lapis框架(基于Moonscript的WEB框架)采用基于时间戳和签名验证的CSRF防护设计: 创建Token处理机制 Token数据结构与时间、加密签名直接相关 目的:为"身份凭证"添加时间生存周期管理和签名校验管理 0x04 签名与时间戳防护处理流程 Token生成 Token构成 Token由三部分组成: 消息(msg) 随机字符串 过期时间戳 分隔符(separator):使用"."分隔msg和signature 签名(signature):对"msg消息"用特定算法加密后的串 结构表示: 加密方法 使用sha256散列算法 进行BASE64格式转换 隐含过期时间设定 Token验证 验证步骤 Token解包 以"."为分隔符,分为msg部分和signature部分 比对签名 对msg部分base64解码 对解码后的msg明文进行相同加密处理 比较加密结果与客户端传来的signature部分 一致则token有效 判断时间过期 取出msg中的timestamp字段 与当前系统时间比较 过期时间小于当前时间则token过期 0x05 流程实现(Lua代码) Token生成函数 Token验证函数 0x06 核心安全算法库 实现Token机制需要以下库支持: 1. 加密库 LuaCrypto(推荐) 安装: luarocks install luacrypto 是OpenSSL库的前端lua调用 依赖OpenSSL,支持sha256加密 示例代码: 其他选项 SecureHashAlgorithm/SecureHashAlgorithmBW:纯lua实现,但依赖lua5.2/5.3 Lcrypt:C语言实现,依赖libTomCrypt和libTomMath 2. Base64库 推荐使用:https://github.com/toastdriven/lua-base64 0x07 总结 现代WEB开发必须重视输入数据的有效性验证 渗透攻击方式不断演变,防御手段也需要相应更新 安全人员需要从攻防双重角度理解问题 CSRF防御核心: Token机制 时间戳管理 签名验证 任何程序都可能存在漏洞,安全是持续的过程 通过这种基于时间和签名的防护机制,可以有效降低CSRF攻击的成功率,为WEB应用提供更安全的防护。