XSRF
XSRF即为跨站请求伪造
这个漏洞利用了浏览器的一个允许恶意攻击者在受害者网站注入脚本使未授权请求代表一个已登录用户的安全漏洞。
了解XSRF
当一个网站的图片SRC属性为另一个网站的链接时,浏览器加载这个网站的这张图片时就会访问另一个网站。
防范请求伪造
重要的请求尽可能使用post方法,但这并不是万能的,因为post方法也会被伪造(如HTML表单或XMLHTTPRequest API来向你的应用发送POST请求)。
为了防范伪造POST请求,我们会要求每个请求包括一个参数值作为令牌(token)来匹配存储在cookie中的对应值。我们的应用将通过一个cookie头和一个隐藏的HTML表单元素向页面提供令牌。当一个合法页面的表单被提交时,它将包括表单值和已存储的cookie。如果两者匹配,我们的应用认定请求有效。
由于第三方站点没有访问cookie数据的权限,他们将不能在请求中包含令牌cookie。这有效地防止了不可信网站发送未授权的请求。
使用Tornado的XSRF保护
在setting中做如下设置
settings = { "cookie_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=", "xsrf_cookies": True }
当这个应用标识被设置时,Tornado将拒绝请求参数中不包含正确的_xsrf值的POST、PUT和DELETE请求。Tornado将会在幕后处理_xsrf cookies,但你必须在你的HTML表单中包含XSRF令牌以确保授权合法请求。要做到这一点,只需要在你的模板中包含一个xsrf_form_html调用即可:
<form action="/purchase" method="POST"> {% raw xsrf_form_html() %} <input type="text" name="title" /> <input type="text" name="quantity" /> <input type="submit" value="Check Out" /> </form>
实现原理
- 为浏览器设置了一个名为_xsrf的安全cookie,这个cookie在关闭浏览器后会失效
- 为模板表单添加了一个隐藏域,名为_xsrf,值为_xsrf这个cookie的值
手动设置_xsrf的cookie
class SetXSRFCookieHandler(RequestHandler): def get(self, *args, **kwargs): # 设置_xsrf的cookie self.xsrf_token self.finish("ok")
为了让用户一访问就加载上,通常将其放在请求主页的Handler中,而一般将静态页面作为主页,所以在StaticHandler中添加即可
# 定义自己的StaticFileHandler class StaticFileHandler(StaticFileHandler): def __init__(self, *args, **kwargs): super(StaticFileHandler, self).__init__(*args, **kwargs) self.xsrf_token
XSRF令牌和AJAX请求
AJAX请求也需要一个_xsrf参数,但不是必须显式地在渲染页面时包含一个_xsrf值,而是通过脚本在客户端查询浏览器获得cookie值。下面的两个函数透明地添加令牌值给AJAX POST请求。第一个函数通过名字获取cookie,而第二个函数是一个添加_xsrf参数到传递给postJSON函数数据对象的便捷函数。
function getCookie(name) { var c = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return c ? c[1] : undefined; } jQuery.postJSON = function(url, data, callback) { data._xsrf = getCookie("_xsrf"); jQuery.ajax({ url: url, data: jQuery.param(data), dataType: "json", type: "POST", success: callback }); }