>백엔드 개발 >PHP 튜토리얼 >PHP 양식은 반복 제출을 방지합니다(csrf 방지 취약점).

PHP 양식은 반복 제출을 방지합니다(csrf 방지 취약점).

不言
不言원래의
2018-04-20 11:44:013817검색

이 글의 내용은 PHP 양식의 반복 제출 방지(CSRF 취약점 방지)에 관한 내용입니다. 이제 필요한 친구들이 참고할 수 있도록 공유하겠습니다.

토큰에 대한 간략한 이야기

Token, 토큰이며 가장 큰 특징은 무작위성과 예측 불가능성입니다. 일반 해커나 소프트웨어는 이를 추측할 수 없습니다.

그렇다면 토큰의 기능은 무엇인가요? 원리는 무엇입니까?

토큰은 일반적으로 반복적인 양식 제출과 안티 csrf 공격(사이트 간 요청 위조)을 방지하기 위해 두 가지 위치에서 사용됩니다.

둘 다 원칙적으로 세션 토큰을 통해 구현됩니다. 클라이언트가 페이지를 요청하면 서버는 임의의 숫자 토큰을 생성하고 세션에 토큰을 배치한 다음 클라이언트에 토큰을 보냅니다(보통 숨겨진 양식을 구성하여). 다음에 클라이언트가 요청을 제출하면 토큰이 양식과 함께 서버에 제출됩니다.

그런 다음 "anti csrf 공격"에 적용되면 서버는 토큰 값을 확인하여 세션의 토큰 값과 동일한지 확인합니다. 동일하면 요청이 유효한 것으로 증명할 수 있습니다. 위조되지 않았습니다.

단, "양식의 반복 제출 방지"를 위해 사용하는 경우 서버 측에서 첫 번째 검증이 동일한 후 사용자가 반복적으로 제출하면 두 번째 검증에서 세션의 토큰 값이 업데이트됩니다. 사용자가 제출한 양식의 토큰은 변경되지 않았지만 서버 측 세션의 토큰은 변경되었기 때문에 판단이 실패합니다.

위 세션 적용은 비교적 안전하지만 동시에 여러 페이지와 여러 요청이 있는 경우 여러 토큰을 동시에 생성하는 방법을 사용해야 하므로 더 많은 시간이 소요됩니다. 자원을 낭비하고 실행 효율성을 감소시킵니다. 따라서 Session Token 대신에 쿠키에 인증정보를 저장하는 방식을 사용할 수도 있습니다. 예를 들어 "반복 제출"을 처리하는 경우 제출된 정보는 첫 번째 제출 후 쿠키에 기록됩니다. 두 번째로 제출하면 쿠키에 이미 제출 기록이 있으므로 두 번째 제출은 실패합니다.

그러나 쿠키 저장에는 치명적인 약점이 있습니다. 쿠키가 하이재킹되면(XSS 공격으로 사용자 쿠키를 쉽게 얻을 수 있음) 또 다른 게임 오버가 발생합니다. 해커는 CSRF 공격을 직접 구현합니다.

1. 먼저 xss 공격 방지

2. 리퍼러 확인

3. 중요한 쿠키 설정은 토큰과 같은 https 전용 4. 서명, 토큰 사용

5.get은 정보 쿼리에만 사용됩니다

6. 게시물을 사용하여 양식을 제출하세요

7. 크로스 스크립트 삽입을 주의해서 사용하세요


따라서 안전성과 효율성은 상대적입니다. 구체적인 문제를 자세히 다루겠습니다.


토큰은 반복 제출을 방지하기 위해 PHP 양식에 추가됩니다.

<span style="margin:0px;padding:0px;"></span>원칙은 임의의 문자열을 생성하여 세션에 넣는 것입니다. 양식을 제출한 후 이 문자열을 확인하여 방지할 수 있습니다. 다른 사람들이 양식을 직접 작성하여 제출을 속이는 것을 방지하거나 두 번 클릭하여 제출합니다.

php로 구현한 간단한 코드는 다음과 같습니다


<?php
/*
* PHP简单利用token防止表单重复提交
* 此处理方法纯粹是为了给初学者参考
*/
session_start();
function set_token() {
  $_SESSION[&#39;token&#39;] = md5(microtime(true));
}
function valid_token() {
  $return = $_REQUEST[&#39;token&#39;] === $_SESSION[&#39;token&#39;] ? true : false;
  set_token();
  return $return;
}
//如果token为空则生成一个token
if(!isset($_SESSION[&#39;token&#39;]) || $_SESSION[&#39;token&#39;]==&#39;&#39;) {
  set_token();
}
if(isset($_POST[&#39;test&#39;])){
  if(!valid_token()){
    echo "token error";
  }else{
    echo &#39;成功提交,Value:&#39;.$_POST[&#39;test&#39;];
  }
}
?>
<form method="post" action="">
  <input type="hidden" name="token" value="<?php echo $_SESSION[&#39;token&#39;]?>">
  <input type="text" name="test" value="Default">
  <input type="submit" value="提交" />
</form>

<span style="margin:0px;padding:0px;"></span><span style="margin:0px;padding:0px;"></span>

上面的比较简单一点的方法,下面的代码更加安全一点。

Token.php


<?php
/*
 * Created on 2013-3-25
 *
 * To change the template for this generated file go to
 * Window - Preferences - PHPeclipse - PHP - Code Templates
 */
function getToken($len = 32, $md5 = true) {
  # Seed random number generator
  # Only needed for PHP versions prior to 4.2
  mt_srand((double) microtime() * 1000000);
  # Array of characters, adjust as desired
  $chars = array (
    &#39;Q&#39;,
    &#39;@&#39;,
    &#39;8&#39;,
    &#39;y&#39;,
    &#39;%&#39;,
    &#39;^&#39;,
    &#39;5&#39;,
    &#39;Z&#39;,
    &#39;(&#39;,
    &#39;G&#39;,
    &#39;_&#39;,
    &#39;O&#39;,
    &#39;`&#39;,
    &#39;S&#39;,
    &#39;-&#39;,
    &#39;N&#39;,
    &#39;<&#39;,
    &#39;D&#39;,
    &#39;{&#39;,
    &#39;}&#39;,
    &#39;[&#39;,
    &#39;]&#39;,
    &#39;h&#39;,
    &#39;;&#39;,
    &#39;W&#39;,
    &#39;.&#39;,
    &#39;/&#39;,
    &#39;|&#39;,
    &#39;:&#39;,
    &#39;1&#39;,
    &#39;E&#39;,
    &#39;L&#39;,
    &#39;4&#39;,
    &#39;&&#39;,
    &#39;6&#39;,
    &#39;7&#39;,
    &#39;#&#39;,
    &#39;9&#39;,
    &#39;a&#39;,
    &#39;A&#39;,
    &#39;b&#39;,
    &#39;B&#39;,
    &#39;~&#39;,
    &#39;C&#39;,
    &#39;d&#39;,
    &#39;>&#39;,
    &#39;e&#39;,
    &#39;2&#39;,
    &#39;f&#39;,
    &#39;P&#39;,
    &#39;g&#39;,
    &#39;)&#39;,
    &#39;?&#39;,
    &#39;H&#39;,
    &#39;i&#39;,
    &#39;X&#39;,
    &#39;U&#39;,
    &#39;J&#39;,
    &#39;k&#39;,
    &#39;r&#39;,
    &#39;l&#39;,
    &#39;3&#39;,
    &#39;t&#39;,
    &#39;M&#39;,
    &#39;n&#39;,
    &#39;=&#39;,
    &#39;o&#39;,
    &#39;+&#39;,
    &#39;p&#39;,
    &#39;F&#39;,
    &#39;q&#39;,
    &#39;!&#39;,
    &#39;K&#39;,
    &#39;R&#39;,
    &#39;s&#39;,
    &#39;c&#39;,
    &#39;m&#39;,
    &#39;T&#39;,
    &#39;v&#39;,
    &#39;j&#39;,
    &#39;u&#39;,
    &#39;V&#39;,
    &#39;w&#39;,
    &#39;,&#39;,
    &#39;x&#39;,
    &#39;I&#39;,
    &#39;$&#39;,
    &#39;Y&#39;,
    &#39;z&#39;,
    &#39;*&#39;
  );
  # Array indice friendly number of chars;
  $numChars = count($chars) - 1;
  $token = &#39;&#39;;
  # Create random token at the specified length
  for ($i = 0; $i < $len; $i++)
    $token .= $chars[mt_rand(0, $numChars)];
  # Should token be run through md5?
  if ($md5) {
    # Number of 32 char chunks
    $chunks = ceil(strlen($token) / 32);
    $md5token = &#39;&#39;;
    # Run each chunk through md5
    for ($i = 1; $i <= $chunks; $i++)
      $md5token .= md5(substr($token, $i * 32 - 32, 32));
    # Trim the token
    $token = substr($md5token, 0, $len);
  }
  return $token;
}
?>

<span style="margin:0px;padding:0px;"></span>

form.php


<?php
include_once("token.php");
$token = getToken();
session_start();
$_SESSION[&#39;token&#39;] = $token;
?>
<form action="action.php" method="post"
<input type="hidden" name="token" value="<?=$token?>" />
<!-- 其他input submit之类的 -->
</form>

<span style="margin:0px;padding:0px;"></span>

action.php


위쪽의 방식은 아래쪽에 있는 혁신적인 방법입니다.


<?php
session_start();
if($_POST[&#39;token&#39;] == $_SESSION[&#39;token&#39;]){
  unset($_SESSION[&#39;token&#39;]);
  echo "这是一个正常的提交请求";
}else{
  echo "这是一个非法的提交请求";
}
?>

<span style="margin:0px;padding:0px;"></span>

Token.php🎜🎜🎜🎜🎜🎜🎜🎜rrreee🎜<span style="margin:0px;padding:0px;"></span>🎜🎜🎜🎜🎜🎜

form.php🎜🎜🎜🎜🎜🎜🎜🎜rrreee🎜<span style="margin:0px;padding:0px;"></span>🎜🎜🎜🎜🎜🎜

action.php🎜🎜🎜

🎜🎜🎜🎜🎜🎜rrreee🎜<span style="margin:0px;padding:0px ;"></span>🎜🎜🎜🎜🎜🎜관련 추천:

변수로 표시되는 PHP 양식 이름 값 문제

php 양식 파일 iframe 비동기 업로드 예제에 대한 자세한 설명



위 내용은 PHP 양식은 반복 제출을 방지합니다(csrf 방지 취약점).의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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