首页 > 代码库 > Java安全编码规范

Java安全编码规范

SQL Injectioin防范

ibatis框架
先看一段ibatis的xml配置

<select id="queryByAccountId" parameterClass="java.util.Map" resultMap="ApplicationInstanceResult">
    SELECT * FROM product where account_id = $accountId$
</select>

以上的sql中存在一个问题
$accountId$是变量替换的形式, 容易引入sql注入, 例如$accountId$是前台用户输入的"‘;select * from admin--", 那么数据库端就会执行两个sql, 所以需要改成#accountId#, 进行预编译处理
修改后的配置如下:

<select id="queryByAccountId" parameterClass="java.util.Map" resultMap="ApplicationInstanceResult">
    SELECT * FROM product where account_id = #accountId#
</select>

再看一段ibatis的xml配置

<select id="queryByAccountId" parameterClass="java.util.Map" resultMap="ApplicationInstanceResult">
    SELECT * FROM product where account_id = #accountId# ORDER BY $columnName$ $sortType$ LIMIT #start#, #rowNum#
</select>

可能由于某种需要搜索结果的排序很灵活, sql中有ORDER BY后$columnName$和$sortType$两个变量,在这里没法用变量绑定, 只能用$符号去替换,所以也存在隐患
其实如果这两个变量是程序中指定的, 那么是没有风险的
但是如果这两个变量是web前端选择填入的,那么就可以被利用构造sql注入的value, 就一定存在安全隐患, 碰到这样的情况, 我们需要映入安全开发的ibaits版本

<dependency>
  <groupId>com.alibaba.external</groupId>
  <artifactId>sourceforge.ibatis</artifactId>
  <version>2.3.4.726-patch</version>
</dependency>

然后是我们可以指定$columnName$和$sortType$的元数据类型, 如:$columnName:METADATA$, $sortType:SQLKEYWORD$, 这样ibatis就会做检查, 杜绝风险.
修改后的配置如下:

<select id="queryByAccountId" parameterClass="java.util.Map" resultMap="ApplicationInstanceResult">
    SELECT * FROM product where account_id = #accountId# ORDER BY $columnName:METADATA$ $sortType:SQLKEYWORD$ LIMIT #start#, #rowNum#
</select>

其他框架
禁止sql拼接生成, 必须使用变量绑定.
如使用spring jdbcTempalte的一段代码:

String insert = "insert into spacemapping (oldspaceid,oldspacekey,newspaceid,newspacekey) values (?,?,?,?)";
jdbcTemplate.batchUpdate(insert, new BatchPreparedStatementSetter() {
    public void setValues(PreparedStatement ps, int i) throws SQLException {
        Object[] spaceMapping = spaceMappings.get(i);
        ps.setLong(1, (Long)spaceMapping[0]);
        ps.setString(2, (String)spaceMapping[1]);
        ps.setLong(3, (Long)spaceMapping[2]);
        ps.setString(4, (String)spaceMapping[3]);
    }
    public int getBatchSize() {
        return spaceMappings.size();
    }
});

XSS 防范

攻击者在页面中注入恶意的js或者html代码,从而完全控制用户浏览器
假设一个模板中有以下内容

<table>
  <tr>
    <td>用户名:</td>
    <td>$userName</td>
  </tr>
</table>

假设用户输入的$userName为"<script src=http://www.mamicode.com/xxx></script>", 那么就插入了恶意脚本的标签, 所以我们先对$userName进行一次html字符的转义处理, 就可以防止.
修改后的代码如下:

<table>
  <tr>
    <td>用户名:</td>
    <td>$stringEscapeUtil.escapeHtml($userName)</td>
  </tr>
</table>

假设模板中有一段构建js的代码,js的功能是同态构建html内容

#foreach ( $node in $nodeList )
   var input = document.createElement("input");
   input.name="$node.name";
   input.value= http://www.mamicode.com/"$!node.value";
   someForm.appendChild(input);
#end

假设node中数据是用户输入的, 就可以植入js恶意脚本,如:";alert(/alibaba/);"导致安全漏洞, 所以我们就需要对node的数据输出时进行一次js字符的转义处理, 修改后的代码如下:

#foreach ( $node in $nodeList )
   var input = document.createElement("input");
   input.name = "$stringEscapeUtil.escapeJavaScript($node.name)";
   input.value = http://www.mamicode.com/"$stringEscapeUtil.escapeJavaScript($!node.value)";
   someForm.appendChild(input);
#end

webx的template service plugins配置

<plugins>
                <vm-plugins:escape-support defaultEscape="html">
                    <vm-plugins:noescape>
                        <vm-plugins:if-matches pattern="^control\." />
                        <vm-plugins:if-matches pattern="^screen_placeholder" />
                        <vm-plugins:if-matches pattern="^stringEscapeUtil\.escape" />
                        <vm-plugins:if-matches pattern="^csrfToken\.(get)?(\w*)hiddenField" />
                        <vm-plugins:if-matches pattern="^tree" />
                    </vm-plugins:noescape>
                </vm-plugins:escape-support>
            </plugins>

加了这段配置,velocity进行模板渲染时会把所有的变量中内容进行html转义, noescape定义了不需要进行html转义的变量名表达式, 例如:<vm-plugins:if-matches pattern="^tree" />表明$tree这个变量不需要进行html转义
我们要求所有使用webx3框架的应用,都需要加入这段配置,在vm模板中输出js字符串,都需要显示的调用$stringEscapeUtil.escapeJavaScript($someString)

另外在pipeline.xml中替换webx框架的RenderResultAsJsonValve,如下配置:

<when>
                    <!-- 创建JSON,无模板,无layout。 -->
                    <pl-conditions:target-extension-condition extension="json" />
                    <performAction />
                    <performScreen />
                    <valve class="com.aliyun.console.common.web.valve.AliyunRenderResultAsJsonValve" />
                </when>

用以json请求或其他ajax请求输出时的js标签安全转义

CSRF 防范

集团防御CSRF方案是采用随机字符串CSRF_TOKEN, 使用的准则是:所有涉及到数据增删改的操作必须只允许使用POST方式提交,并且在提交的数据中要包括CSRF_TOKEN, 服务端收到请求后对CSRF_TOKEN进行校验,决定是否接受请求.

TODO WEBX3默认方案?

Access Control

业务逻辑中权限控制, 对数据库任何操作都需要做身份认证,特别是UPDATE、 DELETE、INSERT的时候更需要注意.
actioin里取得当前登录用户的session信息, 从session中取得当前用户loginId,根据loginId及被操作数据的ower对比结果,进行数据更新,删除.
另外也可以在sql里增加判断条件来控制,如在where条件中增加login_id=‘xxx‘

File upload

当应用允许用户上传文件时, 应用必须在服务端对文件类型进行检查, 在安全部门规定的白名单类型下, 才允许上传. 文件上传存放目录必须是不具有执行环境的独立存储,不能将文件放在应用目录下。需要保存到专门的文件存储服务器上, 如盘古.
应用必须明确允许上传的文件类型,程序必须要根据白名单在服务器端进行检测。其中严禁上传的文件类型有:exe,txt,html,php
对于上传的图片, 我们需对其进行重格式化, 可以去掉多余的meta信息
对于上传的其他文件, 进行病毒扫描.
另外我们必须对上传的文件大小进行限制, webx3的upload service配置如下:<services:upload sizeMax="5M" />

URL redirect

Web应用程序接收到用户提交的URL参数后,没有对参数做"可信任URL"的验证,就向用户浏览器返回跳转到该URL的指令。
如果alibaba.com下的某个web应用程序存在这个漏洞,恶意攻击者可以发送给用户一个alibaba.com的链接,但是用户打开后,却来到钓鱼网站页面,将会导致用户被钓鱼攻击,账号被盗,或账号相关财产被盗.

故我们只信任集团相关公司的url, 可以使用fasttexst提供的工具类进行检查, 如:
Boolean inWhiteList =  CheckSafeUrl.getDefaultInstance().inWhiteList(URL);
检查在白名单内的,我们执行跳转, 否则定向到错误页面

Cookie

防止cookie中用户的敏感信息泄漏, 我们需要对cookie进行高强度的加密, 同时将设置httpOnly的属性.
webx3中sessionStore的配置如下:

<session-stores:single-valued-cookie-store id="xxxCookieStore" >
    <session-stores:cookie name="xxx" httpOnly="true" />
    <session-stores:encoders>
        <session-value-encoders:simple-value-encoder charset="UTF-8"/>
    </session-stores:encoders>
</session-stores:single-valued-cookie-store>

这里配置的encoders不能满足我们的安全要求,我们可以实现一个高强度的加解密类,替换之.