Безопасность сеанса PHP

125

Каковы некоторые рекомендации по обеспечению ответственной безопасности сеанса с помощью PHP? Информация есть по всему Интернету, и самое время собрать всю информацию в одном месте!

saint_groceon
источник

Ответы:

88

Чтобы обеспечить безопасность сеанса, нужно сделать несколько вещей:

  1. Используйте SSL при аутентификации пользователей или выполнении конфиденциальных операций.
  2. Повторно генерировать идентификатор сеанса при изменении уровня безопасности (например, при входе в систему). Вы даже можете восстанавливать идентификатор сеанса при каждом запросе, если хотите.
  3. Тайм-аут сессий
  4. Не использовать глобальные регистры
  5. Храните данные аутентификации на сервере. То есть не отправляйте такие данные, как имя пользователя, в cookie.
  6. Проверьте файл $_SERVER['HTTP_USER_AGENT']. Это добавляет небольшой барьер к захвату сеанса. Вы также можете проверить IP-адрес. Но это вызывает проблемы для пользователей, которые меняют IP-адрес из-за балансировки нагрузки при нескольких подключениях к Интернету и т. Д. (Что имеет место в нашей среде здесь).
  7. Заблокируйте доступ к сеансам в файловой системе или используйте настраиваемую обработку сеансов
  8. Для конфиденциальных операций рассмотрите возможность потребовать от пользователей, вошедших в систему, повторно предоставить данные для аутентификации.
Grom
источник
15
Использование SSL только для некоторых операций недостаточно, если у вас нет отдельных сеансов для зашифрованного и незашифрованного трафика. Если вы используете один сеанс через HTTPS и HTTP, злоумышленник украдет его при первом запросе, отличном от HTTPS.
Kornel
6
-1 пользовательский агент легко подделать. То, что вы описываете, является пустой тратой кода и не является системой безопасности.
ладья
24
@The Rook, это может быть тривиальный барьер (злоумышленник может захватить пользовательский агент жертвы, используя свой собственный сайт) и полагается на безопасность через неясность, но это все еще один дополнительный барьер. Если пользовательский агент HTTP изменится во время использования сеанса, это будет крайне подозрительно и, скорее всего, станет атакой. Я никогда не говорил, что вы можете использовать его в одиночку. Если вы объедините его с другими методами, вы получите гораздо более безопасный сайт.
grom
5
@grom Я думаю, это все равно, что приклеить кусок скотча к двери и сказать, что это предотвратит проникновение людей.
ладья
8
Если вы проверяете пользовательский агент, вы блокируете все запросы от пользователей IE8, когда они переключают режим совместимости. Посмотрите, как я отследил эту проблему в моем собственном коде: serverfault.com/questions/200018/http-302-problem-on-ie7 . Я беру проверку пользовательского агента, потому что это такая тривиальная вещь, чтобы подделать, как говорили другие.
bestattendance
15

Одна из рекомендаций - вызывать session_regenerate_id каждый раз, когда изменяется уровень безопасности сеанса. Это помогает предотвратить захват сеанса.

saint_groceon
источник
11

Мои два (или более) цента:

  • Не доверять никому
  • Фильтр ввода, escape-вывод (cookie, данные сеанса также являются вашим вводом)
  • Избегайте XSS (держите свой HTML в правильном формате, взгляните на PHPTAL или HTMLPurifier )
  • Глубокая защита
  • Не раскрывать данные

По этой теме есть небольшая, но хорошая книга Криса Шифлетта Essential PHP Security .

Основная безопасность PHP http://shiflett.org/images/essential-php-security-small.png

На домашней странице книги вы найдете несколько интересных примеров кода и примеры глав.

Вы можете использовать упомянутую выше технику (IP и UserAgent), описанную здесь: Как избежать кражи личных данных

takeshin
источник
+1 за XSS-предотвращение. Без этого невозможно защититься от CSRF, и, таким образом, кто-то может «оседлать» сеанс, даже не получив его идентификатора.
Kornel
11

Я думаю, что одна из основных проблем (которая решается в PHP 6) - это register_globals. Сейчас один из стандартных методов, которых следует избегать, register_globals- использовать массивы $_REQUEST, $_GETили $_POST.

«Правильный» способ сделать это (начиная с 5.2, хотя там немного глючит, но стабильно с 6, которая скоро появится) - использовать фильтры .

Так что вместо:

$username = $_POST["username"];

вы бы сделали:

$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

или даже просто:

$username = filter_input(INPUT_POST, 'username');
cmcculloh
источник
2
Это вообще не имеет отношения к вопросу.
The Pixel Developer,
5
В самом деле? Тогда почему в принятом ответе они упоминают не использовать глобальные регистры? Разве, с точки зрения большинства рядовых разработчиков, регистрация глобальных переменных и обработка переменных формы не подпадают под действие «сеансов», даже если они технически не являются частью объекта «сеанс»?
cmcculloh
9
Я согласен, это не полностью отвечает на вопрос, но это определенно ЧАСТЬ ответа на вопрос. Опять же, это конкретизирует пункт в принятом ответе: «Не использовать глобальные переменные регистров». Это говорит о том, что делать вместо этого.
cmcculloh
5

По моему опыту, использование IP-адреса - не лучшая идея. Например; В моем офисе два IP-адреса, которые используются в зависимости от нагрузки, и мы постоянно сталкиваемся с проблемами при использовании IP-адресов.

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

Эрик Лэмб
источник
3

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

Вот хороший учебник по setTimer () и clearTimer ().

helloandre
источник
3

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

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

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

Джон Дауни
источник
3

Я настраиваю свои сеансы так:

на странице входа:

$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);

(фраза определена на странице конфигурации)

затем в заголовке, который находится на всем остальном сайте:

session_start();
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR'])) {       
    session_destroy();
    header('Location: http://website login page/');
    exit();     
}
Чад
источник
3

php.ini

session.cookie_httponly = 1
change session name from default PHPSESSID

eq Apache добавить заголовок:

X-XSS-Protection    1
user956584
источник
httpd.conf -> <FilesMatch "\. (php | phtml | aspx | htm | html) $"> Набор заголовков X-XSS-Protection "1" </FilesMatch>
user956584
Имейте в виду, что X-XSS-Protectionэто вообще бесполезно. Фактически, сам алгоритм защиты может быть использован, делая его хуже, чем раньше.
Pacerier
2

Я бы проверил как IP, так и User Agent, чтобы узнать, меняются ли они

if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
    || $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
{
    //Something fishy is going on here?
}
Teifion
источник
5
IP может изменяться законно, если пользователь находится за фермой прокси с балансировкой нагрузки.
Kornel
2
А user_agent может меняться каждый раз, когда пользователь обновляет свой браузер.
Скоттс,
3
@scotts Я согласен с IP-частью, но для обновления браузера вы должны установить сеанс при входе в систему, поэтому я не вижу, как они обновят свой браузер, не создавая новый сеанс после повторного входа в систему.
JasonDavis,
Я считаю, что user_agent также может измениться при переключении между режимами совместимости в IE8. Также очень легко подделать.
Да, но как насчет пользователей, у которых был статический IP-адрес GSM, который меняется каждые полчаса. Итак, сохраненный IP в сеансе + имя хоста, КОГДА IP! = REMOTE_ADDR проверяет хост и сравнивает хосты eq. 12.12.12.holand.nl-> когда holand.nl == true. Но у какого-то хоста было имя хоста на основе IP. Тогда нужно сравнить маску 88.99.XX.XX
user956584
2

Если вы используете session_set_save_handler (), вы можете установить свой собственный обработчик сеанса. Например, вы можете хранить свои сеансы в базе данных. Обратитесь к комментариям php.net за примерами обработчика сеанса базы данных.

Сеансы БД также хороши, если у вас несколько серверов, в противном случае, если вы используете сеансы на основе файлов, вам нужно будет убедиться, что каждый веб-сервер имеет доступ к одной и той же файловой системе для чтения / записи сеансов.

ejunker
источник
2

Вы должны быть уверены, что данные сеанса в безопасности. Посмотрев на свой php.ini или используя phpinfo (), вы можете найти настройки сеанса. _session.save_path_ сообщает вам, где они сохранены.

Проверьте разрешение папки и ее родителей. Он не должен быть общедоступным (/ tmp) или быть доступным для других веб-сайтов на вашем общем сервере.

Предполагая, что вы все еще хотите использовать сеанс php, вы можете настроить php для использования другой папки, изменив _session.save_path_, или сохранить данные в базе данных, изменив _session.save_handler_.

Вы можете быть в состоянии установить _session.save_path_ в вашем php.ini (некоторые провайдеры позволяют это) или для апача + mod_php, в файле .htaccess в корневой папке сайта: php_value session.save_path "/home/example.com/html/session". Вы также можете установить его во время выполнения с помощью _session_save_path () _.

Ознакомьтесь с руководством Криса Шифлетта или Zend_Session_SaveHandler_DbTable, чтобы установить альтернативный обработчик сеанса.

Dinoboff
источник