#php #sql #security #csrf
#php #sql #Безопасность #csrf
Вопрос:
Недавно защитив свой сайт как можно лучше от XSS, я сейчас нахожусь в процессе защиты от CSRF, посмотрев и прочитав несколько статей по этому вопросу, я создал приведенный ниже код.
Я хотел бы знать, корректна ли моя реализация при использовании строки в базе данных для обеспечения безопасности. Что-нибудь я должен делать по-другому?? Должен ли я проверять базу данных с обеих сторон???
Код:
if(!isset($_SESSION['register_token'])){
$keytype = 'register';
$getregisterkey = mysql_query("SELECT key FROM tokenkeys WHERE type='".$keytype."' ") or die(mysql_error());
while ($row = mysql_fetch_array($getregisterkey))
{
$registerkey = mysql_real_escape_string($row['key']);
};
$_SESSION['register_token']=sha1(uniqid(rand(), TRUE).$registerkey);
$_SESSION['register_token_time']=time();
}
<input type="hidden" name="token" value="<?php echo $_SESSION['register_token'];?>" />
if($_POST['register_token']==$_SESSION['register_token']){
$register_token_age=time()-$_SESSION['register_token_time'];
if($register_token_age=>300){
//process form
} else{
//valid token but expired
}
} else{
die('Access Forbidden')
}
Комментарии:
1. Почему вы избегаете вывода SQL-запроса? Знаете ли вы, что вообще делает mysql_real_escape_string?
Ответ №1:
Токены XSRF настолько безопасны, насколько безопасен канал, по которому отправляется страница. Используйте https
и только https
в этой форме и отправляйте ее только в https
конечную точку. В противном случае MITM может получить ваш токен XSRF из формы по мере его отправки или отправки.
while ($row = mysql_fetch_array($getregisterkey))
{
$registerkey = mysql_real_escape_string($row['key']);
};
никогда не будет выполняться при наличии нулевых строк, и в этом случае вы не получите много энтропии, $getregisterkey
когда вы позже это сделаете
$_SESSION['register_token']=sha1(uniqid(rand(), TRUE).$registerkey);
поэтому я бы позаботился о том, чтобы ваша реализация быстро завершилась с ошибкой, если будут возвращены нулевые строки. Возможно, измените на if ($row = mysql_fetch_array(...)) { ... } else { /* abort */ }
, поскольку вы не получаете никакой выгоды от дополнительных строк.
Он rand()
должен быть либо действительно случайным, либо криптографически надежным PRNG.
Я не знаком со стандартными библиотеками PHP, но [википедия] предполагает rand()
, что он не является криптографически надежным. википедия говорит
Есть предложения по добавлению в PHP надежной генерации случайных чисел.
Надежная криптография в PHP предполагает использование openssl_random_pseudo_bytes()
Не используйте rand() или mt_rand()
Чтобы сгенерировать криптографически надежное случайное число в PHP, вы должны использовать функцию
openssl_random_pseudo_bytes()
библиотеки OpenSSL.
Если вы используете слабую случайность, злоумышленник может наблюдать за генерируемыми вами числами (запрашивая несколько версий формы и анализируя скрытый ввод) и использовать это, чтобы выяснить, какими могут быть следующие числа, и подделать токены CSRF.
Если злоумышленник изменит свойство 'register_token_time'
сеанса, он сможет избежать ваших проверок XSRF.
Например, если у вас есть страница, которая
$_SESSION[$_POST['x']] = $_POST['y'];
затем злоумышленник может ОПУБЛИКОВАТЬ
x=register_tokenamp;y=pwnd
чтобы заменить register_token, сохраненный в сеансе, а затем отправить сообщение с
token=pwnd
и обойти вашу защиту XSRF.
Комментарии:
1. Принимая во внимание ваш ответ, должен ли я удалить подключение к базе данных или реализовать его другим способом? Что вы подразумеваете под $ _SESSION[$attackerControlledInput] = … должен ли я добавить что-то еще??
2. @user1002916, пожалуйста, посмотрите мои правки. Я попытался прояснить оба раздела.
3. я не понимаю вашу точку зрения. Если идентификатор сеанса утек из-за нарушения owasp a9, вам не нужно использовать CSRF, у вас уже есть весь сеанс, нет смысла использовать его. это чикен или яйцо.
4. Кроме того, нет, это не фиксация сеанса, это настройка пространства имен переменной сеанса. Фиксация сеанса — это когда злоумышленник создает новый идентификатор сеанса и обманом заставляет пользователя проходить аутентификацию с помощью этого идентификатора. Это должно быть предотвращено с помощью вашего php.ini cofnig.
5. @Rook, я думаю, ты прав насчет «фиксации сеанса». Я не думаю, что я когда-либо говорил об утечке сеанса, просто о способности злоумышленника предсказать токен CSRF. Не могли бы вы процитировать текст, на который вы ссылаетесь, когда говорите о «если идентификатор сеанса просочился …»?