Я переоцениваю свою безопасность СЕССИЙ? - PullRequest
6 голосов
/ 24 августа 2011

Для того, чтобы обезопасить мою страницу СЕССИИ, у меня есть следующие страницы.

Мои вопросы

  1. Я чрезмерно реагирую на это?
  2. Должен ли я поместить токен в login.php вместо loginForm.php?
  3. Когда пользователь входит в систему, я сохраняю его IP в БД. Должен ли я использовать это в аутентификации?

Спасибо, сообщество.

Форма входа loginForm.php

$token = md5(uniqid(rand(),TRUE));
<input name="login" type="text" class="textfield" id="login" />
<input name="password" type="password" class="textfield" id="password" />
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="submit" name="Submit" value="Login" />

Когда пользователь входит в систему login.php

$fingerprint = sha1('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT'].$_SERVER['REMOTE_ADDR'].$_POST['token']);
    session_regenerate_id();
    $member = mysql_fetch_assoc($result);
$_SESSION['SESS_MEMBER_ID'] = $member['member_id'];
$_SESSION['SESS_TOKEN'] = $_POST['token'];
$_SESSION['SESS_FINGERPRINT'] = $fingerprint;
session_write_close();
    header("location: index.php");
    exit();

Аутентификация на каждой странице auth.php

    session_start();
    $fingerprint = sha1('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT'].$_SERVER['REMOTE_ADDR'].$_SESSION['SESS_TOKEN']);
    if( !isset($_SESSION['SESS_MEMBER_ID']) || (trim($_SESSION['SESS_MEMBER_ID']) == '')  || ($_SESSION['SESS_FINGERPRINT'] != $fingerprint) || !isset($_SESSION['SESS_TOKEN']) || (trim($_SESSION['SESS_TOKEN']) == '') ) {
        header("location: denied.php");
        exit();
    }

Ответы [ 2 ]

4 голосов
/ 25 августа 2011

Чтобы ответить на ваши топ-3 вопроса:

  1. Чрезмерно ли я реагирую на это?

    Нет.Нарушено управление сеансами: число 3 в Список 10 самых уязвимых мест OWASP .Есть несколько проблем с вашей реализацией, но в целом это хорошая идея.

  2. Должен ли я поместить токен в login.php вместо loginForm.php?

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

  3. Когда пользователь входит в систему, я сохраняю его IP в БД.Должен ли я использовать это в аутентификации?

    Нет.Пользователи будут часто входить в систему с нескольких компьютеров.Нет никакого IP-> пользовательского сопоставления, которое действительно будет возможно.IP-> сопоставление сеансов может работать лучше, но не забывайте, что за динамическим IP-адресом стоит значительное число пользователей, поэтому оно может быть ненадежным даже для сеансов.

ИВот несколько комментариев к самому вашему коду:

  • Генерация токена. Прямо сейчас вы используете следующий алгоритм:

    $token = md5(uniqid(rand(),TRUE));
    

    Я бы лично изменил это на что-то более случайное и безопасное.Что-то вроде:

    $token = md5(uniqid(mt_rand() . mt_rand(), true);
    

    Или, если у вас установлен mcrypt, я бы сделал это вместо этого:

    $token = md5(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
    

    Причина в том, что обе эти функции имеют значительно большую энтропию(это означает, что они будут генерировать большое количество уникальных значений), и злоумышленнику будет сложнее угадать.

  • Отпечаток пальца. Прямо сейчас выВы делаете:

    $fingerprint = sha1(
        'SECRET-SALT' . 
        $_SERVER['HTTP_USER_AGENT'] . 
        $_SERVER['REMOTE_ADDR'] . 
        $_POST['token']
    );
    

    Есть несколько проблем с этим.Во-первых, динамические IP-адреса сделают сеанс недействительным.Во-вторых, нет никакой реальной причины хэшировать эти данные.Сохраните каждый как отдельное поле, а затем проверьте их индивидуально.Это может помочь предотвратить определенную теоретическую атаку, когда пользователь с другим удаленным IP-адресом может создать поддельный токен и идентификатор пользователя, который приводит к тому же хешу (и, следовательно, способен «взломать» отпечаток пальца).В-третьих, вы используете введенный токен для идентификации данных.Это может привести к фиксации сеанса * атакам в стиле 1052 *.

    Я бы предложил сохранить каждый фрагмент информации в отдельной переменной сеанса и проверить их по отдельности.Кроме того, используйте токен сеанса, который вы сгенерировали по предыдущему запросу, и только проверяйте, соответствует ли опубликованный токен тому, который вы сохранили.

  • Проверка сеанса. Этодовольно хорошо там.Я бы предложил перенести его в отдельную функцию, чтобы его можно было легко изменить, если вам нужно изменить алгоритм.Таким образом, вы просто позвоните:

    require_once 'session.php';
    verifySession();
    

    Вверху каждого файла ...

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

1 голос
/ 24 августа 2011

Первое, что вы должны сделать, это управлять захватом сессии . Это означает session_regenerate_id(), когда пользователь входит / выходит. После этого вам следует рассмотреть возможность использования https .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...