PHP 개발 시 CSRF 공격 시연 및 예방

墨辰丷
풀어 주다: 2023-03-27 13:50:01
원래의
1384명이 탐색했습니다.

CSRF의 정식 명칭은 Cross-site request forgery이고, 중국어 이름은 cross-site request forgery(교차 사이트 요청 위조[더 원활하게 읽기])입니다. 로그인된 웹 애플리케이션에 대한 요청 의도된 작업의 공격 방법입니다. XSS와 비교하여 CSRF는 페이지 브라우저에 대한 시스템의 신뢰를 활용하는 반면 XSS는 사용자에 대한 시스템의 신뢰를 활용합니다.

csrf 공격, 즉 크로스 사이트 요청 위조 크로스 사이트(도메인 이름) 요청 위조, 여기서 위조는 위조를 의미합니다. 예를 들어, CSRF의 공격 방법에 대해 자세히 설명하는 고급 기사가 있습니다. 간단한 설명은 이 기사를 참조하십시오. CSRF 공격의 실현은 다음과 같은 간단한 사실에 달려 있습니다. 웹을 탐색하기 위해 브라우저를 사용하는 경우 일반적으로 사이트 A에 로그인하면 사이트 A가 쿠키를 통해 사용자의 세션을 추적하고 사용자가 사이트 A에 로그인하면 사이트 A는 여러 개의 브라우저 탭(또는 창)을 엽니다. 사용자 클라이언트에서 설정을 지정합니다. 쿠키, 사이트 A에 siteA-page.php(url 리소스) 페이지가 있고 사이트 B가 URL 주소를 알고 있고 이 페이지의 주소가 siteB-page.php 페이지에 포함되어 있는 경우 어떤 방식으로든 사이트 B, 만약 이때 사용자가 사이트 A의 세션을 유지하면서 사이트 B의 siteB-page.php를 엽니다. 그러면 siteB-page.php 페이지가 이 URL 주소를 트리거할 수 있는 한(URL 요청) 사이트 A의 리소스), csrf 공격이 이루어졌습니다.

위의 설명은 매우 혼란스럽습니다. 간단한 예를 들어 보겠습니다.

1, 백그라운드 및 일반 요청 프로세스

사이트 도메인 이름은 html5.yang.com이고, /get-update.php?uid=uid&username=username 주소가 있으며, 이 주소를 통해 전달될 수 있음을 알 수 있습니다. get 메소드 일부 매개변수(이 페이지의 논리가 uid가 유효한지 여부를 판단하여 사용자 이름을 업데이트하는 경우) 이 페이지의 스크립트는 다음과 같습니다.


<?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;);
}
로그인 후 복사

일반적으로 이 페이지에 대한 링크 예를 들어 사이트 A의 csrfdemo.php 페이지에서 사용자는 사이트 A에 로그인한 후 이 링크를 클릭하여 요청을 보낼 수 있습니다. 예를 들어 사이트 A에는 다음 링크가 포함된 페이지 스크립트가 있습니다.

<?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>
로그인 후 복사

다음과 같이 이 페이지를 로드하세요.

페이지의 링크를 클릭하여 get-update.php 페이지로 이동하세요.

위는 일반적인 요청 프로세스입니다. 사이트 B가 CSRF 공격을 구현하는 방법을 살펴보십시오.

2. CSRF 공격의 가장 간단한 구현

사이트 B의 도메인 이름은 test.yang.com이며, 여기에는 csrf.php 페이지가 있습니다. 사용자가 사이트 A의 세션을 유지하면서 이 페이지를 열면 됩니다. B는 csrf 공격을 달성할 수 있습니다. 왜 오픈하는지... 사실 이런 상황은 웹서핑을 할 때 흔히 일어나는 일입니다. 예를 들어 제가 이 블로그를 쓰면서 CSRF에 대해 뭔가 이해가 안 되고 있다는 느낌이 들었습니다. 바이두 글쎄요, 바이두에서 나온 결과가 많이 나오네요. CSRF를 매우 상세하고 권위있게 소개하는 CSRF Encyclopedia Knowledge라는 웹사이트가 있다면 아마 클릭하겠지만 이 웹사이트는 실제로는 피싱 웹사이트입니다. 특정 웹사이트에 있습니다. 방문자가 많은 페이지에 내 블로그 편집 페이지의 URL 주소가 포함되어 있어 내 블로그에 CSRF 공격을 실행할 수 있습니다. 자, 본론으로 들어가 csrf.php 스크립트 코드를 살펴보겠습니다.

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

위 코드에는 PHP 코드가 없고 img 태그만 있으며 img의 src만 있는 것을 볼 수 있습니다. 태그는 사용자 이름을 업데이트하는 사이트 A의 태그입니다. 사용자 이름을 jsonp로 변경하고 사이트 B의 csrf.php 페이지를 방문하세요.

다음으로 사이트 A의 csrfdemo.php 페이지를 방문하세요.

사용자 이름이 jsonp로 변경된 것을 확인할 수 있습니다.

간단한 분석: 사이트 B의 csrf.php는 img 태그에 src 속성이 있고 속성 값이 로드되어야 하는 이미지의 주소를 가리킨다는 것을 모두 알고 있습니다. 페이지가 로드되면 이미지를 로드하는 것은 src가 가리키는 주소로 http 요청을 시작하려면 이미지 주소를 스크립트 주소로 변경하기만 하면 되며 이는 자연스럽게 가장 간단한 CSRF 공격을 구현합니다. 이런 식으로 CSRF는 실제로 구현하기가 매우 쉽지만 모든 사람이 "신사"이고 누구도 그런 "외설적인" 일을 하려고 게으르지 않을 것입니다. 그러나 남에게 해를 끼치려는 의도가 있어서도 안 되고, 남을 경계하려는 의도도 있어서는 안 됩니다. 이 간단한 CSRF 공격을 간단히 방지하는 방법을 살펴보겠습니다.

3. 간단한 예방 조치

사실 예방 조치는 비교적 간단합니다. 사이트 A는 get-update.php 스크립트에서 요청 헤더의 소스를 확인할 수 있습니다. 다음은 get-update.php에 있습니다. 일부 코드를 추가하세요:

<?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验证模拟提交方法

위 내용은 PHP 개발 시 CSRF 공격 시연 및 예방의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!