Play 框架手册(16) – 安全指南


play 框架的安全设计只是存在于脑海中的一个概念——这就不可能阻止开发者在设计上出漏洞。本指南描述了在 Web 应用中常见的安全问题,并指导如何在play 应用开发中去避免。

16.1. Sessions 

一般情况下,你需要保存用户登录信息。如果不使用 session,用户就需要在每次请求时传递证书。

这就是 session 要做的事:一系列 cookies 存储在用户的浏览器里,以用于标识不同的站点,并提供其他数据层之外的信息,比如语言。

守住你的安全…安全

session 是一个 key/values 哈希表,有签名但没有加密。也就是说主要你的secret 是安全的,那么第三方就不可能伪造 session。

而 secret 存储在 conf/application.conf 里。 保持这个文件的私有化非常重要:不要把它提交给公共仓库,为防止在安装某些人写的应用程序时对 secret key进行修改,你可以运行命令 play secret 进行保护。

不要存储关键性的数据 

然后, 既然 session 没有加密, 那么就不应该在 session 里存储关键性安全数据,通过本地网络连接或 wifi 连接进行嗅探,它将被看成是用户的 cookie。

session 被存储在 cookie 里, 而 cookies 被限制为 4 KB 大小。而且只能存储 String。

16.2. 跨站点脚本攻击 

在 web 应用程序中,Cross-site scripting 跨站点脚本是最常见的弱点。它包含了利用应用程序提供的窗体恶意注入到 web 页面的脚本代码。

假定这里有一个博客程序,任何人都可以发表评论,如果评论内容里包含了攻击脚本,那么你将打开你的站点进行攻击,可能步骤为:

  • 为访问者弹出一个窗体
  • 跳转访问者到被攻击者控制的站点
  • 窃取当前用户的可见信息,并发回攻击者的站点

因此为防止类似攻击,进行保护非常重要。

play的模板引擎会自动转义字符串。 如果需要在模板里插入未转义的 HTML代码,那就需要使用 java 字符串扩展的 raw() 方法。但如果这个字符串是用户输入的,那么你就需要首先确定它是否是无害的。

在对用户输入进行 sanitizing 消毒的时候,只允许白名单(只允许列表中的安全标签通过)通过,黑名单 (禁止一些不安全的标签列表)则禁止。

详见 cross-site scripting

16.3. SQL 注入

SQL 注入所谓 SQL 注入,就是通过把 SQL 命令插入到 Web 表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的 SQL 命令,比如先前的很多影视网站泄露 VIP 会员密码大多就是通过 WEB 表单递交查询字符暴出的, 这类表单特别容易受到 SQL 注入式攻击。这个漏洞可以摧毁数据,或访问不应该让当前用户看到的数据。

当使用高级的“find”方法时, 就应该小心 sql 注入。 当手工构建自己的查询时,尽量不要用+来作连接符,而是用?占位符。

比如:

createQuery("SELECT * from Stuff WHERE type= ?1").setParameter(1,theType);

下面这个就不好了:

createQuery("SELECT * from Stuff WHERE type=" + theType;

16.4. 跨站点请求伪造

跨站点请求伪造 CSRF 攻击在 web 应用程序里非常危险:这个攻击方法通过在用户信任的 web 应用程序的页面里加入恶意代码或链接进行攻击。如果 web 应用程序的 session 没有设置超时,那么攻击者就可以执行未经验证的命令。

为预防这类攻击,首先就是要正确全用 GET 和 POST 方法。意思是仅允许 POST 方法用于修改应用程序的状态。

对 POST 请求来说,只有真实的 token 才会触发动作。Play 现在内建了一个帮助类用于处理这样的问题:

  • checkAuthenticity() 检查真实性方法在控制器里可直接使用, 用于检查请求参数里的 token 的真实有效,如果存在问题,就发送一个禁止response 的命令。
  • session.getAuthenticityToken()方法用于为当前 session 生成一个真实可信的 token
  • #{authenticityToken /}用于创建一个隐藏的输入域,可用于任何窗体 

示例:

public static destroyMyAccount() {
    checkAuthenticity();
    ...
}

上面的方法仅当窗体包含了真实有效的 token 时,才会被调用:

<form method="post" action="/account/destroy">
    #{authenticityToken /}
    <input type="submit" value="destroy my account">
</form>

对 POST 请求来说,Play 提供 form 标签会自动生成一个有效的 token:

#{form @destroyMyAccount()}
    <input type="submit" value="destroy my account">
#{/form}

如果你想保护所有控制器的 action 动作,你也可以使用 checkAuthenticity() 方法作为 before filter 进行听说。

更多跨站点请求伪造见:More on cross-site request forgery。


前一篇:
后一篇:

发表评论