前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CSRF攻击防御原理

CSRF攻击防御原理

作者头像
糖果
发布2020-01-14 16:18:59
1.8K0
发布2020-01-14 16:18:59
举报
文章被收录于专栏:糖果的实验室

Leafo老师基于Moonscript语言开发的WEB框架Lapis,框架中有一段针对CSRF(Cross—Site Request Forgery)的防护代码, 是一种基于围绕时间戳和签名验证的CSRF防护设计,后来Leafo老师还更新了CSRF的处理代吗:

Changes

  • Replaced the CSRF implementation, removed the key parameter and replaced with it randomly generated string stored in cookie.

跨站攻击的本质是, 攻击者拿着你的“身份凭证”,冒充你进行的相关攻击行为

为了防止CSRF的发生,创建Token处理机制,Token数据结构与时间、加密签名相关, 这么做的目的是给“身份凭证”加上时间生存周期管理,如果的凭证被人拿到了, 要先判断Token中的“签名”与时间戳是否都有效。

以下,是Token生成的加密原理和具体实现例子:

1.Token构成。

为了防止CSRF攻击,Token要求不能重复,需要含有时间戳信息。

下面的图描述了一个token的数据构成:

Token的数据结构。

代码语言:javascript
复制
-----------------------------------------------------------------------------
|             msg                  |     separator   |  signature           |
-----------------------------------------------------------------------------
|     key     |   timestamp        |                 |  Base64(sha256(msg)) |
-----------------------------------------------------------------------------

token由三部分组成:

a). 消息[msg]:而msg本身也有两部分组成:一部分:随机字符串,过期时间戳。

b). 分割符[separator]:用于分隔msg部分与加密后生成的signature签名部分,这里用的是”.“

c). 签名[signature]:signature。signature签名,是对“msg消息”用特定算法进行加密后的串。

代码语言:javascript
复制
token = base64(msg)格式化..base64(sha256("秘锁", msg))

Token由被Base64的msg编码串+先256加密msg再进行Base64编码,两个串的内容结合。

2.Token的加密。

首先,是按照合适得加密方法对数据进行加密。这里我们通用的就使用了sha256散列算法,然后进行BASE64的格式转换。然后,我们需要在token串中隐含过期时间的设定,这种机制要保证,每条与服务器交互的Token有过期时间控制,一点过期服务器不处理。

3.Token的验证校验。

当用户从客户端,计算了Token提交给服务器的时候,服务器需要判断token的有效性(是否过期),一旦传向服务器的请求中的Token时间异常,就可以判定是可疑请求。

验证具体过程:

a). Token解包。

先把接受到的token,进行分解,“.”为分隔符,分为msg部分+signature签名部分。

b). 比对签名。

对msg部分的base64码反向decode_base64(msg)解码,在对解码后的msg明文,进行同样的encode_base64(sha256(msg))签名串转换处理。如果秘锁相同,判断加密后的数据和客户端传过来的token.signature的部分是否一致。如果一致,说明这个token是有效的。

c). 判断时间过期。

如果是有效的,取出msg取出msg信息中的timestamp字段数据,与当前系统时间进行比较,如果过期时间小于当前时间,那这个token是过期的,需要重新的取得token。

Lua代码如下:

代码语言:javascript
复制
local gen_token = function(key, expires)
    --做成一个过期时间戳。
    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


local  val_token = function(key,token)
    --对输入数据的判空操作
    if not (token) then
     return nil, 'mssing csrf token'
    end
    
    --对token的msg部分,signature签名部分进行拆分。
    local msg, sig = token:match("^(.*)%.(.*)$")
    if not (msg) then
         return nil, "malformed csrf token"
    end


    sig = encoding.decode_base64(sig)
    --对解包后msg,按照相同的加密key:"testkey",重新进行sha256哈希,比对signature,
    --如果不一致,说明这个token中的数据有问题,无效的token。
    if not (sig == hmac_sha256('testkey', msg)) then
         return nil, "invalid csrf token(bad sig)"
    end


    --对msg进行base64解码,判断其中的key和传入的key是否一致。
    --如果不一致说明token也是无效的。
    msg =json.decode(decode_base64(msg))
    if not (msg.key == key) then
     return nil, "invalid csrf token (bad key)"    
    end
    
    --取出msg部分的时间戳,判断是否大于当前时间,如果大于,说明token过期无效了。
    if not (not msg.expires or msg.expires > os.time()) then
         return nil, "csrf token expired"
    end
end

因为本文提到的 CSRF防护,是Leafo老师的Moonscript(Lua)实现, 而用的Token编码的函数与signature签名用的加密算法,也都是基于Lua库,所以下面列出了这些常用的库的相关信息。

库一览列表:

代码语言:javascript
复制
http://lua-users.org/wiki/CryptographyStuff

要实现上文所说的Token机制,要有库函数Bash64与sha256加密的工具包库支持。

不用Lua的同学,可以忽略下面的内容:

1.SecureHashAlgorithm和SecureHashAlgorithmBW

这个工具包是支持sha256加密的,而且是纯lua方法的实现,问题是,这两个包分别依赖lua5.2和lua5.3。

而我们系统的运行环境是lua5.1,因为大部分的生产环境都是lua5.1,因为历史原因暂时没法改变。如果要把5.2的程序移植到5.1下运行,还需要移植一个lua5.2才独有的包,这是lua5.2升级之后才有的部件:bit32,而在lua5.3中又将这个部件去掉了,移植的动力不大,暂时不使用这个包。

2.Lcrypt

这个包不是纯lua的实现,底层加密用的是C语言,而且额外还有依赖另外另个工具包 libTomCrypt和libTomMath,这两个包的官网已经被和谐了,github上有源码,所以要想让这个包正常运行需要手动make安装3个源码工程,还是算了,有时间的时候再装好测试一下,先暂时不用。

网站:

代码语言:javascript
复制
http://www.eder.us/projects/lcrypt/

3.LuaCrypto

这个包的安装用的是luarocks,就比较简单了

代码语言:javascript
复制
luarocks install luacrypto

我们选用这个包进行加密处理。LuaCrypto其实是openssl库的前端lua调用,依赖openssl,openssl库显然会支持sha256加密,相对也比一般的第三方实现更可靠。写一个简单的加密程序:

代码语言:javascript
复制
local crypto = require("crypto")
local hmac = require("crypto.hmac")
local ret = hmac.digest("sha256", "abcdefg", "hmackey")
print(ret)

ret的返回结果是,如下这个字符串。

代码语言:javascript
复制
704d25d116a700656bfa5a6a7b0f462efdc7df828cdbafa6fbf8b39a12e83f24

我们需要改造一下代码,在调用digest的时候指定输出的形式是raw二进制数据形式,然后在编码成base64的数据形式。

代码语言:javascript
复制
local ret = hmac.digest("sha256", "abcdefg", "hmackey",rawequal)
print(ret)

这时候的输出结果是:

代码语言:javascript
复制
cE0l0RanAGVr+lpqew9GLv3H34KM26+m+/izmhLoPyQ=
lua-base64

使用的是下面的库,lua库就是这样,有很多功能程序有很多的实现,并且很多非官方的第三方实现。

代码语言:javascript
复制
https://github.com/toastdriven/lua-base64
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-01-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 糖果的实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.Token构成。
  • 2.Token的加密。
  • 3.Token的验证校验。
    • a). Token解包。
      • b). 比对签名。
        • c). 判断时间过期。
          • 不用Lua的同学,可以忽略下面的内容:
            • 1.SecureHashAlgorithm和SecureHashAlgorithmBW
            • 2.Lcrypt
            • 3.LuaCrypto
        相关产品与服务
        SSL 证书
        腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档