Home >Backend Development >PHP Tutorial >Demonstration and prevention of CSRF attacks in PHP development
The full name of CSRF is Cross-site request forgery, and its Chinese name is cross-site request forgery (forged cross-site request [read more smoothly]). CSRF is a kind of web application that holds users logged in An attack method that performs unintended operations. Compared with XSS, CSRF takes advantage of the system's trust in the page browser, while XSS takes advantage of the system's trust in the user.
csrf attack, that is, cross site request forgery cross-site (domain name) request forgery, where forgery means forgery. There are many introductions about CSRF on the Internet. For example, a senior article explains in detail the attack methods of CSRF. Please refer to this article for a brief explanation: The realization of CSRF attacks relies on such a simple fact: when we use a browser to browse the web, we usually Open several browser tabs (or windows). If we log in to a site A, if site A tracks the user's session through cookies, then after the user logs in to site A, site A will set the settings on the user's client. Cookie, if site A has a page siteA-page.php (url resource) and site B knows the url address, and the address of this page is embedded in a page siteB-page.php of site B in some way, if At this time, the user opens siteB-page.php of site B while maintaining the session of site A. Then as long as the siteB-page.php page can trigger this url address (requesting the url resource of site A), a csrf attack is achieved.
The above explanation is very confusing, so let’s give a simple example to demonstrate.
1, background and normal request process
A site domain name is html5.yang.com, it has a /get-update.php?uid=uid&username=username address, which can be seen This address can pass some parameters through the get method. If the logic of this page is: it updates the username by judging whether the uid is legal. The script of this page is as follows:
<?php // 这里简便起见, 从data.json中取出数据代替请求数据库 $str = file_get_contents('data.json'); $data = json_decode($str, true); // 检查cookie和请求更改的uid, 实际应检查数据库中的用户是否存在 empty($_COOKIE['uid']) ||empty($_GET['uid']) || $_GET['uid'] != $data['id'] ? die('非法用户') : ''; // 检查username参数 $data['username'] = empty($_GET['username']) ? die('用户名不能为空') : $_GET['username']; // 更新数据 $data['username'] = $_GET['username']; if(file_put_contents('data.json', json_encode($data))) { echo "用户名已更改为{$data['username']}<br>"; } else { die('更新失败'); }
Normally, the link to this page is placed under site A, such as the csrfdemo.php page of site A. After logging in to site A, the user can click this link to send a request, such as Site A has a page script that contains this link:
<?php // 这里用一个data.json文件保存用户数据,模拟数据库中的数据 // 先初始化data.json中的数据为{"id":101,"username":"jack"}, 注意这句只让它执行一次, 然后把它注释掉 // file_put_contents('data.json','{"id":101,"username":"jack"}'); $data = json_decode(file_get_contents('data.json'), true); // 这里为了简便, 省略了用户身份验证的过程 if ($data['username']) { // 设置cookie setcookie('uid', $data['id'], 0); echo "登录成功, {$data['username']}<br>"; } ?> <a href="http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=json" rel="external nofollow" > 更新用户名为json </a>
Loading this page is as follows:
Click the link on the page to get to the get-update.php page:
The above is the normal request process. Let’s take a look at how site B implements the CSRF attack.
2, the simplest implementation of csrf attack
The domain name of site B is test.yang.com, which has a page csrf.php, as long as the user opens this while maintaining the session of site A page, then site B can implement CSRF attacks. As for why it is opened..., in fact, this situation is very common when we browse the web. For example, when I was writing this blog, I felt that I didn’t understand something about CSRF, and then I went to Baidu Well, there are a lot of results from Baidu. If there is a website called CSRF Encyclopedia Knowledge, which introduces CSRF in a very detailed and authoritative way, then I will probably click on it, but this website is actually a phishing website. It is on a certain website. The URL address of my blog editing page is embedded in a frequently visited page, so it can implement a CSRF attack on my blog. Okay, let’s get down to business, let’s take a look at the csrf.php script code:
<?php ?> <img src="http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=jsonp">
You can see that the above code has no php code, only one img tag, img The src of the tag is the link to update the username of site A, but the username is changed to jsonp. Visit the csrf.php page of site B:
Visit again below Download the csrfdemo.php page of site A:
You can see that the user name has been changed to jsonp.
A brief analysis: The csrf.php of site B uses the img tag in HTML. We all know that the img tag has a src attribute, and the attribute value points to the address of the image that needs to be loaded. When the page is loaded, Loading an image is equivalent to initiating an http request to the address pointed to by src. As long as the address of the image is changed to a script address, the simplest CSRF attack will naturally be realized. In this way, CSRF is actually very easy to implement, but everyone is a "gentleman", and no one will be idle to do such "obscene" things. But you must not have the intention to harm others, and you must not have the intention to guard against others. Let’s take a look at how to simply prevent this simplest CSRF attack.
3, simple preventive measures
In fact, the preventive measures are relatively simple. Site A can determine the source of the request header in the get-update.php script. If the source is not site A, it can truncate the request. , add some code to get-update.php below:
<?php // 检查上一页面是否为当前站点下的页面 if (!empty($_SERVER['HTTP_REFERER'])) { if (parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) != 'html5.yang.com') { // 可以设置http错误码或者指向一个无害的url地址 //header('HTTP/1.1 404 not found'); //header('HTTP/1.1 403 forbiden'); header('Location: http://html5.yang.com/favicon.ico'); // 这里需要注意一定要exit(), 否则脚本会接着执行 exit(); } } $str = file_get_contents('data.json'); // 代码省略
但是,这样就万事大吉了吗,如果http请求头被伪造了呢?A站点升级了防御,B站点同时也可以升级攻击,通过curl请求来实现csrf,修改B站点的csrf.php代码如下:
<?php $url = 'http://html5.yang.com/csrfdemo/get-update.php?uid=101&username=jsonp'; $refer = 'http://html5.yang.com/'; // 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, 'uid=101'); 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验证模拟提交实例详解
The above is the detailed content of Demonstration and prevention of CSRF attacks in PHP development. For more information, please follow other related articles on the PHP Chinese website!