Как я уже говорил в своих статьях – безопасность является важным компонентом любого сайта. Тем не менее, добавив безопасность можно увеличить нагрузку на сервер и в итоге замедлить загрузку страниц сайта. В этом уроке мы с Вами будем рассматривать общие проблемы, которые возникают при использовании Sessions и Cookies.
Cookies
Cookies – это удобное средство для пользователей сайта. Например, сайт создает Cookies с именем "favorite_color" и присваивает ему значение "red". Теперь каждый раз, когда пользователь будет заходить сайт, браузер будет загружать и устанавливать, что значение Cookies с именем "favorite_color" является"red". Для пользователей Cookies могут быть удобны, однако они могут создать серьезные дыры в безопасности. Когда происходит загрузка с Cookies, браузер автоматически отправляет их на сайт. Это было бы не очень страшно, если их нельзя было редактировать.
После недолгих поисков в Интернете, я нашел сайт с интересной панелью пользователя, которая работает на Cookies. Когда я оставил комментарий на странице сайта, сайт выдает мое имя с именем переменной Cookies. После использования нескольких методов (о них я не буду рассказывать, так как это можно считать взломом) мне удалось посмотреть эти Cookies. Если их можно открывать, значит их можно и редактировать. При редактировании можно изменить идентификатор пользователя на администраторский и захватить сайт.
// Легкая настройка Cookies в PHP set_cookie(имя, значение, срок действия, путь, домен, безопасность, только http); //Название это то, что ваши Cookies будут сохранены как. //Значение, которое будет храниться в куки. //Срок, когда ваши куки истекает (удаляется). //Путь — это место где Cookies будут доступны на сервере. //Домен, показывает к какому домену доступны Cookies. (Примечание: считается WWW www.example.com как субдомен example.com) //Безопасен, если Cookies будут переданы только через безопасное соединение SSL. //Только http – это обозначает, что Cookies будут отправлены только через HTTP. (Примечание: только для PHP 5.2 +, а также некоторых браузеров)
Sessions
Sessions являются переменными, которые хранят данные на сервере, для идентификации пользователя. В отличии от Cookies пользователи не могут напрямую их изменять, но есть и еще риски связанные с безопасностью. Существует две основные угрозы для Sessions – Сессия Фиксации и Сеанса.
Сессия Фиксации
Сессия фиксации – когда пользователь заходит на страницу уже с установленной Sessions и загружает свою информацию в этой сессии. Заходя уже в установленную Sessions злоумышленник может получить информацию, введенную пользователем. Простым примером является случай, когда Вы переходите по ссылке на страницу сайта, где уже установлена сессия. Эти ссылки могут выглядеть следующим образом, ?PHPSESSID=1234. Переходя по такой ссылке, злоумышленнику не составит труда подобрать PHPSESSID администратора сайта.
Сессия Сеанса
Сессия Сеанса второй вид риска. Эту сессию гораздо труднее защищать от злоумышленников. Сессия Сеанса – это сессия где злоумышленник может получить нужный ему идентификатор с помощью перехвата различными способами. Например, злоумышленник может быть подключен к Вашей локальной сети, и фильтровать переданные Вами данные. После того, как он получает идентификатор Сессии, он может легко получить доступ ко всей информации.
//Работать с Sessions довольно легко. Во-первых, что Вы должны сделать на каждой странице начиная сессию. session_start(); // После этого вы можете установить переменные для пользователей $_SESSION['username'] = "admin"; $_SESSION['website_url'] = "www.example.com"; echo $_SESSION['username']; // Происходит вывод сессии пользователя
Использование сессий эффективно
Кодирование сценария входа, в данном уроке мы рассматривать не будем. Но сейчас я покажу, как сделать свой сценарий входа более безопасным.
Использование Sessions, как правило, более безопасно, чем использование Cookies. Это потому, что пользователь не может изменить значения Sessions также легко, как пожжет изменить значение Cookies. Вот почему я рекомендую хранить все пользовательские переменные в Сессии Сеанса. Еще одна рекомендация, НИКОГДА НЕ ДОВЕРЯЙТЕ ПОЛЬЗОВАТЕЛЬСКОМУ ВВОДУ. Многие web-программисты хотят осуществить проверку правильного ввода данных пользователем и осуществить проверку ввода со значениями в базе данных MySql. Если Вы хотите это сделать, попробуйте изменить Ваш сценарий ввода на нечто похожее на следующую функцию:
function login($username, $password) { $sql = mysql_query("SELECT id, user_level FROM users WHERE password = ‘" . $password . "’ AND username = ‘" . $username . "’ LIMIT 1"); // Если нет совпадений, то пароль и Логин не принимаются if($sql === false) { return false; } else { while($u = mysql_fetch_array($sql)) { session_regenerate_id(true); $session_id = $u[id]; $session_username = $username; $session_level = $u[user_level]; $_SESSION['user_id'] = $session_id; $_SESSION['user_level'] = $session_level; $_SESSION['user_name'] = $session_username; $_SESSION['user_lastactive'] = time(); return true; } } }
Проанализируем, написанный выше код. Сначала принимается значение имени пользователя и пароля. Затем проверяется, есть ли пользователь, когда оба критерия соответствуют. Если функция возвращает ЛОЖЬ, то функция прекращает работу. Вместо return false, можно выводить предупреждение или что-то еще. В противном случае создаются переменные сессии, и происходит вывод соответствующих данных с базы MySql.
Теперь Вы можете быть полностью уверенны, что сессия session_regenerate_id(true) существует. Этот способ поможет нам защититься от Сессии Фиксации. Функция будет создавать каждый раз новый идентификатор сессии при авторизации пользователя. Другими словами, каждый раз при новой идентификации пользователя будет генерироваться новый, уникальный идентификатор, а также пользовательские данные будут добавлены в новую сессию. Все это возможно благодаря функции удаления старой сессии.
Функция запоминания
Cookies и Sessions не должны содержать паролей пользователей. Это прежде всего, потому что если угнали Cookies или Sessions Вы ж не хотите, чтобы угонщик имел доступ к учетной записи. Кроме того, как известно, многие пользователи ставят один пароль на все. Так как мы можем решить эту дилемму?
Решить эту проблему возможно с помощью auth_key. Аuth_key возможно связать имя пользователя и пароль с набором комбинаций, а затем зашифровать. Аuth_key также должен быть уникальным для каждого пользователя. Таким образом, когда установлены Cookies, установите auth_key, а затем проверяйте его со значение базы данных MySql. Давайте посмотрим, как это будет выглядеть.
function login($username, $password, $remember = false) { $sql = mysql_query("SELECT * FROM bio_users WHERE password = ‘" . $password . "’ AND username = ‘" . $username . "’ LIMIT 1"); // Если имя пользователя и пароль не совпадают if($sql === false) { return false; } else { while($u = mysql_fetch_array($sql)) { $this->account_active = true; //Проверяем, хочет ли пользователь запомнить данные в Cookies if($remember) { // Создаем новый ключ аутентификации для каждого пользователя (старые ключи не //могут быть использованы если угнали Cookies) $cookie_auth= rand_string(10) . $username; $auth_key = session_encrypt($cookie_auth); $auth_query = mysql_query("UPDATE users SET auth_key = ‘" . $auth_key . "’ WHERE username = ‘" . $username . "’"); setcookie("auth_key", $auth_key, time() + 60 * 60 * 24 * 7, "/", "example.com", false, true) } // Присваиваем переменные сессии session_regenerate_id(true); $session_id = $u[id]; $session_username = $username; $session_level = $u[user_level]; $_SESSION['user_id'] = $session_id; $_SESSION['user_level'] = $session_level; $_SESSION['user_name'] = $session_username; $_SESSION['user_lastactive'] = time(); return true; } } }
В данном случае проверка истинного параметра входа проверяется с помощью функции. Если имя пользователя и пароль совпадают, функция устанавливает маркеры для auth_key. Rand_string будет генерировать длину строки, которая прошла через нее. Session_encrypt шифрует с помощью MD5. Эта строка уникальна, поскольку использует имя пользователя. Однако этого моэет быть не достаточно для защиты Вашего сайта, так что можно рассмотреть вопрос о добавлении нескольких auth_key и Cookies. Но это не будет являться достаточно эффективным методом.
Ниже приведенная функция должна располагаться на каждой странице сайта. Ее целью является проверка значений Cookies для "auth_key". Если данные Cookies существуют, то она выберет соответствующего пользователя.
function initiate() { $logged_in = false; if(isset($_SESSION['user_name'])) { $logged_in = true; } // Проверка установлены ли Cookies if(isset($_COOKIE['auth_key'])) { $auth_key = safe_var($_COOKIE['auth_key']); if($logged_in === false) { // Выбор пользователя из базы данных $auth_key_query = mysql_query("SELECT username, password FROM users WHERE auth_key = ‘" . $auth_key . "’ LIMIT 1"); if($auth_key_query === false) { // Если ключ не относится к пользователю, удалить Cookies setcookie("auth_key", "", time() — 3600); } else { while($u = mysql_fetch_array($auth_key_query)) { // Выполнен вход в систему. login($u['username'], $u['password'], true); } } } else { setcookie("auth_key", "", time() — 3600); } } }
Эта функция проверяет существование Cookies. Если Cookies существует, то она будет проверять совпадение auth_key с пользователем. Если все в порядке, выводится необходимая информация, в противном случаи, Cookies удаляются.
Другие функции
function logout() { // Необходимо удалить ключ аутентификации по базе данных, Cookies не могут быть использованы $username = $_SESSION['user_name']; setcookie("auth_key", "", time() — 3600); $auth_query = mysql_query("UPDATE users SET auth_key = 0 WHERE username = ‘" . $username . "’"); // Если ключ аутентификации удаляется из базы данных, сбросить сессию (удалить сессию) if ($auth_query) { unset($_SESSION['user_id']); unset($_SESSION['user_level']); unset($_SESSION['user_name']);; unset($_SESSION['user_lastactive']); session_unset(); session_destroy(); return true; } else { return false; } } // Проверяем, если сессия остается активной function keepalive() { // Если сессия должна быть сохранена используйте мледующий код if(!isset($_COOKIE['auth_key']) { $oldtime = $_SESSION['user_lastactive']; if(!empty($oldtime)) { $currenttime = time(); // это эквивалентно 30 минутам $timeoutlength = 30 * 600; if($oldtime + $timeoutlength >= $currenttime){ // Установить последнее время входа нового пользователя $_SESSION['user_lastactive'] = $currenttime; } else { // Если сессия слишком долго была неактивна выполнить выход logout(); } } } }
Функция выхода. Данная функция выполняет выход пользователя при это м удаляются Cookies и Sessions, а установленные для пользователей auth_key, уже не могут быть использованы. Следует отметить, что Вы можете установить время сессии пользователя. Функция keepalive() должна быть включена на каждой странице сайта.
Заключение
Также вместо auth_key можно использовать IP адрес пользователя, но этого делать НЕ РЕКОМЕНДУЕТСЯ. У некоторый интернет провайдеров нет статических IP адресов. Если Вы сделаете это проверку, попросту пользователь не сможет заходить на сайт. На этом закончим урок. Защищайте свои приложения.