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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java入门第四步之应用服务器的安装(Tomcat)

    java入门第四步之应用服务器的安装(Tomcat)

    2021年8月18日
    48
  • SQL 获取当前系统时间

    SQL 获取当前系统时间SQL获取当前系统时间

    2022年10月19日
    0
  • 30分钟后页面自动跳转到登录页面「建议收藏」

    30分钟后页面自动跳转到登录页面「建议收藏」年前到年后这段时间很浮躁,继续学习之旅,从这篇博客开始,2018,加油!梭哈梭哈。。。。代码拿去,妥妥的,什么session,什么filter,什么listener<scriptlanguage=”javascript”>varmyTime=setTimeout(“Timeout()”,60000);functionresetTime()…

    2022年5月30日
    89
  • Navicat for MySQL 15mac激活码【2021.8最新】

    (Navicat for MySQL 15mac激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月25日
    328
  • 详解Python中pyautogui库的最全使用方法

    详解Python中pyautogui库的最全使用方法这篇文章主要介绍了详解Python中pyautogui库的最全使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值在使用Python做脚本的话,有两个库可以使用,一个为PyUserInput库,另一个为pyautogui库。就本人而言,我更喜欢使用pyautogui库,该库功能多,使用便利。下面给大家介绍一下pyautogui库的使用方法。在cmd命令框中输入pip3installpyautogui即可安装该库!常用操作我们在pyautogui库中常

    2022年7月20日
    13
  • PC傻瓜式安装黑苹果并打造成全能逆向工作站–更新至2021.12.20

    PC傻瓜式安装黑苹果并打造成全能逆向工作站–更新至2021.12.20安装黑苹果有多简单原版Windows镜像安装大家都会,当然Ghost安装除外喔,太“乡村范儿”了。Windows操作系统的安装,无非下列四个步骤。准备镜像→写镜像到U盘→从U盘安装系统→系统自定义配置现在我们安装黑苹果也是同样的流程。先说一下本机的配置:2014年1999元买的宁美国度的组装台式机*CPU:i34160*GPU:HD4400CPU自带*RAM:4…

    2022年6月11日
    37

发表回复

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

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