sql-injection
SQL - 注入
Section titled “SQL - 注入”SQL 注入是一种代码注入技术,用于攻击数据驱动的应用程序。当恶意 SQL 语句被插入到输入字段中以执行时(例如,将数据库内容转储给攻击者),就会发生 SQL 注入。它是最常见和最危险的 Web 应用程序漏洞之一。
SQL 注入是如何发生的?
Section titled “SQL 注入是如何发生的?”当应用程序将用户提供的数据直接嵌入到 SQL 查询字符串中而没有进行适当的净化时,就会发生 SQL 注入。这使得攻击者可以跳出数据上下文,注入自己的 SQL 命令。
一个经典示例
Section titled “一个经典示例”想象一个登录表单,应用程序像这样构建查询(伪代码示例):
username = get_user_input('username')password = get_user_input('password')
query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "';"
execute_sql(query)正常用户将输入 alice 作为用户名。查询变为:
SELECT * FROM users WHERE username = 'alice' AND password = 'some_password';然而,攻击者可以在用户名字段中输入以下内容:
' OR '1'='1应用程序将构造此恶意查询:
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '...';由于 '1'='1' 始终为真,WHERE 子句对每个用户都评估为真,攻击者可能无需密码即可登录为数据库中的第一个用户(通常是管理员)。
一个更具破坏性的示例
Section titled “一个更具破坏性的示例”攻击者可以在用户名字段中输入此内容:
'; DROP TABLE users; --生成的 SQL 将是:
SELECT * FROM users WHERE username = ''; DROP TABLE users; --' AND ...;如果数据库允许执行多条语句,它将执行 SELECT,然后继续 删除整个 users 表。-- 开始一个注释,导致原始查询的其余部分被忽略。
通用解决方案:预处理语句
Section titled “通用解决方案:预处理语句”防止 SQL 注入最有效的方法是 绝不 将用户输入直接连接到 SQL 字符串中。相反,请使用 预处理语句(也称为参数化查询)。
预处理语句分两个阶段工作:
- 1. 准备: 应用程序将 SQL 查询结构发送到数据库,其中包含用户提供值的占位符(
?、$1等)。数据库解析并编译此查询结构,不包含数据。 - 2. 执行: 应用程序随后单独发送用户提供的数据。数据库引擎将此数据插入到预编译的查询中,将其严格视为数据,而不是可执行代码。
预处理语句示例(Python 和 psycopg2)
Section titled “预处理语句示例(Python 和 psycopg2)”import psycopg2
# 用户输入user_name_input = "' OR '1'='1'" # 恶意输入
# 数据库连接conn = psycopg2.connect(...)cursor = conn.cursor()
# 1. 使用占位符准备语句(psycopg2 使用 %s)sql = "SELECT * FROM users WHERE username = %s;"
# 2. 执行,将用户数据作为单独的参数传递# 数据库驱动程序负责处理净化。cursor.execute(sql, (user_name_input,))
# 数据库将恶意字符串视为要搜索的字面字符串,而不是要执行的代码。# 查询未能找到用户,这是预期的结果。
results = cursor.fetchall()- 始终 使用带参数化查询的预处理语句。
- 绝不 信任用户输入。将所有外部数据视为潜在的恶意数据。
- 不要 尝试编写自己的净化或转义函数。这极其难以正确实现。请依赖数据库驱动程序提供的久经考验的函数。