🚀 大家好,我是小康。

今天给大家分享一个 网络安全面试题 :什么是 SQL 注入?如何避免?

小技巧:在面试中,可以参考下面的示例回答,这样回答简洁明了。详细介绍部分则是为了帮助大家系统学习,以便应对面试官深入提问。

示例回答

SQL注入是一种通过在输入字段中插入恶意SQL代码来攻击数据库的方式。为了避免SQL注入,我们可以使用预处理语句和参数化查询,验证和转义输入数据,以及使用ORM框架。


详细解释

什么是 SQL 注入?

SQL注入是一种常见的网络攻击方式,攻击者通过在输入字段(如登录表单或搜索框)中插入恶意的SQL代码,操控数据库执行未经授权的操作。这种攻击可能导致敏感数据泄露、数据篡改、甚至删除数据库。

SQL 注入的工作原理

  1. 输入恶意代码
  • 攻击者在输入字段(如登录表单、搜索框)中输入SQL代码,这些代码与正常的输入混合在一起。
  1. 解析和执行
  • 如果应用程序直接将这些输入嵌入到SQL查询中,数据库会解析并执行这些混合的SQL代码。
  1. 未授权操作
  • 通过这种方式,攻击者可以绕过认证、读取或修改数据,甚至删除数据库。

示例说明

假设一个登录表单中的SQL查询如下:

1
SELECT * FROM users WHERE username = 'admin' AND password = 'password';

攻击者输入以下内容作为用户名:

1
admin' OR '1'='1

生成的SQL查询变为:

1
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = 'password';

因为'1'='1'永远为真,攻击者可以绕过密码验证,登录为任意用户。

如何避免 SQL 注入?

1. 使用预处理语句和参数化查询

  • 预处理语句将SQL查询和输入数据分离,防止恶意代码被解释执行。

示例
使用 Python 的 sqlite3 库进行参数化查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import sqlite3

# 连接到数据库
connection = sqlite3.connect('example.db')
cursor = connection.cursor()

# 定义用户输入
username = 'user'
password = 'pass'

# 使用预处理语句执行查询
cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))

# 获取查询结果
result = cursor.fetchall()
print(result)

在这个例子中,? 占位符用于替代用户输入的数据,这些数据会被安全地绑定到查询中,从而防止恶意 SQL 代码被执行。

2. 使用 ORM 框架

使用 ORM(对象关系映射)框架自动处理SQL生成和执行,降低直接操作SQL的风险。
示例
使用 Django 的 ORM 进行数据库操作:

1
2
3
4
5
6
7
8
9
from django.contrib.auth.models import User

# 假设 username 和 password 是用户输入
username = 'user'
password = 'pass'

# 使用 Django ORM 进行查询
user = User.objects.get(username=username, password=password)
print(user)

ORM 框架会自动生成安全的 SQL 查询,防止开发者编写不安全的 SQL 语句,从而减少 SQL 注入的风险。

3. 最小化数据库权限

仅授予应用程序必要的数据库权限,避免攻击者通过 SQL 注入执行高权限操作。
示例
在数据库中创建一个具有最低权限的用户,用于应用程序连接:

1
2
3
4
5
6
7
8
-- 创建一个新用户
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'password';

-- 仅授予 SELECT 和 INSERT 权限
GRANT SELECT, INSERT ON database_name.* TO 'appuser'@'localhost';

-- 应用更改
FLUSH PRIVILEGES;

这样,即使攻击者通过 SQL 注入获得了数据库访问权限,他们也只能执行有限的操作,而不能进行破坏性的更改。

4. 输入验证和转义

通过正则表达式验证用户名只包含字母、数字和下划线,确保输入符合预期格式。使用预处理语句防止恶意代码注入。
示例
使用正则表达式验证用户输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import re
import sqlite3

# 用户输入
username = 'user'
password = 'pass'

# 输入验证
if not re.match("^[a-zA-Z0-9_]+$", username):
raise ValueError("Invalid username")

# 连接到数据库
connection = sqlite3.connect('example.db')
cursor = connection.cursor()

# 使用预处理语句执行查询
cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))

# 获取查询结果
result = cursor.fetchall()
print(result)

虽然输入验证和转义可以大大减少SQL注入的风险,但最好的方法是结合预处理语句使用,以提供更全面的防护。

总结

SQL注入是一种通过在输入字段中插入恶意SQL代码来攻击数据库的方式。为了防止SQL注入,可以使用预处理语句和参数化查询来分离SQL查询和输入数据,使用ORM框架来自动处理SQL生成和执行,最小化数据库权限来限制攻击者的操作范围,并对输入数据进行严格验证和转义。结合这些方法,可以有效保护数据库的安全。

最后:

欢迎大家关注我的微信公众号「跟着小康学编程」!本号致力于分享C/C++/Go/Java 语言学习、计算机基础原理、Linux 编程、数据库、微服务、容器技术 等内容。文章力求通俗易懂,并配有代码示例,方便初学者理解。如果您对这些内容感兴趣,欢迎关注我的公众号「跟着小康学编程」。

后续,我还会陆续分享各个方向的编程面试题,包括C/C++、Java、Go,以及操作系统、计算机网络、数据结构、数据库和微服务等领域,为大家的面试提供帮助。

此外,小康最近创建了一个技术交流群,专门用来讨论技术问题和解答读者的疑问。在阅读文章时,如果有不理解的知识点,欢迎大家加入交流群提问。我会尽力为大家解答。期待与大家共同进步!