SQL注入攻击和防御

声明:本文仅限于技术讨论与分享,严禁用于非法途径。若读者因此作出任何危害网络安全行为后果自负,与本号及原作者无关。

# 概述

SQL注入是一种网络安全攻击,它利用了Web应用程序对用户输入的验证不足,从而在后台数据库中执行恶意的SQL语句,获取或修改数据,甚至控制数据库服务器。

# SQL注入产生的原因

Web应用程序使用了动态SQL语句,即根据用户输入的内容拼接SQL语句,而没有对用户输入的内容进行合法性检查或过滤。

例如,以下是一个PHP代码片段,用于根据用户输入的用户名和密码进行登录验证:

复制代码
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = mysqli_query($conn, $sql);

这段代码直接使用了用户输入的用户名和密码,拼接成了一个SQL查询语句,然后执行该语句。如果用户输入的用户名和密码都是合法的,例如username = 'admin'password = '123456',那么SQL语句就是:

复制代码
SELECT * FROM users WHERE username = 'admin' AND password = '123456'

这个语句的作用是从users表中查询用户名和密码都匹配的记录,如果存在,就表示登录成功,否则,就表示登录失败。

但是,如果用户输入的用户名或密码包含了一些特殊的字符或命令,例如username = 'admin'password = '123456' OR 1 = 1,那么SQL语句就变成了:

复制代码
SELECT * FROM users WHERE username = 'admin' AND password = '123456' OR 1 = 1

这个语句的作用是从users表中查询用户名和密码都匹配,或者1等于1的记录,由于1等于1永远为真,所以这个语句会返回users表中的所有记录,相当于绕过了密码验证,实现了SQL注入攻击。(万能密码就是这个原理)

例2,假设你想在某个网站上购买一本书,你需要输入你的姓名、地址、信用卡号等信息,然后点击提交按钮,完成订单。这个网站的后台程序可能会使用类似于以下的SQL语句,将你的信息插入到数据库中:

复制代码
INSERT INTO orders (name, address, credit_card) VALUES ('$name', '$address', '$credit_card')

其中,$name$address$credit_card是你输入的内容,用单引号包围。如果你输入的内容都是合法的,例如name = '张三'address = '重庆市南岸区YJ'credit_card = '1234-5678-9012-3456',那么SQL语句就是:

复制代码
INSERT INTO orders (name, address, credit_card) VALUES ('张三', '重庆市南岸区YJ', '1234-5678-9012-3456')

这个语句的作用是将你的信息插入到orders表中,没有任何问题。

但是,如果你输入的内容包含了一些特殊的字符或命令,例如name = '张三'address = '重庆市南岸区YJ'credit_card = '1234-5678-9012-3456'; DROP TABLE orders; --',那么SQL语句就变成了:

复制代码
INSERT INTO orders (name, address, credit_card) VALUES ('张三', '重庆市南岸区YJ', '1234-5678-9012-3456'; DROP TABLE orders; --')

这个语句的作用是先将你的信息插入到orders表中,然后执行一个分号后面的命令,即删除orders表,最后执行一个双破折号后面的注释,即忽略后面的内容。这样,你就利用了SQL注入攻击,删除了网站的订单数据,造成了严重的损失。

# SQL注入防御
  • 使用参数化查询或预编译语句

    即将用户输入的内容作为参数传递给SQL语句,而不是直接拼接。参数化查询或预编译语句可以有效地防止SQL注入攻击,因为它们会将用户输入的内容作为字面值,而不是可执行的代码。

    例如,以下是一个使用参数化查询的PHP代码片段,用于根据用户输入的用户名和密码进行登录验证:

    复制代码
    $username = $_POST['username'];
    $password = $_POST['password'];
    $sql = "SELECT * FROM users WHERE username = ? AND password = ?";
    $stmt = mysqli_prepare($conn, $sql);
    mysqli_stmt_bind_param($stmt, "ss", $username, $password);
    mysqli_stmt_execute($stmt);
    $result = mysqli_stmt_get_result($stmt);

    这段代码使用了mysqli_prepare函数来预编译SQL语句,使用了?占位符来表示参数,使用了mysqli_stmt_bind_param函数来绑定参数的值和类型,使用了mysqli_stmt_execute函数来执行SQL语句。这样,即使用户输入的用户名或密码包含了特殊的字符或命令,也不会影响SQL语句的结构和语义,而只会作为普通的字符串进行比较,从而避免了SQL注入攻击。

    • 使用最小权限原则

      如果给数据库用户分配了过多的权限,导致攻击者可以利用SQL注入攻击执行一些危险的操作,例如删除表、修改数据、执行系统命令等。例如,如果Web应用程序使用的数据库用户拥有db_owner角色,那么攻击者就可以利用SQL注入攻击执行以下语句,删除users表:

      复制代码
      DROP TABLE users

      或者执行以下语句,调用xp_cmdshell扩展存储过程,执行系统命令,例如打开计算器:

      复制代码
      EXEC xp_cmdshell 'calc.exe'

      因此,为了防止SQL注入攻击,Web应用程序应该使用最小权限原则,即只给数据库用户分配必要的权限,例如只允许执行查询和更新操作,而不允许执行删除和执行操作。

      你可以使用MySQL的GRANT命令,指定用户的用户名、主机名、数据库名、表名和权限。例如,假设你的webapp用户的用户名是webapp,主机名是localhost,数据库名是mydb,表名是mytable,你可以使用以下命令:

      复制代码
      GRANT SELECT, UPDATE ON mydb.mytable TO 'webapp'@'localhost';

      这个命令的作用是给webapp用户授予在mydb数据库的mytable表上执行SELECT和UPDATE操作的权限。如果你想要授予webapp用户在mydb数据库的所有表上执行查询和更新操作的权限,你可以使用以下命令:

      复制代码
      GRANT SELECT, UPDATE ON mydb.* TO 'webapp'@'localhost';
相关推荐
张璐月2 小时前
mysql join语句、全表扫描 执行优化与访问冷数据对内存命中率的影响
数据库·mysql
全干engineer4 小时前
ClickHouse 入门详解:它到底是什么、优缺点、和主流数据库对比、适合哪些场景?
数据库·clickhouse
Hellyc6 小时前
基于模板设计模式开发优惠券推送功能以及对过期优惠卷进行定时清理
java·数据库·设计模式·rocketmq
lifallen6 小时前
Paimon LSM Tree Compaction 策略
java·大数据·数据结构·数据库·算法·lsm-tree
{⌐■_■}10 小时前
【Kafka】登录日志处理的三次阶梯式优化实践:从同步写入到Kafka多分区批处理
数据库·分布式·mysql·kafka·go
isNotNullX10 小时前
数据中台架构解析:湖仓一体的实战设计
java·大数据·数据库·架构·spark
睿思达DBA_WGX13 小时前
由 DB_FILES 参数导致的 dg 服务器无法同步问题
运维·数据库·oracle
袋鼠云数栈14 小时前
使用自然语言体验对话式MySQL数据库运维
大数据·运维·数据库·后端·mysql·ai·数据治理·数栈·data+ai
渣渣盟14 小时前
掌握MySQL函数:高效数据处理指南
sql·mysql·adb·dba