Torando源码解析之XSRF防护的实现

Torando源码解析之XSRF防护的实现Torando源码解析之XSRF防护的实现Torando源码解析之XSRF防护的实现Tornado开启XSRF防护的方法源码解析xsrf_form_html()是什么self.xsrf_token是什么Tornado开启XSRF防护的方法http://tornado-zh.readthedocs.io/zh/latest/guide/security.ht…

大家好,又见面了,我是你们的朋友全栈君。

Torando源码解析之XSRF防护的实现

Tornado开启XSRF防护的方法

http://tornado-zh.readthedocs.io/zh/latest/guide/security.html

核心代码如下
Tornado开启xsrf_cookies

settings = {
    "cookie_secret": "__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
    "login_url": "/login",
    "xsrf_cookies": True,
}
application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/login", LoginHandler),
], **settings)

HTML页面添加相关的代码

<form action="/new_message" method="post"> {% module xsrf_form_html() %} ...... </form>

源码解析

在上述的代码中,很明显可以看出,所谓开启xsrf防护,其实就是在post提交的数据里面带上 {% module xsrf_form_html() %} 这段代码所包含的东西

xsrf_form_html()是什么

找到tornado的目录,然后再该目录下通过linux命令找到xsrf_form_html

grep xsrf_form_html -r *

查看grep结果,找到相关代码如下

def xsrf_form_html(self):
    return '<input type="hidden" name="_xsrf" value="' + \
        escape.xhtml_escape(self.xsrf_token) + '"/>'

发现所谓的 {% module xsrf_form_html() %}其实就是隐藏的一个

self.xsrf_token是什么

同样的方法找到xsrf_token

@property
def xsrf_token(self):
    if not hasattr(self, "_xsrf_token"):
        version, token, timestamp = self._get_raw_xsrf_token()
        output_version = self.settings.get("xsrf_cookie_version", 2)
        cookie_kwargs = self.settings.get("xsrf_cookie_kwargs", {})
        if output_version == 1:
            self._xsrf_token = binascii.b2a_hex(token)
        elif output_version == 2:
            mask = os.urandom(4)
            self._xsrf_token = b"|".join([
                b"2",
                binascii.b2a_hex(mask),
                binascii.b2a_hex(_websocket_mask(mask, token)),
                utf8(str(int(timestamp)))])
        else:
            raise ValueError("unknown xsrf cookie version %d",
                             output_version)
        if version is None:
            expires_days = 30 if self.current_user else None
            self.set_cookie("_xsrf", self._xsrf_token,
                            expires_days=expires_days,
                            **cookie_kwargs)
    return self._xsrf_token

其中,@property 是将该类函数设置成属性访问的装饰器
像第一次访问的时候,_xsrf_token这个值肯定是没有的
由代码可以看出token是其实就是self.xsrf_token的关键

def _get_raw_xsrf_token(self):
    if not hasattr(self, '_raw_xsrf_token'):
        cookie = self.get_cookie("_xsrf")
        if cookie:
            version, token, timestamp = self._decode_xsrf_token(cookie)
        else:
            version, token, timestamp = None, None, None
        if token is None:
            version = None
            token = os.urandom(16)
            timestamp = time.time()
        self._raw_xsrf_token = (version, token, timestamp)
    return self._raw_xsrf_token

这里其实就很明显可以看出
如果是第一次生成token,那么

token = os.urandom(16)

os.urandom(n) 是随机生成n个字节的函数
所以,token就是一个随机的16字节的串

如果不是第一次。那么会从cookie里面去获取token,并将这个token重新传回给前端

def _decode_xsrf_token(self, cookie):
    try:
        m = _signed_value_version_re.match(utf8(cookie))


        if m:
            version = int(m.group(1))
            if version == 2:
                _, mask, masked_token, timestamp = cookie.split("|")


                mask = binascii.a2b_hex(utf8(mask))
                token = _websocket_mask(
                    mask, binascii.a2b_hex(utf8(masked_token)))
                timestamp = int(timestamp)
                return version, token, timestamp
            else:
                raise Exception("Unknown xsrf cookie version")
        else:
            version = 1
            try:
                token = binascii.a2b_hex(utf8(cookie))
            except (binascii.Error, TypeError):
                token = utf8(cookie)           
            timestamp = int(time.time())
            return (version, token, timestamp)
    except Exception:
        gen_log.debug("Uncaught exception in _decode_xsrf_token",
                      exc_info=True)
        return None, None, None

这个与前面的xsrf_token 函数相对应,因为在传给前端的时候token进行了”encode”,所以获取的时候需要“decode”下。
当然这里所谓的”encode”和”decode”,其实仅仅是将版本号和当前的时间戳以某种规则加在了返回的token两边。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/144705.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • tcpdf_teambition搭建

    tcpdf_teambition搭建tcpdf开发文档(中文翻译版)2017年5月3日15:06:15这个是英文翻译版,我看过作者的文档其实不太友善或者不方便阅读,不如wiki方便后面补充一些,结构性文档翻译这是一部官方网站文档,剩余大部分都是开发的时候和网络总结来的项目官网:https://tcpdf.org/github:https://github.com/tecnickcom/TCPDF都没比较完整的api文档…

    2022年9月8日
    0
  • JS基础——cssText的用法[通俗易懂]

    JS基础——cssText的用法[通俗易懂]JS基础——cssText的用法#div1{width:100px;height:100px;background:#f3f3f3;border:1pxsolid#ccc;color:red;}window.onload=function(){ var oDiv=document.getElementById(‘div1’); varoBtn=docume

    2022年7月26日
    21
  • c++ accept_怎么把汇编语言转化为c语言

    c++ accept_怎么把汇编语言转化为c语言AcceptEx函数的定义如下:BOOLAcceptEx(SOCKETsListenSocket,SOCKETsAcceptSocket,PVOIDlpOutputBuffer,DWORDdwReceiveDataLength,DWORDdwLocalAddressLength,DWORDdwRemoteAddressLength,LPDWORDlpdwBytesReceived,…

    2022年9月29日
    0
  • Boost.Lockfree官方文档[通俗易懂]

    Boost.Lockfree官方文档[通俗易懂]目录介绍与动机简介与术语非阻塞数据结构的性质非阻塞数据结构的性能阻塞行为的来源数据结构数据结构配置示例队列栈无等待单生产者/单消费者队列脚注介绍与动机简介与术语术语“非阻塞”表示并发数据结构,该结构不使用传统的同步原语(例如警卫程序)来确保线程安全。MauriceHerlihy和NirShavit(比较“多处理器编程的艺术”)区分了3种类型的非阻塞数据结构,每种结构具有不同的属性:如果保证每个并发操作都可以在有限的步骤中完成,则数据.

    2022年7月19日
    25
  • pycharm安装第三方库失败_pycharm怎么安装python库

    pycharm安装第三方库失败_pycharm怎么安装python库pycharm安装第三方库首先启动pycharm随后通过快捷键进入setting界面,快捷键为ctrl+Als+S点击右上角的加号,添加第三方库在安装之前,首先点击ManageRepositories增加一些国内的镜像源,包括豆瓣http://pypi.douban.com/simple/阿里的,http://mirrors.aliyun.com/pypi/simple/https://pypi…

    2022年8月28日
    2
  • GPS通讯协议(NMEA0183)协议解析_台积电回应芯片巨头撤离

    GPS通讯协议(NMEA0183)协议解析_台积电回应芯片巨头撤离GPSNEMA0183协议 一、NMEA0183标准语句(GPS常用语句)$GPGGA例:$GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,19.7,M,,,,0000*1F字段0:$GPGGA,语句ID,表明该语句为GlobalPositioningSystemFixData(GGA)GPS定位信息字段1

    2025年6月12日
    10

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号