安全注意事项

Web 应用通常面临所有种类的安全问题,并且很难把所有事做的正确。 Flask 试图 为你解决这些事情中的一些,但你仍需要关心更多的问题。

跨站脚本(XSS)

跨站脚本攻击的概念是在一个网站的上下文中注入任意的 HTML (以及附带的 JavaScript )。 开发者需要正确地转义文本,使其不能包含任意 HTML 标签来避免 这种攻击。 有关详细信息,请参阅有关跨网站脚本的维基百科文章。

Flask 配置 Jinja2 自动转义所有值,除非显式地指明不转义。 这就排除了模板导 致的所有 XSS 问题,但是你仍需要在其它的地方小心:

  • 生成 HTML 而不使用 Jinja2
  • 在用户提交的数据上调用了 Markup
  • 从上传的文件发出HTML,从不这样做,请使用Content-Disposition: 附件
  • 发送上传的文本文件。 一些浏览器使用基于开头几个字节的 content-type 猜测,所以用户可能欺骗浏览器执行 HTML

另一件非常重要的事情是未用引号包裹的属性。 虽然 Jinja2 可以通过转义 HTML 来保护你免受 XSS 问题,仍有一种情况,它不能保护你: 属性注入的 XSS 。 为了 应对这种攻击媒介,确保当在属性中使用 Jinja 表达式时,始终用单引号或双引号 包裹属性:

<a href="{{ href }}">the text</a>

为什么这是必要的? 因为如果你不这么做,攻击者可以容易地注入自制的 JavaScript 处理器。 譬如一个攻击者可以注入这段 HTML+JavaScript:

onmouseover=alert(document.cookie)

当用户鼠标经过这个链接, 会在警告窗口里把 cookie 显示给用户。 一个精明的 攻击者可能也会执行其它的 JavaScript 代码,而不是把 cookie 显示给用户。 同 CSS 注入联系在一起,攻击者甚至使得元素填满整个页面,这样用户鼠标在页面 上的任何地方都会触发攻击。

跨站点请求伪造(CSRF)

另一个大问题是 CSRF 。 这是一个非常复杂的话题,我不会在此详细介绍,而只会 提及 CSRF 是什么和理论上如何避免它。

如果你的验证信息存储在 cookie 中,你有隐式的状态管理。 “已登入”状态由一个 cookie 控制,并且这个 cookie 在每个页面的请求中都会发送。 不幸的是,在第三 方站点触发的请求中也会发送这个 cookie 。 如果你不注意这点,一些人可能会通过 社会工程学来诱导你应用的用户在他们不知道的情况下做一些蠢事。

假设您有一个特定网址,当您发送POST请求时,将删除用户的个人资料(例如http://example.com/user/delete)。 如果一个攻击者现在创造一个页面来用 JavaScript 发送这个 post 请求,他们只是诱骗一些用户加载那个页面,而他们 的资料最终会被删除。

想象你在运行 Facebook ,有数以百万计的并发用户,并且某人放出一些小猫图片 的链接。 当用户访问那个页面欣赏毛茸茸的猫的图片时,他们的资料就被删除。

你怎么能防止这种情况? 基本上,对于每个修改服务器上内容的请求,你应该使用 一次性令牌,并存储在 cookie 里, 并且 在发送表单数据的同时附上它。 在服务器再次接收数据之后,你要比较两个令牌,并确保它们相等。

为什么 Flask 没有为你这么做? 理想情况下,这应该是表单验证框架做的事,而 Flask 中并不存在表单验证。

JSON安全

不幸的是,只有在 jsonify() 中有这样的保护,所以如果你用其它方法生成 JSON 仍然 有风险。 幸运 的是, JavaScript 规范中有一个怪异的部分可以用于简易地解决这一问题。

从 ECMAScript 5 开始,常量的行为变化了。 所有这些浏览器都有其他更严重的漏洞,因此此行为已更改,jsonify()现在支持序列化数组。