Код токена PHP CSRF. Достаточная безопасность?

#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. Не могли бы вы процитировать текст, на который вы ссылаетесь, когда говорите о «если идентификатор сеанса просочился …»?