내 웹 사이트의 양식에 보안을 추가하려고합니다. 양식 중 하나는 AJAX를 사용하고 다른 하나는 간단한 “문의하기”양식입니다. CSRF 토큰을 추가하려고합니다. 내가 가지고있는 문제는 토큰이 HTML “값”에 가끔 표시된다는 것입니다. 나머지 시간에는 값이 비어 있습니다. 다음은 AJAX 양식에서 사용중인 코드입니다.
PHP :
if (!isset($_SESSION)) {
session_start();
$_SESSION['formStarted'] = true;
}
if (!isset($_SESSION['token']))
{$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
}
HTML
<form>
//...
<input type="hidden" name="token" value="<?php echo $token; ?>" />
//...
</form>
어떤 제안?
답변
보안 코드의 경우 다음과 같이 토큰을 생성하지 마십시오. $token = md5(uniqid(rand(), TRUE));
rand()
예측 가능하다uniqid()
최대 29 비트의 엔트로피 만 더합니다.md5()
엔트로피를 추가하지 않고 결정 론적으로 혼합합니다.
이것을 시도하십시오 :
CSRF 토큰 생성
PHP 7
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['token'];
(!) 참고 : 하나의 내 고용주의 오픈 소스 프로젝트가 백 포트에 대한 이니셔티브 random_bytes()
와 random_int()
PHP 5 프로젝트에. MIT 라이센스가 있으며 Github 및 Composer에서 paragonie / random_compat 로 사용할 수 있습니다 .
PHP 5.3 이상 (또는 ext-mcrypt 사용)
session_start();
if (empty($_SESSION['token'])) {
if (function_exists('mcrypt_create_iv')) {
$_SESSION['token'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
} else {
$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
}
}
$token = $_SESSION['token'];
CSRF 토큰 확인
단지 사용하지 마십시오 ==
또는 ===
사용 hash_equals()
(PHP 5.6+ 만하지만과 이전 버전에서 사용할 해시의 compat 라이브러리).
if (!empty($_POST['token'])) {
if (hash_equals($_SESSION['token'], $_POST['token'])) {
// Proceed to process the form data
} else {
// Log this as a warning and keep an eye on these attempts
}
}
양식 별 토큰으로 더 나아 가기
을 사용하여 특정 양식에서만 사용할 수 있도록 토큰을 추가로 제한 할 수 있습니다 hash_hmac()
. HMAC는 더 약한 해시 함수 (예 : MD5)에서도 사용하기에 안전한 특정 키 해시 함수입니다. 그러나 대신 SHA-2 해시 함수 제품군을 사용하는 것이 좋습니다.
먼저 HMAC 키로 사용할 두 번째 토큰을 생성 한 다음 다음과 같은 논리를 사용하여 렌더링합니다.
<input type="hidden" name="token" value="<?php
echo hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
?>" />
그런 다음 토큰을 확인할 때 합동 작업을 사용합니다.
$calc = hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
if (hash_equals($calc, $_POST['token'])) {
// Continue...
}
한 양식에 대해 생성 된 토큰은 알지 못하면 다른 컨텍스트에서 다시 사용할 수 없습니다 $_SESSION['second_token']
. 페이지에 방금 놓은 토큰이 아닌 별도의 토큰을 HMAC 키로 사용하는 것이 중요합니다.
보너스 : Hybrid Approach + Twig Integration
Twig 템플릿 엔진 을 사용하는 사람은 누구나 Twig 환경에이 필터를 추가하여 단순화 된 이중 전략의 이점을 누릴 수 있습니다.
$twigEnv->addFunction(
new \Twig_SimpleFunction(
'form_token',
function($lock_to = null) {
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
if (empty($_SESSION['token2'])) {
$_SESSION['token2'] = random_bytes(32);
}
if (empty($lock_to)) {
return $_SESSION['token'];
}
return hash_hmac('sha256', $lock_to, $_SESSION['token2']);
}
)
);
이 Twig 함수를 사용하면 다음과 같이 범용 토큰을 모두 사용할 수 있습니다.
<input type="hidden" name="token" value="{{ form_token() }}" />
또는 잠긴 변형 :
<input type="hidden" name="token" value="{{ form_token('/my_form.php') }}" />
Twig는 템플릿 렌더링에만 관련됩니다. 여전히 토큰의 유효성을 올바르게 검증해야합니다. 제 생각에 Twig 전략은 최대의 보안 가능성을 유지하면서 더 큰 유연성과 단순성을 제공합니다.
일회용 CSRF 토큰
각 CSRF 토큰을 정확히 한 번만 사용할 수 있어야한다는 보안 요구 사항이있는 경우 가장 간단한 전략은 각 성공적인 유효성 검사 후에 토큰을 다시 생성합니다. 그러나 그렇게하면 한 번에 여러 탭을 탐색하는 사람들과 잘 섞이지 않는 모든 이전 토큰이 무효화됩니다.
Paragon Initiative Enterprises는 이러한 코너 케이스에 대해 Anti-CSRF 라이브러리 를 유지합니다 . 일회성 형식 별 토큰으로 만 작동합니다. 세션 데이터에 충분한 토큰이 저장되면 (기본 구성 : 65535) 가장 오래된 사용되지 않은 토큰이 먼저 순환됩니다.
답변
보안 경고 :
md5(uniqid(rand(), TRUE))
난수를 생성하는 안전한 방법이 아닙니다. 자세한 내용과 암호화 보안 난수 생성기를 활용하는 솔루션 은 이 답변 을 참조하십시오 .
if에 다른 것이 필요한 것 같습니다.
if (!isset($_SESSION['token'])) {
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
$_SESSION['token_time'] = time();
}
else
{
$token = $_SESSION['token'];
}
답변
변수 $token
가 세션에있을 때 세션에서 검색되지 않습니다.