PHP中的preg_replace函数

问题提出

最近在土司上面看到一个求助的帖子,是关于这个函数的对注入的过滤的

image-20210519095641626

包括下面很多人,都是在说这个规则是过滤所有的非字母和数字的

相信,其实开发人员也是这么想的

但是这个正则写的有问题

因为这是两个正则块一起匹配,就相当于第一个字符是个特殊符号,第二个只要是个数字

就不会被匹配到

如下图

image-20210519100754464

那这个正则应该怎么写呢

preg_replace("/([^a-z]|[^0-9])/","",$str);

image-20210519100841128

可以看出来了这是一个正则的缺陷,但是要想 构造SQL语句,还需要知道的是

preg_replace函数的匹配规则

这个可能以后会用的到就是关于整合表达式组合匹配的问题

这里主要提出的问题就两个

  • 对于这个匹配的组合,函数是怎么组合的?

  • preg_replace中是先匹配后删除,还是匹配和删除是同时进行的?

对于上述问题,在之前遇到的一些CMS中,我个人也忽略了这方面的探索

探索

假设

匹配组合的形式

假设存在1、2、3、4四个字符串

  • 顺序组合:1&23&4A-1
  • 顺序排列组合:1&22&33&4A-2

删除模式假设

  • 先全部匹配,再进行删除 (B-1
  • 匹配和删除同时进行 (B-2

假设组合

共有四种组合形式

  • A-1B-1
  • A-1B-2
  • A-2B-1
  • A-2B-2

排除影响因素

首先可以排除掉A-1的组合

我们可以使字符串的字符个数为奇数,这样无法构成循序组合

理论上最后一个字符,会被轮空不匹配

'10'30a

测试结果,可以看到最后一个字符a被删除

image-20210519105410669

现在还剩下两种可能

测试字符

'10'a0b

预期结果

  • A-2B-1
    • 分解后为[[',1],[1,0],[0,'],[',a],[a,0],[0,b]]
    • 其实这种想想也不可能,可能存在一个组合中需要删,另外一个不删的情况
    • 按照需要删除来看
    • '1
  • A-2B-2
    • [0,']不符合删除,删除后就不存在了[',a]组合
    • '1a

代码测试

image-20210519110348715

所以这里大概清楚了匹配模式

针对上面的注入问题

结果

在所有的非数字字母前或者后加一个 数字和字母的组合,比如:0x

1
2
3
4
5
6
<?php
$guanliyuan="'0x)0x 0xunion 0xselect 0xuser0x(0x)0x#";
$guanliyuan=preg_replace("/[^a-z][^0-9]/","",$guanliyuan);
$sql="select * from admin where (guanliyuan='{$guanliyuan}' and mima='')";
echo $sql;
?>

image-20210519110802751

end