Maison >développement back-end >tutoriel php >Démonstration et prévention des attaques CSRF dans le développement PHP

Démonstration et prévention des attaques CSRF dans le développement PHP

墨辰丷
墨辰丷original
2018-05-22 16:02:131407parcourir

Le nom complet de CSRF est Cross-site request falsification, et son nom chinois est cross-site request forgery (la falsification de requêtes inter-sites [lire plus facilement] CSRF est une sorte d'application Web qui maintient les utilisateurs connectés). dans Une méthode d'attaque qui effectue des opérations involontaires. Par rapport à XSS, CSRF profite de la confiance du système dans le navigateur de pages, tandis que XSS tire parti de la confiance du système dans l'utilisateur.

attaque csrf, c'est-à-dire falsification de demande intersite falsification de demande intersite (nom de domaine), où contrefaçon signifie contrefaçon. Il existe de nombreuses introductions sur CSRF sur Internet. Par exemple, un article senior explique en détail les méthodes d'attaque de CSRF. Veuillez vous référer à cet article pour une brève explication : La réalisation des attaques CSRF repose sur un fait aussi simple : lorsque nous utilisons. un navigateur pour naviguer sur le Web, nous ouvrons généralement plusieurs onglets de navigateur (ou fenêtres). Si nous nous connectons à un site A, si le site A suit la session de l'utilisateur via des cookies, une fois que l'utilisateur s'est connecté au site A, le site A le fera. définir les paramètres sur le client de l'utilisateur, si le site A a une page siteA-page.php (ressource url) et que le site B connaît l'adresse url, et que l'adresse de cette page est intégrée dans une page siteB-page.php de site B d'une manière ou d'une autre, si A ce moment, l'utilisateur ouvre siteB-page.php du site B tout en maintenant la session du site A. Puis tant que la page siteB-page.php peut déclencher cette adresse url (demandant l'url ressource du site A), une attaque CSRF est réalisée.

L’explication ci-dessus est difficile à expliquer, donnons donc un exemple simple pour la démontrer.

1, arrière-plan et processus de demande normal

Un nom de domaine de site est html5.yang.com, il a une adresse /get-update.php?uid=uid&username=username, vous pouvez voir Cette adresse peut transmettre certains paramètres via la méthode get. Si la logique de cette page est : elle met à jour le nom d'utilisateur en jugeant si l'uid est légal. Le script de cette page est le suivant :


<.>

<?php
// 这里简便起见, 从data.json中取出数据代替请求数据库
$str = file_get_contents(&#39;data.json&#39;);
$data = json_decode($str, true);

// 检查cookie和请求更改的uid, 实际应检查数据库中的用户是否存在
empty($_COOKIE[&#39;uid&#39;]) ||empty($_GET[&#39;uid&#39;]) || $_GET[&#39;uid&#39;] != $data[&#39;id&#39;] ? die(&#39;非法用户&#39;) : &#39;&#39;;
// 检查username参数
$data[&#39;username&#39;] = empty($_GET[&#39;username&#39;]) ? die(&#39;用户名不能为空&#39;) : $_GET[&#39;username&#39;];

// 更新数据
$data[&#39;username&#39;] = $_GET[&#39;username&#39;];
if(file_put_contents(&#39;data.json&#39;, json_encode($data))) {
  echo "用户名已更改为{$data[&#39;username&#39;]}<br>";
} else {
  die(&#39;更新失败&#39;);
}

Normalement, le lien vers cette page est placé sous le site A, comme la page csrfdemo.php du site A. Après vous être connecté au site A , les utilisateurs peuvent cliquer sur ce lien pour envoyer une demande. Par exemple, le site A a un script de page qui contient ce lien :

<?php
// 这里用一个data.json文件保存用户数据,模拟数据库中的数据
// 先初始化data.json中的数据为{"id":101,"username":"jack"}, 注意这句只让它执行一次, 然后把它注释掉
// file_put_contents(&#39;data.json&#39;,&#39;{"id":101,"username":"jack"}&#39;);

$data = json_decode(file_get_contents(&#39;data.json&#39;), true);

// 这里为了简便, 省略了用户身份验证的过程
if ($data[&#39;username&#39;]) {
  // 设置cookie
  setcookie(&#39;uid&#39;, $data[&#39;id&#39;], 0);
  echo "登录成功, {$data[&#39;username&#39;]}<br>";
}
?>

 <a href="http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=json" rel="external nofollow" >
  更新用户名为json
 </a>

Charger cette page en tant que suit :

Cliquez sur le lien présent sur la page pour accéder à la page get-update.php :

Le ci-dessus est le processus de requête normal. Voyons comment le site B l'implémente.

2. La mise en œuvre la plus simple de l'attaque CSRF

Le nom de domaine du site B est test.yang.com, qui possède une page csrf.php, à condition que l'utilisateur l'ouvre en maintenant la session de la page du site A, puis le site B peut mettre en œuvre des attaques CSRF. Quant à savoir pourquoi il est ouvert..., en fait, ce genre de situation est très courant lorsqu'on navigue sur le web. Par exemple, quand j'écrivais ce blog, j'avais l'impression de ne pas comprendre quelque chose au CSRF, et puis. Baidu Eh bien, il y a beaucoup de résultats de Baidu. S'il existe un site Web appelé CSRF Encyclopedia Knowledge, qui présente CSRF de manière très détaillée et faisant autorité, alors je cliquerai probablement dessus, mais ce site Web est en fait un site Web de phishing. Il se trouve sur un certain site Web. Une page très visitée intègre l'adresse URL de la page d'édition de mon blog, afin de pouvoir mettre en œuvre une attaque CSRF sur mon blog. Bon, passons aux choses sérieuses, jetons un œil au code du script csrf.php :

<?php
?>
<img src="http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=jsonp">

Vous pouvez voir que le code ci-dessus n'a pas code php, uniquement une balise img, le src de la balise img est le lien pour mettre à jour le nom d'utilisateur du site A, mais changez le nom d'utilisateur en jsonp Visitez la page csrf.php du site B :

ci-dessous Visitez ensuite la page csrfdemo.php du site A :

Vous pouvez voir que le nom d'utilisateur a été changé en jsonp.

Une brève analyse : le csrf.php du site B utilise la balise img en HTML Nous savons tous que la balise img a un attribut src, et la valeur de l'attribut pointe vers l'adresse de l'image qui doit être utilisée. être chargé. Lorsque la page est chargée, Charger une image équivaut à lancer une requête http à l'adresse pointée par src. Tant que l'adresse de l'image est modifiée en adresse de script, l'attaque CSRF la plus simple sera naturellement réalisée. . De cette façon, le CSRF est en fait très facile à mettre en œuvre, mais tout le monde est un « gentleman », et personne ne restera inactif pour faire des choses aussi « obscènes ». Mais vous ne devez pas avoir l’intention de nuire aux autres, ni l’intention de vous prémunir contre les autres. Voyons comment empêcher simplement cette attaque CSRF la plus simple.

3. Mesures préventives simples

En fait, les mesures préventives sont relativement simples. Le site A peut déterminer la source de l'en-tête de requête dans le script get-update.php. pas le site A, il peut tronquer la requête, ajoutez du code à get-update.php ci-dessous :

<?php
// 检查上一页面是否为当前站点下的页面
if (!empty($_SERVER[&#39;HTTP_REFERER&#39;])) {
  if (parse_url($_SERVER[&#39;HTTP_REFERER&#39;], PHP_URL_HOST) != &#39;html5.yang.com&#39;) {
    // 可以设置http错误码或者指向一个无害的url地址
    //header(&#39;HTTP/1.1 404 not found&#39;);
    //header(&#39;HTTP/1.1 403 forbiden&#39;);
    header(&#39;Location: http://html5.yang.com/favicon.ico&#39;);
    // 这里需要注意一定要exit(), 否则脚本会接着执行
    exit();
  }
 }

$str = file_get_contents(&#39;data.json&#39;);
// 代码省略

但是,这样就万事大吉了吗,如果http请求头被伪造了呢?A站点升级了防御,B站点同时也可以升级攻击,通过curl请求来实现csrf,修改B站点的csrf.php代码如下:

<?php
$url = &#39;http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=jsonp&#39;;
$refer = &#39;http://html5.yang.com/&#39;;
// curl方法发起csrf攻击
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
// 设置Referer
curl_setopt($ch, CURLOPT_REFERER, $refer);
// 这里需要携带上cookie, 因为A站点get-update.php对cooke进行了判断
curl_setopt($ch, CURLOPT_COOKIE, &#39;uid=101&#39;);
curl_exec($ch);
curl_close($ch);
?>
<img src="http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=jsonp">

这样同样可以实现csrf攻击的目的。那么就没有比较好的防范方法了吗?

4,小结

下面我们回到问题的开始,站点A通过cookie来跟踪用户会话,在cookie中存放了重要的用户信息uid,get-update.php脚本通过判断用户的cookie正确与否来决定是否更改用户信息,看来靠cookie来跟踪会话并控制业务逻辑是不太安全的,还有最严重的一点:get-update.php通过get请求来修改用户信息,这个是大忌。所以站点A可以接着升级防御:用session来代替cookie来跟踪用户会话信息,将修改用户信息的逻辑重写,只允许用post方法来请求用户信息。站点B同样可以升级攻击:curl可以构造post请求,劫持session等等,不过这些我还没研究过,后续再说吧。

相关推荐:

php curl带有csrf-token验证模拟提交实例详解

php表单防止重复提交(防csrf漏洞) 

php curl带有csrf-token验证模拟提交方法

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!

Déclaration:
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