2013-08-14 1 views
3

CSRF (Cross Site Whomery) 공격으로부터 사이트와 사용자를 보호하려는 경우 양식이있는 모든 페이지에 고유 토큰 $token = md5(time() * rand);을 생성 할 수 있습니다. 토큰은 숨겨진 입력 필드 echo '<input type="hidden" name="token" value="'.$token.'">';에 제출되고 동시에 세션 변수 $_SESSION['token'] = $token;에 저장됩니다.고유 한 양식 토큰이 사용자의 멀티 태스킹을 비활성화합니다.

제출 된 양식이 if($_POST['token'] == $_SESSION['token'])인지 확인하고 이에 따라 진행합니다.

그러나 일부 사용자는 멀티 태스킹을 할 수 있습니다. 이것은 내가 실제로 게시하는 동안 지금 실제로하고있는 것입니다.

내 게시물을 작성하는 동안 정보를 조사하거나 스택 오버플로에 대한 다른 질문을 보려면 다른 창/탭을 열어보십시오. 스택 오버플로를 사용하면 문제없이 양식을 제출할 수 있습니다.

하지만 내 사이트에서이 작업을 수행하는 경우 - 게시물/양식을 작성하면서 다른 페이지를 탐색하는 것을 의미 - 내 웹 사이트에서 다른 페이지를 가져올 때마다 내 $token이 재생성됩니다. 나는 결국 작업하고 있어요 양식에 숨겨진 input 토큰을 만드는 것은 늘 내가 다른 페이지를 방문했을 때 재생되어 더 이상 $_SESSION['token'] 변수를 일치하기 때문에 ... 잘못된를 제출 할

모든 좋은에게 어떻게이 문제를 예방할 수있는 아이디어 또는 우선 CSRF를 중단시킬 수있는 더 나은 해결책이 있습니까?

나는 다중 작업에 내 사용자를 허용 할 및 CSRF으로부터 보호 할

...

+0

내가 토큰이 전혀이를 방지하기 위하여려고하는 방법을 모르겠습니다. – John

+0

CSRF가 GET 또는 POST 요청에서 사용될 수 없도록 막기 위해 고유 한 토큰이 사용되어야합니다. –

+0

@ RaymondN : 예, 그게 정확히 내가하고있는 일입니다. 맞습니까? – olli

답변

4

난 당신 때문에 하나의 CSRF의 상태 것과 같은 문제를 했어 그들은 최신 페이지를 제출하지 않는 한 교체됩니다,하지만 당신은/세션 승 배열을 사용하는 경우이 문제 (들)을 해결한다 . 또한 captcha를 포함 시키려 할 수도 있습니다. Google의 Recaptcha를 권하고 싶습니다.

session_start(); 
function createToken(){ 
    $token = sha1(uniqid(mt_rand(), true)); 
    $_SESSION['Tokens']['Token'][] = $token; 
    $_SESSION['Tokens']['Time'][] = time() + (10 * 60); #10 min limit 
    #you can omit/change this if you want to not limit or extend time limit 
    return $token; 
} 

function checkToken($token){ 
    clearTokens(); 
    foreach($_SESSION['Tokens']['Token'] as $key => $value){ 
     if($value === $token){ 
      return true; 
     } 
    } 
    return false; 
} 

function clearTokens(){ 
    foreach($_SESSION['Tokens']['Time'] as $key => $value){ 
     if($value <= time()){ 
      unset($_SESSION['Tokens']['Token'][$key], $_SESSION['Tokens']['Time'][$key]); 
      #remove last parameter if you aren't using token time limit 
     } 
    } 
} 

당신의 HTML :

<input type="hidden" name="token" value="<?php createToken(); ?>"> 

PHP 토큰 검사

if(isset($_POST['token']) && checkToken($_POST['token'])){ 
    #valid token 
}else{ 
    #create error message saying that they tried to repost data or session token expired 
} 
+0

좋은 생각이다! 잠시 후 만료되는 여러 토큰 생성 ... 위대한 팁 주셔서 감사합니다! – olli

+0

@olli가 다음 단계로 나아가려면 recaptcha와 같은 것을 추가하고 싶을 것입니다. – Class

+0

나는 내 사이트의 일부 장소에서 recaptcha를 사용하는데, 보통 어디서나 내가 bruteforce 공격을 막고 싶을 뿐이다 ... 나는 CSRF를하기 위해 토큰을 bruteforce하는 것이 현실적으로 가능한 시나리오를 생각할 수 없었다. ? – olli

2

브라우저는 심지어 탭과 세션 ID가 동일해야 창 사이를 올바른 세션 ID를 유지해야합니다. (위험한 가정은 반드시 크로스 브라우저에서 테스트해야 함)

세션 ID를 기반으로 유효한 토큰을 더 생성하십시오.

이렇게하면 확인할 수 있습니다.

$tokenCorrect = false; 

foreach($_SESSION['tokens'] as $token) { 
    if ($token !== $_POST['token']) 
    continue; 
    $tokenCorrect = true; 
} 

if ($tokenCorrect == false) { 
    die(); // 
    // Maybe log to database ?? but watch if possible Denial of Service because somebody can write your disk/ shared diskspace full with only making fast requests with a invalid CSRF token 
} 
+0

좋은 생각, 고마워요! 클래스 구현은 훨씬 더 진보적입니다. 그래서 최선의 대답으로 선택했습니다 ... 그리고 제가 아는 한 세션 ID는 서버에서 생성되기 때문에 브라우저 탭간에 동일하게 유지됩니다 (테스트를 시작하기 전에 몇 가지 기본 사항을 이해하기 위해 테스트) 한 사용자를 식별하는 데 사용됩니다. – olli

+0

서버에서 세션이 생성된다는 사실은 true이지만 클라이언트가 해당 session_id없이 다시 요청하면 서버에서 새 세션이 생성됩니다. 새로운 윈도우가 열려있을 때 브라우저가 필요한 세션 ID를 거부 할 수 있으므로 테스트를해야하지만 파이어 폭스와 IE가 여기에 문제를 일으키지 않을 것임을 알고있다. –