sql注入原理及实验

本文通过一个实战案例,详细解析了SQL注入攻击的工作原理及其防御措施。介绍了如何利用构造特殊的输入来操控SQL查询语句,以及如何实施有效的防护策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原理

可以将Web程序想象成一个图书馆管理员,它机械的听从用户告诉它的信息,在书库(sql程序)中查询(Select)信息
当你告诉它”三国演义”时,它会查找并告诉你书库中《三国演义》的信息
  这里的组合方式就是 书库中《[用户输入]》的信息
但是如果你告诉它”三国演义》或《所有书籍”,它机械地听从指令会查询并告诉你
  书库中《三国演义》或《所有书籍》的信息

究其原理,便是用户输入的”数据”被恶意构造成”操作”
上例的书名号就是用来区分书名(名词)和句子其他成分的,在程序中则是使用双引号来区分字符串和语句其他功能指令的

利用

这里拿一个WarGame作为例子:
http://natas14.natas.labs.overthewire.org/
username=natas14
password=Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
可以自己先试试~会了的话就不用看了0v0节省下好久时间呢!

打开以后发现是username和password的输入框,提供了服务器端的PHP源代码

<? 
if(array_key_exists("username", $_REQUEST)) { //检查$_REQUEST中是否存在key=username
    $link = mysql_connect('localhost', 'natas14', '<censored>'); //连接mysql
    mysql_select_db('natas14', $link); //选择数据库

    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\""; //组成SQL语句字符串
    if(array_key_exists("debug", $_GET)) { //如果$_GET中存在key=debug
        echo "Executing query: $query<br>"; //将$query显示出来
    } 

    if(mysql_num_rows(mysql_query($query, $link)) > 0) { //如果返回一条以上的数据
            echo "Successful login! The password for natas15 is <censored><br>"; 
    } else { 
            echo "Access denied!<br>"; 
    } 
    mysql_close($link); //关闭mysql连接
?> 

连接结构为:
  浏览器<————->PHP<————->mysql
  |客户端|    |---服务器---|

$query就是关键的sql语句
在php中它是一个作为连接函数的字符串参数,而输入mysql以后将成为一个sql命令
因此首先需要分析明确它的结构,这样才能方便我们之后的操作
假设令$_REQUEST={‘username’: ‘aaa’, ‘password’: ‘bbb’}时,$query和实际Sql语句分别是什么呢?
(建议看答案之前先自己尝试一下,提示:\是转义,’.’是PHP中的字符串连接符)
这里写图片描述

清楚了SQL语句的组成,我们就可以尝试发现PHP的漏洞了
很明显,双引号用来包裹两个变量,使其作为字符串类型的变量送入mysql
而知道了这一点,恶意令输入中带有双引号就会使得$query被送入mysql以后产生歧义:
试试令password= b” and True,会构造出怎样的SQL语句呢?
SELECT * from users where username = "aaa" and password="b" and True "
很明显,这是一句错误的SQL语句,因为双引号是单数个,就意味着肯定有字符串未闭合

说到这里,就要解释一下where子句的作用了:
Select语句在mysql数据库是查询检索的作用,where子句则是过滤条件
可以理解为

遍历所有数据项
 if(数据项满足条件)Then 
      echo 数据项;

我们不知道username和password,所以没法让username=xxx and password=xxx成立
但是如果满足的条件恒真,那么mysql就会显示所有数据了
即令SQL语句为
SELECT * from users where True;

由于and和or优先级相同,因此它们依次从左向右运算
现有的语句为
SELECT * from users where False [] and False []
[]是我们可以注入的地方
那么很明显,or这个只要一侧为真,就令整个表达式为真的操作符就派上用场了
构造SELECT * from users where False and False or True就可以使运算后where恒真了

观察到$query后恒有一个双引号,因此不能简单地输入True,而是要构造能够合理包含尾双引号的语句,例如令password=b” or “1” = “1

生成的SQL语句就是:
SELECT * from users where username=”a” and password=”b” or “1”=”1”
很明显,where子句恒真,将会返回数据库内所有信息

防御

从SQL注入被发现到现在已有十几年的历史,在这个过程中黑客和开发者进行了大量的博弈
从最简单粗暴的检测用户输入中是否存在引号等非法字符,到从SQL解决问题的参数化查询
黑客同时也引入了构造绕过过滤的宽字节注入法等等

虽然参数化查询其实可以根本性地解决SQL注入的问题,不过由于开发者的水平问题,漏洞仍然层出不穷~
希望大家以后开发网页的时候要注意哦0 -

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值