Предотвращение выхода из системы из ненадежных источников в PHP - PullRequest
5 голосов
/ 01 марта 2011

У меня есть действие на моем сайте:

http://mysite.com/User/Logout

Это приведет к выходу текущего пользователя из сеанса. Поскольку это простой запрос GET, злоумышленник может либо создать ссылки на эту страницу, либо даже поместить эту ссылку в атрибут src изображения, который вынудит пользователей выйти из системы. Я все еще хотел бы сохранить простоту ссылки выхода из системы, не заходя слишком далеко, но в то же время я хотел бы иметь возможность предотвратить возникновение описанного выше сценария.

Есть идеи?

Ответы [ 6 ]

5 голосов
/ 01 марта 2011

Ну, есть несколько вариантов защиты от CSRF-атак:

  1. Используйте форму и случайный токен.Поэтому вместо «ссылки» используйте случайный токен, который устанавливается в сеансе в форму

    <form action="/User/logout" method="post">
        <submit name="logout" value="Logout" />
        <input type="hidden" name="token" value="<?php echo getSessionToken(); ?>" />
    </form>
    

    Обратите внимание, что POST лучше всего подходит для этого типа действий, но вы можете изменить форму на GETбез особых проблем.

    Затем в php просто выполните:

    if (getSessionToken(true) != $_POST['token']) {
        die('CSRF!');
    }
    

    Обратите внимание, что getSessionToken должно работать примерно так:

    function getSessionToken($reset = false) {
        if (!isset($_SESSION['random_token'])) {
            $_SESSION['random_token'] = sha1(uniqid(mt_rand(), true));
        }
        $token = $_SESSION['random_token'];
        if ($reset) {
            unset($_SESSION['random_token']);
        }
        return $token;
    }
    

    Также обратите внимание, что всякий раз, когда вы получаете токенчтобы проверить это, вы должны сбросить его на что-то новое (что и делает).Это предотвращает повторные атаки, когда злоумышленник обнаруживает токен при отправке и повторно отправляет значение.

  2. Если необходимо использовать ссылку, вставьте токен в ссылку.Но обратите внимание, что это более подвержено атаке, так как есть вероятность, что пользователь может скопировать и вставить ссылку кому-то еще.Пока это токен с самовозвратом, не должно быть особых проблем с несколькими вкладками.Но поймите, что это не оптимально:

    <a href="/User/logout?token=<?php echo getSessionToken(); ?>">Logout</a>
    

    Это абсолютно лучше, чем ничего.Но я бы все же предложил использовать форму для лучшей защиты.

Я бы высоко предложил прочитать и следовать Рекомендациям OWASP CSRF для предотвращенияCSRF.Он расскажет вам почти все, что вам нужно знать, и почему ...

5 голосов
/ 01 марта 2011

Если вы выйдете из системы с помощью GET-запросов (или в этом отношении сделаете что-то более важное, чем GET-запросы), то ваш веб-сайт будет уязвим для атак подделки межсайтовых запросов. Вы должны использовать POST для выхода из системы. GET предназначен только для идемпотентных действий, см. RFC 2616, раздел 9.1 .

.

Имейте в виду, что, хотя использование GET в этом случае не соответствует RFC, это не все, что вам нужно изменить, чтобы предотвратить XSRF. См. этот ответ от ircmaxell для превосходного объяснения.

0 голосов
/ 07 апреля 2017

Полагаю, я опоздал на вечеринку, но вот как я справлюсь:

<?php

session_start();

function logoutButton($name = 'logout', $action = '/User/logout'){
$random_token = md5(uniq_id());
$_SESSION['csrf'] = $random_token;
$form = '<form ><input type="hidden" value="'. $random_token .'" name="' .$name. '"><input type="button" value="logout"><</form>';
return $form;
}

public static isValidRequest($name = 'logout'){
if(isset($_POST[$name]) && $_POST[$name] === $_SESSION['csrf']){
    return true;
}
return false;
}

}
?>

для отображения кнопки выхода из системы

echo logoutButton();

Для безопасного выхода из системы пользователя

if(isValidRequest()){
    //logout
}

Надеюсь, это кому-нибудь пригодится.

edit: вот класс, который я создал https://github.com/sahithvibudhi/PHP-CSRF-Protection-class

0 голосов
/ 01 марта 2011

Вам потребуется, чтобы какой-то валидатор был передан на страницу выхода из системы. И это должно быть увлекательно, что уникально для сессии и трудно угадать. Теперь, если бы только было подходящее значение ..... о да, идентификатор сеанса.

Обратите внимание, что вы должны использовать куки для управления сеансом, и вы должны установить флаг только для http в куки сеанса - поэтому вам нужно заполнить ссылку из PHP (или copy сеанс идентификатор в javascript-файле, доступном для чтения).

<?php
   session_start();
   if ($_GET['logout_valid']!==session_id()) {
       // handle invalid logout request
       exit;
   } else {
       $_SESSION=array();
       session_destroy();
   }
0 голосов
/ 01 марта 2011

Переписать, чтобы читать как / Выход? # NONCE #, # NONCE # - значение, которое вы изменяете от запроса к запросу.

0 голосов
/ 01 марта 2011

Не изменяя метод HTTP, вы можете добавить уникальный идентификатор в сеанс пользователя и добавить его в ссылку выхода из системы. Если действие выхода из системы выполнено и оба идентификатора совпадают, выход будет действительным. Иначе это не так!

...