设为首页收藏本站

IT技术擎 - 最棒的IT web技术交流社区

 找回密码
 注册为IT技术擎人

QQ登录

只需一步,快速开始

搜索
热搜: php h5 jquery
查看: 15|回复: 0

[其他] SQL注入与防范

[复制链接]

9948

主题

9948

帖子

3万

积分

版主

Rank: 7Rank: 7Rank: 7

积分
30418
发表于 2018-3-14 02:09:10 | 显示全部楼层 |阅读模式
首先给大家看个例子:
1)小编首先在数据库中建立了一张测试表logintable,表内有一条测试信息:

然后写了个测试程序:
  1. packagecom.java.SqlInject;
  2. importjava.sql.Connection;
  3. importjava.sql.DriverManager;
  4. importjava.sql.PreparedStatement;
  5. importjava.sql.ResultSet;
  6. importjava.sql.SQLException;
  7. importjava.sql.Statement;
  8. publicclassSqlInject {
  9. privatestaticString Driver="com.mysql.jdbc.Driver"; //数据库驱动 //连接数据库的URL地址 privatestaticString url="jdbc:mysql://localhost:3306/hellojdbc?useUnicode=true &characterEncoding=UTF-8";privatestaticString username="root";//数据库连接用户名 privatestaticString password="123456";//数据库连接密码 privatestaticConnection conn=null;//数据库连接对象 privatestaticStatement stat=null;//语句陈述对象 privatestaticResultSet rs=null;//结果数据集 privatestaticPreparedStatement pst=null;//预编译语句 //使用静态块的方式加载驱动 static{try{//调用Class对象的静态forName()方法加载数据库驱动类 Class.forName(Driver); }catch(ClassNotFoundException e) { e.printStackTrace(); } }//使用单例模式返回数据库连接对象 publicstaticConnection getConnection() throwsSQLException{if(conn==null){ conn=DriverManager.getConnection(url, username, password);returnconn; }returnconn;
  10. }publicstaticvoidlogin(String name,String password){try{ conn=getConnection(); stat=conn.createStatement();//使用动态拼接的方式拼接sql语句 rs=stat.executeQuery("select * from logintable where name='"+name+"' and password='"+password+"'");if(rs.next()){ System.out.println("用户已注册"); }
  11. else System.out.println("无记录"); }catch(SQLException e) { e.printStackTrace(); } }publicstaticvoidmain(String[] args) { login("zhangsan","123456");
  12. }
  13. }
复制代码
输出结果为:

2)然后我们修改main()方法中,login()方法调用时的参数,改为:
  1. publicstaticvoidmain(String[] args) { login("zhangsan","123");
  2. }
复制代码
执行结果:

3)似乎一切都天经地义,没什么问题。但是这时我们再对login()方法调用的参数做一下修改:
  1. publicstaticvoidmain(String[] args) {//注意:第一个参数两个短杠后面有空格 login("zhangsan';-- ","123");
  2. }
复制代码
测试执行结果又变成了:

明明用户名和密码都不对,数据库中也没有这条记录,为什么会出现这种情况?
这就是SQL注入带来的漏洞问题。
恶意用户通过伪装请求,来骗过我们的业务程序,达到获取数据库核心数据的目的。
通过上面的例子,我们可以看到我们最后一次改写参数来调用login()方法的时候,java业务程序中接收到的不是我们期望的那个sql语句。
由于分号的存在,使得我们的sql语句拼接后完变成了这样:
  1. select*fromlogintable wherename='zhangsan';
  2. --'password='123';
复制代码
这样就由一条sql语句变成了两条sql语句。在第一条的sql语句中去掉了密码的检索条件,同时注释掉了第二条sql语句。
(两个横线为注释符)
总结一下:SQL注入就是用户在输入表单或者URL参数中输入SQL命令,到达欺骗应用程序的目的,破坏原有SQL的语义,发送恶意的SQL到后端数据库,导致数据库信息出现泄露的漏洞。发生这种漏洞的原因是:
我们的sql语句是通过动态拼接组成的,在拼接完成之前,sql语句是不完整的,所以当在拼接时新加入的参数中有sql命令的注入就有可能改变原有的sql语义。
比方像上面的例子中,密码被恶意地屏蔽注释掉了。
解决方法:
传入外部参数时,不使用动态拼接的方式拼接sql语句;使用参数化方式的sql实现方式(格式化,占位符),即使用预编译的statement。

然后传参:

所以上面例子中相关代码应修改为:
  1. conn=getConnection();//stat=conn.createStatement();//使用组合的方式拼接sql语句 //rs=stat.executeQuery("select * from logintable where name='"+name+"' and password='"+password+"'"); pst=conn.prepareStatement("select * from logintable where name= ? and password= ?"); pst.setString(1, name); pst.setString(2, password); rs=pst.executeQuery();if(rs.next()){ System.out.println("用户已注册"); }
  2. else System.out.println("无记录");
复制代码
其他注意事项:
使用严格的数据库管理权限:1.仅给予Web应用访问数据库的最小权限;
2.避免Drop table等权限。
封装数据库错误:1.禁止直接将后端数据库异常信息暴露给用户;
2.对后端异常信息进行必要的封装,避免用户直接查看到后端异常。
机密信息禁止明文存储:
1.涉密信息需要加密处理;
2.使用AES_ENCRYPT/AES_DECRYPT加密和解密。
该用户未在地球留下任何的痕迹

本版积分规则

QQ|小黑屋|帮助|IT技术擎 ( 沪ICP备15054863号  

GMT+8, 2018-6-24 07:08

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表