Maison > Opération et maintenance > Sécurité > Principe AOP et méthode d'utilisation correcte

Principe AOP et méthode d'utilisation correcte

王林
Libérer: 2020-01-11 17:29:47
avant
6471 Les gens l'ont consulté

Principe AOP et méthode d'utilisation correcte

Avant-propos

À mesure que les requêtes paramétrées sur les bases de données deviennent de plus en plus courantes, les vulnérabilités d'injection SQL sont considérablement réduites par rapport à avant, et PDO est la plus typique en PHP. La méthode de requête précompilée est de plus en plus utilisée.

Comme nous le savons tous, PDO est le meilleur moyen d'empêcher l'injection SQL en PHP, mais ce n'est pas un moyen à 100 % d'éliminer l'injection SQL. La clé dépend de la façon dont on l'utilise.

J'ai appris dans un article précédent que des problèmes tels que l'exécution de plusieurs phrases provoqués par des paramètres contrôlables dans les scénarios PDO (https://xz.aliyun.com/t/3950), donc J'ai écrit sur l'injection SQL dans le scénario PDO qui a été réexploré.

Problèmes de sécurité qui peuvent être contrôlés par les instructions de requête PDO :

Créez d'abord une nouvelle bibliothèque et une nouvelle table localement et écrivez quelque chose avec désinvolture.

Principe AOP et méthode dutilisation correcte

Écrivez ensuite un test.php et utilisez PDO pour effectuer une requête simple :

<?php 
try{
  $db = new PDO(&#39;mysql:host=localhost;dbname=pdotest&#39;,&#39;root&#39;,&#39;&#39;);
} 
catch(Exception $e)
{  echo $e->getMessage();
}if(isset($_GET[&#39;id&#39;]))
{
  $id = $_GET[&#39;id&#39;];
}else{
  $id=1;
}
$query = "select balabala from table1 where 1=?";echo "id:".$id."</br>";
$row = $db->prepare($query);
$row->bindParam(1,$id);
$row->execute();
$result = $row->fetch(PDO::FETCH_ASSOC);if($result)
{  echo "结果为:";
  print_r($result);  echo "</br>";
}
Copier après la connexion

Imprimez le contenu d'entrée et les résultats sur la page :

Principe AOP et méthode dutilisation correcte

PDO a les trois paramètres principaux suivants liés aux problèmes de sécurité :

PDO::ATTR_EMULATE_PREPARES
PDO::ATTR_ERRMODE
PDO::MYSQL_ATTR_MULTI_STATEMENTS
Copier après la connexion

sont respectivement liés à la pré-compilation simulée, au rapport d'erreurs et à l'exécution de plusieurs phrases.

PDO permet l'exécution de plusieurs phrases et la précompilation simulée par défaut. Il a été écrit dans de nombreux articles précédents que lorsque les paramètres sont contrôlables, cela conduira à une injection de pile.

Par exemple, si nous modifions l'instruction de requête en :

$query = "select balabala from table1 where 1={$id}";
$row = $db->query($query);
Copier après la connexion

, alors avant que l'étape $db->query() ne soit exécutée, nous pouvons effectuer des opérations illégales sur $query, alors PDO équivaut à Inutile :

Principe AOP et méthode dutilisation correcte

Risques de sécurité dans les paramètres par défaut de PDO :

Si nous n'avons aucun paramètre contrôlable dans l'instruction de requête, saisissez les paramètres comme suit N'y a-t-il aucun problème si je l'écris dans prepare->bindParam->execute ?

Nous interrogeons selon l'instruction suivante :

$query = "select balabala from table1 where 1=?";
$row = $db->prepare($query);
$row->bindParam(1,$_GET[‘id’]);
$row->execute();
Copier après la connexion

Nous entrons un paramètre aléatoire dans l'URL : ?id=asdasd, puis définissons SET GLOBAL GENERAL_LOG=ON pour surveiller en temps réel à partir du .log Jetez un œil à ce que l'instruction sql exécute réellement :

Principe AOP et méthode dutilisation correcte

Nous avons constaté que la méthode d'envoi de requêtes précompilées simulées n'est pas différente du mysqli précédent, mais nous avons remarqué que dans l'original Les paramètres ne sont pas entourés de guillemets simples dans l'instruction de requête, mais ils sont entourés de guillemets simples ici, nous pouvons donc essayer de saisir certains caractères spéciaux, tels que des guillemets simples :

Principe AOP et méthode dutilisation correcte

Nous avons constaté que les guillemets simples étaient échappés, alors nous n'avons pas pu nous empêcher de penser à ce qui se passerait si l'encodage gbk était défini :

Principe AOP et méthode dutilisation correcte

Nous trouverions que select * from table1 a été exécuté avec succès, bien que PDO ne renvoie qu'un résultat, mais il est effectivement exécuté.

En d'autres termes, même s'il n'y a pas de paramètres contrôlables dans l'instruction de requête, mais uniquement des paramètres liés tels que ? ou :id, l'injection de pile peut toujours être effectuée.

Et si vous désactivez l'exécution de plusieurs phrases ?

Nous définissons PDO::MYSQL_ATTR_MULTI_STATEMENTS sur false et répétons l'opération ci-dessus :

Principe AOP et méthode dutilisation correcte

Nous avons constaté que cela ne fonctionne plus.

Principe AOP et méthode dutilisation correcte

En fait, seule la déclaration de mise en gbk a été exécutée

Mais est-ce la fin ?

Pourquoi ne pas essayer d’autres méthodes comme l’injection syndicale ?

Principe AOP et méthode dutilisation correcte

Après l'avoir essayé, j'ai découvert que l'injection syndicale était également possible ! Pas besoin d'exécuter plusieurs phrases du tout !

实际上,在模拟预编译的情况下,PDO对于SQL注入的防范(PDO::queto()),无非就是将数字型的注入转变为字符型的注入,又用类似mysql_real_escape_string()的方法将单引号、双引号、反斜杠等字符进行了转义。

这种防范方法在GBK编码的情况下便可用宽字节进行绕过,而在非GBK编码的情况下,若存在二次注入的情况,是否能利用呢?

答案是否定的。

二次注入是由于对添加进数据库中的数据没有再次处理和转义而导致的,而预编译对每次查询都进行转义,则不存在二次注入的情况。

上述安全隐患,是由于未正确设置PDO造成的,在PDO的默认设置中,PDO::ATTR_EMULATE_PREPARES和PDO::MYSQL_ATTR_MULTI_STATEMENTS都是true,意味着模拟预编译和多句执行是默认开启的。

而在非模拟预编译的情况下,若语句中没有可控参数,是否还能这样做呢?

答案是否定的。

我们将PDO::ATTR_EMULATE_PREPARES设为false,来看看sql语句到底执行了什么:

Principe AOP et méthode dutilisation correcte

它对每一句sql语句都进行了预编译和执行两个操作,在执行select balabala from table1 where 1=?这句时,如果是GBK编码,那么它将会把?绑定的参数转化成16进制,这样无论输入什么样的东西都无法再进行注入了。

如果不是GBK编码,如上面所说,也不存在二次注入的情况,故可以避免SQL注入漏洞。

相同原理的Prepare Statement方法

PDO的原理,与Mysql中prepare语句是一样的。上面PDO所执行的SQL语句,用如下的方式可以等效替代:

Set @x=0x31
Prepare a from “select balabala from table1 where 1=?”
Execute a using @x
Copier après la connexion

我们可以手动将输入的参数设置为@x,并将其转化为16进制,随后预编译,再执行

也就是说,不用PDO也可以仿照其原理手动设置预编译:

$db = new mysqli(&#39;localhost&#39;,&#39;root&#39;,&#39;&#39;,&#39;pdotest&#39;);if(isset($_GET[&#39;id&#39;]))
{
	$id = "0x".bin2hex($_GET[&#39;id&#39;]);
}else{
	$id=1;
}echo "id:".$id."</br>";
$db->query("set names gbk");
$db->query("set @x={$id}");
$db->query("prepare a from &#39;select balabala from table1 where 1=?&#39;");
$row = $db->query("execute a using @x");
$result = $row->fetch_assoc();if($result)
{	echo "结果为:";
	print_r($result);	echo "</br>";
}
Copier après la connexion

得到的结果和使用PDO是一样的:

Principe AOP et méthode dutilisation correcte

这样设置不用担心没有合理地设置PDO,或是用了GBK编码等情况。

Prepare Statement在SQL注入中的利用

Prepare语句在防范SQL注入方面起到了非常大的作用,但是对于SQL注入攻击却也提供了新的手段。

Prepare语句最大的特点就是它可以将16进制串转为语句字符串并执行。如果我们发现了一个存在堆叠注入的场景,但过滤非常严格,便可以使用prepare语句进行绕过。

例如我们将createtable table2 like table1转化成16进制,然后执行:

Principe AOP et méthode dutilisation correcte

我们发现数据库中已经多了一个表table2。则语句成功执行了。

总结

对于此类问题的防范,主要有以下三个方面:

1. 合理、安全地使用gbk编码。即使采用PDO预编译的方式,如若配置不当,依然可造成宽字节注入

2. 使用PDO时,一定要将模拟预编译设为false

3. 可采用使用Prepare Statement手动预编译,杜绝SQL注入

相关文章教程推荐:网站安全教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:freebuf.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal