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';
      
相关推荐
小扳17 分钟前
微服务篇-深入了解 XXL-JOB 分布式任务调度的具体使用(XXL-JOB 的工作流程、框架搭建)
数据库·分布式·spring·spring cloud·微服务·架构
drebander24 分钟前
SQL 实战:正则表达式匹配 – 高效数据筛选与文本解析
数据库·sql·正则表达式
唐可盐25 分钟前
图文教程:使用PowerDesigner导出数据库表结构为Word/Html文档
数据库
web1376560764329 分钟前
【MySQL】深度学习数据库开发技术:使用CC++语言访问数据库
数据库·mysql·数据库开发
lucky_syq31 分钟前
MySQL和HBase的对比
数据库·mysql·hbase
丁总学Java1 小时前
要查询 `user` 表中 `we_chat_subscribe` 和 `we_chat_union_id` 列不为空的用户数量
数据库·mysql·微信小程序
张声录11 小时前
【ETCD】【实操篇(十七)】 etcd 集群定期维护指南
数据库·etcd
岚精灵玩电脑1 小时前
Spring自动化创建脚本-解放繁琐的初始化配置!!!(自动化SSM整合)
数据库·spring·自动化
追风赶月、2 小时前
【MySQL】数据类型
数据库·mysql
whisperrr.2 小时前
探索JDBC:Java数据库连接的艺术与魅力
java·开发语言·数据库