Механизм предотвращения CSRF PHP

Я прочитал много статей о CSRF, почти все они имеют одно и то же решение, которое представляет собой скрытые токены, поэтому я написал код для предотвращения CSRF, а затем попытался взломать свою собственную страницу, но это не сработало, я хотел бы знать, если мой код пуленепробиваемый CSRF, и если вокруг него вообще что-то есть.

у меня есть четыре страницы, на которых есть формы, поэтому на каждой странице я бы написал следующее:

            if (isset($_POST['submit'])){

            // Check for CSRF token
            if ($_SESSION['token'] === $_POST['token']){

                // write to db

            }else{
                 // CSRF attack has been detected
                 die("CSRF :<br>1: $_SESSION[token]  <br> 2: $_POST[token]");

            }

        }else{
            // assign CSRF prevention token
            $form_token = md5((rand(1,89412) * 256 / 4).$date.time());
            $_SESSION['token'] = $form_token;
        }
        ?>
        <form action='' method='post'>
        <input type='hidden' name='token' value='<?echo $form_token;?>'>

будет ли этого метода достаточно, чтобы помешать злоумышленникам использовать CSRF на моем веб-сайте?

Большое спасибо.


person user2585384    schedule 08.09.2013    source источник
comment
Это предотвращает публикацию слепых или автоматических форм... это всего лишь одна часть предотвращения атак. Ваша сессия (идентификатор) также должна быть безопасной, чтобы ее нельзя было взломать — то же самое относится и к файлам cookie сеанса.   -  person djot    schedule 08.09.2013
comment
означает ли это, что мой веб-сайт все еще уязвим для CSRF? если да, то как я могу предотвратить это.   -  person user2585384    schedule 08.09.2013
comment
Ну, я не эксперт по безопасности ... но если мне удастся перехватить идентификатор сеанса вашего/пользователя, токен формы будет бесполезен.   -  person djot    schedule 08.09.2013
comment
Спасибо, Джот, за быстрый ответ. Могу ли я что-нибудь еще сделать, чтобы обезопасить свои сеансы, а не постоянно использовать https?   -  person user2585384    schedule 08.09.2013
comment
Регенерировать сеанс, когда пользователь входит/выходит, получает более высокие привилегии и т. д. (php.net/manual/en/function.session-regenerate-id.php). Лучше всего не использовать стандартные сеансы, которые могут быть уязвимы на виртуальном хостинге (php.net/manual/en/function.session-set-save-handler.php). Попробуйте хешировать + соль данных везде, где это применимо (пароли и т. д.)   -  person djot    schedule 08.09.2013
comment
Спасибо @djot, ваш вклад был очень полезен.   -  person user2585384    schedule 08.09.2013
comment
@ user123 Ну, у меня те же проблемы ... и, к сожалению, это не одна строка ... У меня есть все эти 3 части ... зашифрованные сеансы в базе данных, я регенерирую свой идентификатор сеанса, у меня есть зашифрованные файлы cookie (или нет данные в них), хешированные и соленые пароли (и другие соответствующие данные), я никогда не доверяю пользовательскому вводу и, да, токенам в веб-формах ... но я все равно чувствую себя небезопасно. (Если сервер взломают, вы все равно пропали)   -  person djot    schedule 08.09.2013


Ответы (1)


Я покажу вам свой код для предотвращения CSRF:

config.php
Файл конфигурации должен автоматически загружаться на каждой странице с помощью функций require или include.
Лучше всего написать класс конфигурации (я просто запишу функции, чтобы упростить код).

session_start();

if(empty($_SESSION['CSRF'])){
        $_SESSION['CSRF'] = secureRandomToken();
    }

post.php
Это всего лишь пример. На каждой странице «сообщения» вы должны проверить, установлен ли токен CSRF. Пожалуйста, отправляйте свои формы методом POST! Я также рекомендую вам взглянуть на Slim Framework или Laravel Lumen, они предоставляют отличную систему маршрутизации, которая позволит вам очень легко принимать POST-запросы только на вашей странице "post.php" (они также автоматически добавит токен CSRF в каждую форму).

if (!empty($_POST['CSRF'])) {
    if (!hash_equals($_SESSION['CSRF'], $_POST['CSRF'])) {
        die('CSRF detected.');
    }
}else{
    die('CSRF detected.');
}

view.php
Теперь вам просто нужно поместить в него скрытый ввод со значением вашего сеанса CSRF.

<input type="hidden" name="CSRF" value="<?= $_SESSION['CSRF'] ?>">

Я надеюсь, что это краткое объяснение может помочь вам :)

person Michele Riva    schedule 15.02.2017