1.1 数据持久化

1.1.1【必须】SQL语句默认使用预编译并绑定变量

Web后台系统应默认使用预编译绑定变量的形式创建sql语句,保持查询语句和数据相分离。以从本质上避免SQL注入风险。

如使用Mybatis作为持久层框架,应通过#{}语法进行参数绑定,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数。

示例:JDBC

  1. String custname = request.getParameter("name");
  2. String query = "SELECT * FROM user_data WHERE user_name = ? ";
  3. PreparedStatement pstmt = connection.prepareStatement( query );
  4. pstmt.setString( 1, custname);
  5. ResultSet results = pstmt.executeQuery( );

Mybatis

  1. <select id="queryRuleIdByApplicationId" parameterType="java.lang.String" resultType="java.lang.String">
  2. select rule_id from scan_rule_sqlmap_tab where application_id=#{applicationId}
  3. </select>

应避免外部输入未经过滤直接拼接到SQL语句中,或者通过Mybatis中的${}传入SQL语句(即使使用PreparedStatement,SQL语句直接拼接外部输入也同样有风险。例如Mybatis中部分参数通过${}传入SQL语句后实际执行时调用的是PreparedStatement.execute(),同样存在注入风险)。

1.1.2【必须】白名单过滤

对于表名、列名等无法进行预编译的场景,比如外部数据拼接到order by, group by语句中,需通过白名单的形式对数据进行校验,例如判断传入列名是否存在、升降序仅允许输入“ASC”和“DESC”、表明列名仅允许输入字符、数字、下划线等。参考示例:

  1. public String someMethod(boolean sortOrder) {
  2. String SQLquery = "some SQL ... order by Salary " + (sortOrder ? "ASC" : "DESC");`
  3. ...