网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
0x03 CSRF防御原理
CSRF防护的一个重点是要对“用户凭证”进行校验处理,通过这种机制可以对用户的请求是合法进行判断,判断是不是跨站攻击的行为。因为“用户凭证”是Cookie中存储的,所以防护机制的处理对像也是Cookie的数据,我们要在防护的数据中加入签名校验,并对数据进行生命周期时间管理,就是数据过期管理。
Lapis框架是一种基于Moonscript语言开发的WEB框架,框架中有一段针对CSRF(Cross—Site Request Forgery)的防护代码, 是一种围绕时间戳和签名验证的CSRF防护设计,后来Lapis的作者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中的“签名”与时间戳是否都有效,再进行正常的业务处理, 这样通过对非法数据的校验过滤,来降低CSRF攻击的成功率。
0x04 签名与时间戳防护处理流程
Token产生
1.Token构成
为了防止CSRF攻击,Token要求不能重复,需要含有时间戳信息、签名信息。
下面的图描述了一个token的数据构成:
Token的数据结构。
`-----------------------------------------------------------------------------``| msg | separator | signature |``-----------------------------------------------------------------------------``| key | timestamp | . | Base64(sha256(msg)) |``-----------------------------------------------------------------------------`
token由三部分组成:
a). 消息[msg]:而msg本身也有两部分组成:一部分:随机字符串,过期时间戳。
b). 分割符[separator]:用于分隔msg部分与加密后生成的signature签名部分,这里用的是”.“
c). 签名[signature]:signature。signature签名,是对“msg消息”用特定算法进行加密后的串。
`token = base64(msg)格式化..base64(sha256("密锁", msg))`
Token由被Base64的msg编码串+先256加密msg再进行Base64编码,两个串的内容结合。
2.Token的加密
首先,是按照合适的加密方法对数据进行加密。这里我们通用的就使用了sha256散列算法,然后进行BASE64的格式转换。然后,我们需要在token串中隐含过期时间的设定,这种机制要保证,每条与服务器交互的Token有过期时间控制,一旦token过期服务器不处理请求。
3.Token的验证校验
当用户向服务提出访问请求时,产生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中的timestamp字段数据,与当前系统时间进行比较,如果过期时间小于当前时间,那这个token是过期的,需要重新的取得token。
0x05 流程实现
文字版本的防护原理上面讲了,下面我们将整个防护流程分解成函数实现, 直接通过代码的形式来看实现,其实比看文字描述更简单。
Lua代码如下:
`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防护,是Moonscript实现的,最后翻译成Lua语言, 而用的Token编码的函数与signature签名用的加密算法,也都是基于Lua库,所以下面列出了这些常用的库的相关信息。
库一览列表:
`http://lua-users.org/wiki/CryptographyStuff`
0x06 核心安全算法库
要实现上文所说的Token机制,要有库函数Bash64与sha256加密的工具包库支持。
1.SecureHashAlgorithm和SecureHashAlgorithmBW
这个工具包是支持sha256加密的,而且是纯lua方法的实现,问题是,这两个包分别依赖lua5.2和lua5.3。
大部分老系统的运行环境是lua5.1,因为大部分的生产环境都是lua5.1,因为历史原因暂时没法改变。如果要把5.2的程序移植到5.1下运行,还需要移植一个lua5.2才独有的包,这是lua5.2升级之后才有的部件:bit32,而在lua5.3中又将这个部件去掉了,移植的动力不大,lua5.1的用户可以考虑使用其他的库。
2.Lcrypt
这个包不是纯lua的实现,底层加密用的是C语言,而且额外还有依赖另外另个工具包 libTomCrypt和libTomMath,github上有源码,所以要想让这个包正常运行需要手动make安装3个源码工程。
网站:
`http://www.eder.us/projects/lcrypt/`
3.LuaCrypto
这个包的安装用的是luarocks,就比较简单了
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!