• Web安全之防止SQL注入


    所谓SQL注入式攻击,就是输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击。

    导致原因及可能后果

    通过将带有恶意目的的SQL语句或参数写入表单中进行提交,程序未经过校验直接执行SQL语句,导致一些敏感数据泄露包括一些用户名密码信息等,以及可能会对数据库信息进行增删改操作,篡改数据等严重后果。

    一些例子

    直接动态拼接SQL语句

    反例:

    String username = request.getParameter("username");
    String password = request.getParameter("password");
    String encryptedPass = PasswordUtil.encrypt(password);
    String sql = "select * from users where username = '" + username + "' and password = '" + encryptedPass + "'";
    Statement s = c.createStatement();
    ResultSet rs = s.executeQuery(sql);
    

    正例:

    String username = request.getParameter("username");
    String password = request.getParameter("password");
    String encryptedPass = PasswordUtil.encrypt(password);
    String sql = "select * from users where "
    			+ "username = ? and password = ?";
    PreparedStatement s = c.prepareStatement(sql);
    s.setString(1, username);
    s.setString(2, encryptedPass);
    ResultSet rs = s.executeQuery();
    

    如果用户登录时候在username和passwor分别填入

    username = "‘1' or '1'='1‘";
    password = "’1' or '1'='1’";
    

    最终SQL语句就会变成

    String sql = "select * from users where "
    	+ "username = '1' or '1'='1' and password = '1' or '1'='1'";
    

    由于where条件永为真,那么最后相当于执行

    String sql = "select * from users"
    

    直接曝露所有用户信息。更有甚者,可将语句变为

    String sql = "select * from users;drop table users;"
    

    将用户数据全部删除。

    因此,需要使用PreparedStatement对象而不是用Statement对象来预编译SQL语句。主要有三点优势:

    1. PreparedStatement可以写动态参数化的查询
    2. PreparedStatement比 Statement 更快
    3. PreparedStatement可以防止SQL注入式攻击

    使用mybatis框架动态参数使用'$'而不是'#'

    反例:

    <dynamic prepend="where">
    <isParameterPresent>
    	<isNotEmpty prepend="and" property="onShelves">
    		p.onshelves=$onShelves$
    	</isNotEmpty>
    </isParameterPresent>
    </dynamic>
    

    正例:

    <dynamic prepend="where">
    <isParameterPresent>
    	<isNotEmpty prepend="and" property="onShelves">
    		p.onshelves=#onShelves#
    	</isNotEmpty>
    </isParameterPresent>
    </dynamic>
    

    '#'解析为一个 JDBC 预编译语句(prepared statement)的参数标记符。而'$'仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。
    注意点:

    1. 能使用 #{}的地方就用 #{}
    2. 表名作为变量时,必须使用 ${}

    如何防止

    1. 永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和双"-"进行转换等。
    2. 永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。
    3. 可通过一些检查方法来进行安全测验。sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。

    参考资料

    1. 利用SQL注入漏洞登录后台
    2. JDBC为什么要使用PreparedStatement
    3. mybatis之#和$区别
  • 相关阅读:
    java8新特性之Lambda表达式入门
    小结
    Kafka入门
    关于java多线程初试
    关于Netty入门
    IOS UITableView代码添加数据源和指定委托
    C#读书笔记1
    vs2008 C# Windows Mobile 智能设备开发 初步1
    Microsoft ActiveSync简介(来自网络)
    winForm单击用户区可移动窗体,代码控制窗体最大适中
  • 原文地址:https://www.cnblogs.com/universal/p/10477393.html
Copyright © 2020-2023  润新知