SQL注入(SQL Injection)是…

1. 原理

1.1 正常的输入

考虑一个简单常用的SQL查询场景:用户输入用户名,后台程序生成SQL查询语句,如下图1

Fig.1 Generate SQL query from user input username
Fig.1 Generate SQL query from user input username

图1中,用户输入Smith,后台生成SQL,返回用户Smithusers表中相关的信息:

SELECT * FROM users WHERE name = ‘Smith’;

注意输入用户名的时候,是不需要输入单引号的。单引号是后台程序生成的SQL语句中自动添加的。一个简单的后台程序相应伪代码可以是:

“SELECT * FROM users WHERE name = ‘” + string(输入的用户名) + “’;”

可以看出,最终生成的SQL语句由三部分拼接而成:

  1. "SELECT * FROM users WHERE name = '"
  2. 输入用户名
  3. "';"

最后生成完整的字符串SQL语句:SELECT * FROM users WHERE name = 'Smith';

1.2 特殊的输入

Smith正常的用户名,但有没有一些特殊的输入呢?例如输入:Smith' or '1' = '1,生成的SQL语句就变为如图2:

Fig.2 SQL injection example
Fig.2 SQL injection example

注意'1' = '1'总是为True,那最终SQL语句执行时就被解释为: SELECT * FROM users WHERE name = 'Smith' or True

也就是条件name = ‘Smith’被绕过(bypass)了,WHERE条件语句总是为True,SQL解释器无条件的执行SELECT * FROM users

这是SQ注入的一个经典例子,说穿了其实并不复杂,就好像魔术被揭秘后产生的不过如此的感觉。

2. 更多的例子

考虑一个类似的例子1

“select * from user_data where FIRST_NAME = ‘John’ and LAST_NAME = ‘” + lastName + “’”;

同样由三部分拼接完成:

  1. "select * from user_data where FIRST_NAME = 'John' and LAST_NAME = '"
  2. 用户输入last name
  3. "'";

同样是利用输入last name实现SQL注入。

2.1 注入失败一

考虑输入last name: 'Smith or 1 = 1

那么完整的SQL语句为:

SELECT * FROM user_data WHERE first_name = 'John' and last_name = ''Smith or 1 = 1'

不合法语句,原因是Smith被当作一个关键词而不是字符串,如下图:

Fig.3 illegal SQL injection example 1
Fig.3 illegal SQL injection example 1

2.2 注入失败二

再考虑输入:' or 1 = 1

完整的SQL语句:

SELECT * FROM user_data WHERE first_name = 'John' and last_name = '' or 1 = 1'

同样不合法语句,因为最后一个单引号没有配对,这也是为什么注入要使用'1'='1',而不是直接1=1的原因,见下图:

Fig.4 illegal SQL injection example 2
Fig.4 illegal SQL injection example 2

2.3 注入成功一

考虑输入:' or '1' = '1

完整的SQL语句:

SELECT * FROM user_data WHERE first_name = 'John' and last_name = '' or '1' = '1'

注入成功,如下图:

Fig.5 successful SQL injection
Fig.5 successful SQL injection

2.4 注入失败例子?

再考虑输入:' and not '1' = '2

完整的SQL语句:

SELECT * FROM user_data WHERE first_name = 'John' and last_name = '' and not '1' = '2'

我理解这个语句和2.3是类似的,区别在于改成not '1' = '2'‘1’ = ‘2’是False,那not False就是True,应该能够注入成功的,不知道为什么失败了?如下图:

Fig.6 unsuccessful SQL injection, but why?
Fig.6 unsuccessful SQL injection, but why?

3. 一点简短的历史

据说最早的SQL注入的记录来自于98年Phrack杂志的一期文章:NT Web Technology Vulnerabilities2,作者署名为rfp(rain.forest.puppy)。虽说谜底被揭穿了也就恍然大悟,但是能第一个想到这个点子的人无疑称得上是genius。

  1. webgoat 8.0 SQL injection lessons  2

  2. NT Web Technology Vulnerabilities