>  기사  >  백엔드 개발  >  CSRF 방어 예시(PHP)

CSRF 방어 예시(PHP)

高洛峰
高洛峰원래의
2016-10-17 10:44:481372검색

CSRF 방어는 서버 측과 클라이언트 측 모두에서 수행할 수 있습니다. 이제 일반 CSRF 방어도 서버 측에서 수행됩니다.

 1. 서버 측 CSRF 방어

서버 측에서 CSRF를 구현하는 방법은 여러 가지가 있지만 일반적인 아이디어는 클라이언트에 의사 난수를 추가하는 것과 같습니다. 페이지.

 (1). 쿠키 해싱(모든 형식에는 동일한 의사 난수 값이 포함됨):

 공격자가 제3자 쿠키를 얻을 수 없기 때문에 이것이 가장 간단한 해결책일 수 있습니다(이론적으로). 따라서 양식의 데이터가 구성되지 않습니다. >

<?php
   //构造加密的Cookie信息
   $value = “DefenseSCRF”;
   setcookie(”cookie”, $value, time()+3600);
 ?>

양식에 해시 값을 추가하여 이것이 실제로 사용자가 보낸 요청인지 확인합니다.

<?php
  $hash = md5($_COOKIE[&#39;cookie&#39;]);
?>
<form method=”POST” action=”transfer.php”>
  <input type=”text” name=”toBankId”>
  <input type=”text” name=”money”>
  <input type=”hidden” name=”hash” value=”<?=$hash;?>”>
  <input type=”submit” name=”submit” value=”Submit”>
</form>

그런 다음 서버 측에서 해시 값 검증을 수행합니다

    <?php
        if(isset($_POST[&#39;check&#39;])) {
             $hash = md5($_COOKIE[&#39;cookie&#39;]);
             if($_POST[&#39;check&#39;] == $hash) {
                  doJob();
             } else {
        //...
             }
        } else {
      //...
        }
      ?>

개인적으로 이 방법을 사용하면 CSRF 공격을 99% 제거할 수 있다고 생각하지만 아직 1%가 남아있습니다.. .. 웹사이트 XSS 취약점으로 인해 사용자의 쿠키가 쉽게 도난당할 수 있으므로 이는 또 다른 1%입니다. 대부분의 공격자들은 해시 값을 계산해야 한다고 생각하면 기본적으로 포기할 것입니다. 그러나 일부를 제외하고는 100% 제거해야 한다면 이 방법은 최선의 방법이 아닙니다.

 (2). 인증 코드

이 솔루션의 아이디어는 사용자가 제출할 때마다 양식의 사진에 임의의 문자열을 채워야 한다는 것입니다. ... 이 솔루션은 CSRF를 완벽하게 해결할 수 있지만 개인적으로 사용 편의성 측면에서 그다지 좋지 않다고 생각합니다. 또한 인증 코드 이미지를 사용하면 일부에서는 영향을 받을 수 있는 MHTML이라는 버그가 포함되어 있다고 들었습니다. 마이크로소프트 IE 버전.

 (3).일회성 토큰(다른 형태에는 다른 의사 난수 값이 포함됨)

일회성 토큰을 구현할 때 한 가지에 주의해야 합니다: "병렬 세션 호환성" ". 사용자가 사이트에서 동시에 두 개의 서로 다른 양식을 여는 경우 CSRF 보호 조치는 양식 제출에 영향을 주어서는 안됩니다. 양식이 로드될 때마다 사이트에서 의사 난수 값을 생성하여 이전 의사 난수 값을 덮어쓴다면 어떤 일이 일어날지 생각해 보십시오. 다른 모든 양식에는 불법적인 의사 난수 값이 포함되어 있기 때문에 사용자는 마지막으로 연 양식만 성공적으로 제출할 수 있습니다. CSRF 보호가 탭 브라우징이나 사이트 탐색을 위한 다중 브라우저 창 사용에 영향을 미치지 않도록 주의해야 합니다.

다음은 제가 구현한 것입니다:

1) 먼저 토큰 생성 함수(gen_token()):

 <?php
     function gen_token() {
     //这里我是贪方便,实际上单使用Rand()得出的随机数作为令牌,也是不安全的。
    //这个可以参考我写的Findbugs笔记中的《Random object created and used only once》
          $token = md5(uniqid(rand(), true));
          return $token;
     }

2) 그런 다음 세션 토큰 생성 함수입니다. (gen_stoken()):

     <?php
       function gen_stoken() {
      $pToken = "";
      if($_SESSION[STOKEN_NAME]  == $pToken){
        //没有值,赋新值
        $_SESSION[STOKEN_NAME] = gen_token();
      }    
      else{
        //继续使用旧的值
      }
       }
     ?>

3) 숨겨진 입력 필드를 생성하는 WEB 양식 기능:

     <?php
       function gen_input() {
            gen_stoken();
            echo “<input type=\”hidden\” name=\”" . FTOKEN_NAME . “\”
                 value=\”" . $_SESSION[STOKEN_NAME] . “\”> “;
       }
     ?>

4) WEB 양식 구조:

     <?php
          session_start();
          include(”functions.php”);
     ?>
     <form method=”POST” action=”transfer.php”>
          <input type=”text” name=”toBankId”>
          <input type=”text” name=”money”>
          <? gen_input(); ?>
          <input type=”submit” name=”submit” value=”Submit”>
     </FORM>

5) 서버 측 인증 토큰:

매우 간단하므로 여기서는 자세히 설명하지 않겠습니다.

실제로 위의 내용은 "병렬 세션 호환성" 규칙을 완전히 준수하지 않습니다. 이를 기준으로 수정할 수 있습니다.


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.