为你的Django项目保驾护航


保证你的站点安全至关重要,如果你的站点被入侵,后果可能不仅仅是你的服务器被黑,更严重的可能是你的用户隐私数据被盗,造成严重的后果。 Django框架现在已经非常成熟,大多数常见的安全问题框架本身都有提供解决方案,下面大致介绍下一些常见的防御措施。

Https

现在的网站https基本都是标配了吧,如果你的网站还没有支持https,那么就要考虑是不是需要尽快为你的网站加上https,这里推荐使用免费的Let's Encrypt。本站使用的就是他们颁发的证书。可以参考该文章:
申请Let's Encrypt通配符证书有大致的介绍。 如果你的站点已经支持了https访问的话,建议在settings.py中加入:

SECURE_SSL_REDIRECT = True #将http请求重定向到https
SESSION_COOKIE_SECURE = True #只在https才会将cookie发送到客户端
CSRF_COOKIE_SECURE = True

HTTP 严格传输安全协议(HSTS)

HSTS最为核心的是一个HTTP响应头(HTTP Response Header)。正是它可以让浏览器得知,在接下来的一段时间内,当前域名只能通过HTTPS进行访问,并且在浏览器发现当前连接不安全的情况下,强制拒绝用户的后续访问要求。 如本站:

strict-transport-security: max-age=31536000; includeSubDomains; preload

其中:

  1. max-age是必选参数,是一个以秒为单位的数值,它代表着HSTS Header的过期时间,通常设置为1年,即31536000秒。
  2. includeSubDomains是可选参数,如果包含它,则意味着当前域名及其子域名均开启HSTS保护。
  3. preload是可选参数,只有当你申请将自己的域名加入到浏览器内置列表的时候才需要使用到它。

跨站点脚本(XSS)保护

这个大致意思就是用户可能在你需要输入的地方写入一些恶意的JavaScript代码,保存到你数据库之后如果你没有做特殊处理的话可能会导致这些恶意的JavaScript代码在别的用户浏览器执行。如下所示: 用户在你的输入框中输入了如下内容:

<script>alert(document.cookie)</script>

如果你没有处理这段内容的话,在别的用户访问该页面的时候,会弹出提示框,内容是用户在该网站的cookie信息。 下面是解决办法: 使用escape过滤器,如本站的评论部分:

<p>{{ comment_item.body |escape|custom_markdown }}</p>

X-XSS-Protection

这个响应头是用来防范XSS的。现在主流浏览器都支持,并且默认都开启了XSS保护,用这个header可以关闭它。它有几种配置:

  1. 0:禁用XSS保护;
  2. 1:启用XSS保护;
  3. 1; mode=block:启用XSS保护,并在检查到XSS攻击时,停止渲染页面(例如IE8中,检查到攻击时,整个页面会被一个#替换);

在Django中,设置SECURE_BROWSER_XSS_FILTER = True可以启用

跨站点请求伪造(CSRF)保护

CSRF攻击允许恶意用户使用其他用户的凭据执行操作,而无需用户知晓或同意。 csrf 从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  1. 登录受信任网站A,并在本地生成Cookie。
  2. 在不登出A的情况下,访问危险网站B。

看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:

  1. 你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
  2. 你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了......)
  3. 上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。

如果你启用了django.middleware.csrf.CsrfViewMiddleware,Django会检查HTTP引用标头是否设置为同一来源(包括子域和端口)上的URL。 在提交表单的时候,可能会有这样的字段内容:

csrfmiddlewaretoken: qPqPpIDvpRfbzRxmQmrXHeSPUe2errCY6k9EHgCkuoGwpXo6wDnEG3kOXNuSUKKD

使用csrf_exempt装饰器可以禁用该检查,但是必须要非常小心。

SQL注入

SQL注入也算是一个比较常见的攻击方式了,尽量使用Django自带的ORM就可以避免大多数的攻击。

点击劫持(ClickJacking)

点击劫持(ClickJacking)是一种视觉上的欺骗手段。大概有两种方式,一是攻击者使用一个透明的iframe,覆盖在一个网页上,然后诱使用户在该页面上进行操作,此时用户将在不知情的情况下点击透明的iframe页面;二是攻击者使用一张图片覆盖在网页,遮挡网页原有位置的含义。 使用X-Frame-OptionsHTTP头就可以解决这个问题。X-Frame-Options可以说是为了解决ClickJacking而生的,它有三个可选的值:

  1. DENY:浏览器会拒绝当前页面加载任何frame页面;
  2. SAMEORIGIN:frame页面的地址只能为同源域名下的页面;
  3. ALLOW-FROM origin:允许frame加载的页面地址。

在Django中,启用django.middleware.clickjacking.XFrameOptionsMiddleware就可以了,默认情况下,会设置X_FRAME_OPTIONS = 'SAMEORIGIN'.你可以在settings.py中修改为X_FRAME_OPTIONS = 'DENY'来覆盖。

其他

上述只是列举了部分常见的攻击方式,对于Django来说,还有如下几个需要注意的地方:

  1. 在线上环境一定要将DEBUG设置为False.
  2. SECRET_KEY保密,保密,保密。
  3. 如果你的网站有用户上传文件的功能,一定要注意文件检查以及权限。
  4. 不能让用户访问到你的python源码。这个可以使用nginx来过滤。

其他的一些安全方面需要注意的点:

  1. 设置X-Content-Type-Options,禁止浏览器进行类型猜测。
  2. 设置X-Content-Security-Policy 定义页面可以加载哪些资源。
  3. 如果是https的话,尽量启用HSTS.

参考:

  1. http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html
  2. https://docs.djangoproject.com/en/2.1/topics/security
  3. https://imququ.com/post/web-security-and-response-header.html