Сессии PHP + Useragent с солью

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

$fingerprint = md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']);

Соль затруднит атакующему захват или что-то еще. Но ПОЧЕМУ добавьте соль каждый раз, когда вы проверите ее так:

md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']) == $_SESSION [ 'fingerprint' ]

Итак, ПОЧЕМУ соль сделала бы ее более безопасной, так как злоумышленнику по-прежнему нужен только useragent (который относительный небольшой набор разных пользовательских атак) и sessionid?

Наверное, что-то маленькое, я не замечаю, но не могу понять это, сводит меня с ума ха-ха

Спасибо!

Ответ 1

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

В приведенном выше примере да, если у злоумышленника есть как "отпечаток пальца", так и агент "Пользователь", они смогут захватить сеанс.

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

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

define('SESSION_IDHASH', md5($_SERVER['HTTP_USER_AGENT'] . $this->fetch_substr_ip($registry->alt_ip))); // this should *never* change during a session

Кроме того, хэш-сессия сеанса создается с использованием

md5(uniqid(microtime(), true));

Они проверяются при попытке идентифицировать сеанс

Итак, чтобы захватить сеанс, человеку нужно знать следующие

  • Время (точно) на сервере при создании сеанса
  • Строка агента браузера пользователей
  • IP-адрес пользователя

Они также должны были бы обмануть IP-адрес (или, по крайней мере, первые 2/3 октета), чтобы это сделать.

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

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

Например, во что-то, что я сейчас пишу в python, я генерирую хэш для использования с защитой XSRF. Следующее - это то, что я использую.

    self.key = sha1(
        self.user.username +
        self.user.password +
        settings.SECRET_KEY +
        strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())
    ).hexdigest()

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

Ответ 2

Если вы находитесь на своем собственном сервере, шифрование переменных сеанса бессмысленно, потому что они не выходят из сервера. См. Линейный ответ Что мне нужно сохранить в php-сеансе при входе пользователя? для получения дополнительной информации. Если вы находитесь на общем сервере, вам может потребоваться зашифровать все переменные сеанса, помимо идентификатора сеанса, поскольку они хранятся в файлах temp, доступных для чтения на том же веб-сервере, что и все ваши соседи.

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

Некоторые примеры риска для ваших сеансов:

  • Сервер отправляет идентификатор сеанса в URL-адрес, а ваш пользователь следует за ссылкой на badguys.com. Они получат в переменных сервера референт (полный URL-адрес, включая идентификатор сеанса), браузер и IP-адрес вашего пользователя, Если вы не проверяете IP-адреса или ваш пользователь использует открытый прокси-сервер, им нужно только установить такую ​​же версию браузера, вставить URL-адрес, и все будет сделано.
  • Пользователь переходит на общедоступный ПК, регистрируется и уходит, не закрывая сеанс (эй, он человек в конце концов). Следующий парень в строке открывает браузер, проверяет историю и находит открытый сеанс. Тьфу.

Итак, некоторые меры, которые вы можете предпринять, по моему обычному предпочтению:

  • Не отправляйте идентификатор сеанса в URL-адрес; включить session.use_only_cookies в PHP. Минусы: пользователю необходимо включить файлы cookie.
    • Об опасных действиях (смените пароль, сделайте заказ...), снова попросите пароль. Вы можете делать это периодически тоже. Минусы: Раздражающе.
    • Тайм-ауты быстро. Минусы: в большинстве сайтов это заставит пользователей часто входить в систему, раздражая их.
    • Использовать SSL (только для того, чтобы избежать атаки "человек в середине" ). Минусы: Медлен. Глупые сообщения браузера. Нужен SSL на сервере.
    • Проверьте IP. Минусы: Неэффективно для посетителей, использующих общедоступный прокси. Раздражает динамические IP-адреса.
    • Проверьте агент пользователя (браузер). Минусы: почти бесполезно, UA легко получить и тривиально подражать.

(Я считаю, что у вас еще есть PHP, настроенный для максимальной безопасности).

Некоторые более экстремальные меры:

  • Поддерживать постоянное соединение между сервером и браузером, например. используя апплет Java. Нет связи, нет сеанса. Минусы: пользователю нужны Java, ActiveX или все, что вы используете. Сессия закрывается браузером (это может быть хорошо). Не работает на очень медленных соединениях. Более высокая загрузка на сервере. Вам нужно открыть порты, иметь специальный сервер для апплета.
  • То же самое, но используя асинхронные запросы (например, AJAX), чтобы очень часто обновлять сеанс и очень короткий тайм-аут. Или обновить скрытый IFRAME. Минусы: пользователю нужен JavaScript. Не работает на очень медленных соединениях. Более высокая загрузка на сервере.
  • То же самое, но перезагрузка всей страницы. Минусы: пользователю нужен JavaScript. Автоматическая перезагрузка при чтении страницы очень раздражает.

В некоторых случаях вы можете забыть о сеансах и вместо этого использовать аутентификацию Apache. Самое простое решение, но множество ограничений.

Ответ 3

Если я правильно понимаю, вы хотите предотвратить захват сеанса удаленным злоумышленником, который угадывает идентификаторы сеанса?

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

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

Я не верю, что сохранение пользовательского агента обеспечивает достаточную дифференциацию. Лучше было бы генерировать более высокий идентификатор (с большим количеством бит) во время начала сеанса (возможно, sha1 текущая отметка времени + имя пользователя + пользовательский агент + что-то), затем сохраните это в файле cookie, а также в сеансе и сопоставьте его с каждым дополнительным запросом. Это не сильно меняет вектор атаки (вам все равно нужно угадать некоторое число), но его легко значительно увеличить количество бит, которое должно быть угадано для успешной атаки там, значительно увеличивая сложность атаки.

Ответ 4

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

Ответ 5

Я также делаю это для частично защищать от атак сеансов подписи. Вам также необходимо указать IP-адрес.

Имейте в виду, что когда клиентский браузер автоматически обновляет агент пользователя, и вы подумаете, что его сеанс был захвачен;)

Ответ 6

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

Ответ 7

Помните, что если вы это сделаете, вы заставляете людей заходить снова, если они обновляют свой браузер. Это может быть ОК, но просто убедитесь, что это ваши намерения.

Использование удаленного адреса пользователя также не является проблемой. Многие люди используют один и тот же компьютер из разных мест. Мобильные устройства, ноутбуки используются дома и на работе, ноутбуки используются в горячих точках Wi-Fi и так далее. ИМХО это плохая идея использовать IP-адрес таким образом, что для нового IP-адреса требуется логин , если вы не имеете дело с высокочувствительной информацией, например, онлайн-банкинг. Это тот случай?

Что вас беспокоит? Внешняя атака? Или в ситуации совместного хоста, что кто-то может прочитать вашу информацию о сеансе?

Если это последнее, решение прост: просто не храните ничего чувствительного в сеансе. Все важные данные должны храниться в базе данных.

С точки зрения создания секретной соли, вам нужно использовать что-то, что нельзя догадаться. Я бы выбрал нечто вроде случайной строки, созданной при создании пользователя. При необходимости воссоздайте его каждый раз, когда сеанс недействителен.

Что касается того, что сделало бы его более безопасным, вы сказали бы это сами: существуют ограниченные строки пользовательских агентов (менее сотни, вероятно, будут охватывать 99,99% пользователей). Соль просто увеличивает количество возможностей. При этом, если вы используете ту же соль для всех сеансов, то это только вопрос времени, прежде чем он будет найден с грубой силой.

Ответ 8

Хорошо, например, я использую следующий вымышленный код:

<?php

// The sessionid cookie is now a certain hash
if ( array_key_exists ( $_COOKIE [ 'sessionid' ] ) )
{
    // Get the session from database
    $db_sessid = $pdo -> getStuff ( 'session_database', $_COOKIE [ 'sessionid' ] );

    if ( $db_sessid !== null && $db_sessid [ 'fingerprint' ] == sha1 ( 'SOMESALT' . $_SERVER [ 'HTTP_USER_AGENT' ] ) )
    {
        set_cookie ( ... ); // New sessionid and write also to DB

        // User is now logged in, execute some user stuff
    }
    else
    {
        // Session doesn't exist, or the fingerprint does not match
    }
}

Теперь злоумышленнику все еще нужен sessionid, который находится в файле cookie (отправленном по HTTP-заголовкам) и useragent. Так что еще вопрос дополнительной соли?

Проверка на IP также, на мой взгляд, не такая хорошая опция, некоторые провайдеры или прокси меняют их каждый отдельный запрос.

Спасибо, пока (-: