Работа с файлами сессий и cookies в PHP и MYSQL 

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

Файлы Cookie

Файлы Cookies – способы идентификации пользователя сайтом. Например, сайт создаёт файл cookie с именем: “favorite_color” и значением: “red”. С этого момента всякий раз при посещении сайта будет загружаться файл cookie, и устанавливать, что ваш любимый цвет – красный (“favorite_color” is “red). Это довольно удобно, так как пользователю не приходится каждый раз регистрироваться в системе при посещении сайта. Этот метод используется также в опции “Remember Me”, которая встречается на многих сайтах. Однако этот способ также может создать серьёзные бреши в системе безопасности сайта.

Один пример не подтверждает, какой именно файл cookie вернётся на ваш сайт. После несложного поиска я нашёл веб-сайт со сценарием панели пользователя. Данный сценарий вывел все мои данные входа в систему в файлах cookie и загружал значения каждый раз во время выполнения действия. Например, если я оставлял комментарий, система выдавала любое из моих имён из переменной имён файла cookie. Далее, используя расширение firebug и пару других устройств, я мог не только просматривать эти файлы, но также и редактировать их. Таким образом, всякий раз, когда я редактировал файл cookie содержащий моё имя, сайт не подтверждал правильность имени, а выводил данные. Также я мог изменять свой ID. В конечном итоге я смог найти ID администратора (001) и получить доступ на правах администратора.

<?php
		set_cookie(name, value, expiration, path, domain, secure, http_only);
?> 

Сессии

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

Фиксация сессии

Фиксация сессии происходит, когда пользователи подключаются к уже установленной сессии и загружают туда свою информацию. Посредством входа в уже установленную сессию злоумышленник может посетить данную сессию и получить информацию, введённую пользователями. Простой пример - пройти по ссылке на веб-сайт с уже установленным идентификатором сессии (session ID). Например, http://www.example.com/?PHPSESSID=1234. Теперь для просмотра вашей информации злоумышленник использует тот же идентификатор PHPSESSID.

Перехват сессии

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

<?php
		// Working with sessions is quite easy, first thing you have to do on 
		everypage is begin the session.
		session_start();
		// Then you can set the variables for the user
		$_SESSION['username'] = "nettuts";
		$_SESSION['website_url'] = "www.nettuts.com"; 
		echo $_SESSION['username']; // Will echo "nettuts".
?> 

Эффективное использование сессий

В данном руководстве не описывается процесс кодирования сценария регистрации. Однако я постараюсь показать, как сделать более безопасным ваш текущий сценарий регистрации.

В целом использование  сессий безопаснее использования файлов cookie. Это объясняется тем, что пользователи не могут изменять значения сессий так же легко, как и значения файлов cookie. Вот почему мне нравится хранить все переменные пользователей в переменных сессий. Другой важный момент – никогда не доверять вводу данных пользователями. Всегда сверяйте информацию пользователя со значениями в базе данных MYSQL и соответственно затем вывод на сессию. Рассмотрите вариант внесения изменений в регистрационную функцию наподобие следующей функции:

<?php

function login($username, $password)
$sql = mysql_query("SELECT id, user_level FROM users WHERE password = '" . $password . "' AND username = '" . $username . "' LIMIT 1");
// If there are no matches then the username and password do not match
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;
}
}

?>

Давайте проанализируем данный код. Он запрашивает имя пользователя и пароль и проверяет, существует ли пользователь, у которого совпадают оба этих критерия. Если результат отсутствует, образуется неверная комбинация имя пользователя/пароль и выдается ошибка. В противоположном случае создаются переменные сессии: user_id, user_level, user_name, и user_lastactive. Эти значения заполняются данными из списка mysql.

Возможно, у вас возникнет вопрос, что означает функция “session_regenerate_id(true)”. Ранее мы говорили о фиксации сессии. Это решение предназначено для защиты от данного типа атаки. Функция создаёт новый идентификатор сессии при каждом входе пользователя в систему. Таким образом, если пользователь щёлкнет по ссылке с установленным значением сессии, будет создан новый идентификатор сессии, а информация о пользователях будет добавлена в новую, а не старую сессию. При прохождении верного параметра (true) через данную функцию удаляет старую сессию и стирает всю информацию.

Написание функции “Remember Me”

Файлы cookie или файлы сессии не должны содержать паролей пользователей. Это очень важно, так как в случае перехвата файла сессии или cookie злоумышленник может получить полный контроль над всеми учётными записями. Известно, что многие пользователи используют один и тот же пароль в различных учётных записях, и  это позволит злоумышленнику получить контроль над учётными записями пользователей на других сайтах. Как можно выйти из этого затруднительного положения?

Решение данной проблемы – ключ санкционирования доступа (auth_key). Ключом санкционирования доступа может быть связка из имени пользователя, пароля и произвольного набора символов, которые объединяются и зашифровываются. У каждого пользователя должен быть свой уникальный ключ санкционирования доступа. Таким образом, при установке файла cookie значение устанавливается на ключ санкционирования доступа. После этого  происходит сравнение значения ключа санкционирования доступа со значением в списке MySQL, которое вы добавите. Давайте посмотрим, как изменится функция входа пользователей в систему.

 <?php

function login($username, $password, $remember = false) 
{
$sql = mysql_query("SELECT * FROM bio_users WHERE password = '" . $password . "' AND username = '" . $username . "' LIMIT 1");
// If there are no matches then the username and password do not match
if($sql === false) 
{
return false;
}
else
{
while($u = mysql_fetch_array($sql))
{ 
$this->account_active = true;
// Check if user wants account to be saved in cookie
if($remember)
{
// Generate new auth key for each log in (so old auth key can not be used multiple times in case 
// of cookie hijacking)
$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)
}
// Assign variables to session
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;
}
}
} 
?>

Теперь происходит проверка, прошёл ли параметр “true” через параметр запоминания функции входа в систему. Если да, для ключа санкционирования доступа задаётся файл cookie. Функция Rand_string создаёт цепочку с числом символов, которые прошли через неё. Функция Session_encrypt добавляет в цепочку произвольные данные и зашифровывает всю информацию с помощью md5. Данная цепочка является уникальной, так как в ней используется имя пользователя, которое уникально для каждого пользователя. Затем ключ санкционирования доступа в списке mysql устанавливается к значению, вводимому в файл cookie. Как бы там ни было, этой защиты может быть не достаточно для вашего сайта. Рассмотрите возможность добавления нескольких ключей санкционирования доступа и нескольких файлов cookie. Опять-таки, данная функция не соответствует требованиям функции “remember me”. Также необходимо добавить функцию инициализации.

К данной функции необходимо обращаться на каждой странице. Её назначение - проверка ключа санкционирования доступа файла cookie (“auth_key”). Если файл cookie использует функцию isset, появится соответствующий пользователь. Ещё раз, к данной функции необходимо обращаться на каждой странице.

 <?php
function initiate()
{

$logged_in = false;
if(isset($_SESSION['user_name']))
{
$logged_in = true;
}

// Check that cookie is set
if(isset($_COOKIE['auth_key']))
{
$auth_key = safe_var($_COOKIE['auth_key']);

if($logged_in === false)
{
// Select user from database where auth key matches (auth keys are unique)
$auth_key_query = mysql_query("SELECT username, password FROM users WHERE auth_key = '" . $auth_key . "' LIMIT 1");
if($auth_key_query === false)
{
// If auth key does not belong to a user delete the cookie
setcookie("auth_key", "", time() - 3600);
}
else
{
while($u = mysql_fetch_array($auth_key_query))
{
// Go ahead and log in
login($u['username'], $u['password'], true);
}
}
}
else
{
setcookie("auth_key", "", time() - 3600);
}
}

}

?>

Данный код  проверяет, используется ли функция isset. Если данная функция используется файлом cookie, произойдёт проверка соответствия ключа санкционирования доступа с пользователем. Если соответствие установлено, файл извлечёт требуемую информацию и зарегистрирует пользователя. В противном случае файл cookie будет удалён, так как является недействительным.

Другие функции

 <?php

function logout()
{
// Need to delete auth key from database so cookie can no longer be used
$username = $_SESSION['user_name'];
setcookie("auth_key", "", time() - 3600);
$auth_query = mysql_query("UPDATE users SET auth_key = 0 WHERE username = '" . $username . "'");
// If auth key is deleted from database proceed to unset all session variables
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;
}
}


// Check if session is still active and if it keep it alive
function keepalive()
{
// If session is supposed to be saved or remembered ignore following code
if(!isset($_COOKIE['auth_key'])
{
$oldtime = $_SESSION['user_lastactive'];
if(!empty($oldtime))
{
$currenttime = time();
// this is equivalent to 30 minutes
$timeoutlength = 30 * 600;
if($oldtime + $timeoutlength >= $currenttime){ 
// Set new user last active time
$_SESSION['user_lastactive'] = $currenttime;
}
else
{
// If session has been inactive too long logout
logout();
}
}
}
}

?>

Функция выхода из системы не требует разъяснений. Данная функция удаляет все переменные сессии и файлы cookie и устанавливает значение ключа санкционирования доступа для пользователя на 0. После этого ключом санкционирования доступа воспользоваться будет нельзя. Необходимо отметить, что пользователь может задать значение 0 для своего файла cookie и всё ещё регистрироваться в системе под своим именем. Чтобы это исправить, проверьте всё информацию, получаемую из файлов cookie. Используя функцию regexp, убедитесь, что цепочка содержит действительное количество символов, содержит действительные символы и т. д. Функция keepalive() поддерживает активность сессии. Данная функция должна быть на каждой странице.

Заключение & перехват сессии

Чрезвычайно сложно защититься от перехвата сессии Session Hijacking. Возможно, вы читали некоторые советы по использованию комбинации IP-адреса пользователя или процесса User Agent для создания идентификационных меток. Впрочем, это не эффективно для ваших фактических пользователей. IP-адреса пользователей постоянно меняются. У крупных поставщиков услуг Интернета, таких как AOL, они меняются каждые несколько минут. Это создаст огромную проблему. Процессы User Agent также меняются  — установлено, что в IE7 агенты пользователя периодически меняются. Самый лучший способ защиты от перехвата – создать жезловую систему. Данная система выводит файл cookie на каждую страницу загрузки и также хранит это значение в вашем списке mysql. Затем происходит сравнение значения файла cookie со значением таблицы MySQL. Если они разные, сессия будет недействительной.

Это основные функции по работе с файлами сессий и файлами cookie. Разумеется, для усовершенствования защиты необходимо добавить больше файлов cookie для проверки достоверности данных. Данного уровня защиты не достаточно для защиты сугубо важной информации, но с чего-то нужно начинать! И в завершение:

Следите за тем, чтобы значения файлов cookie были действительными.  
Никогда не выводите пароль на сессию или переменную cookie.
 
Для предотвращения фиксации сессии используйте идентификатор
session_regenerate_id.

До следующих уроков!

П.С. Комментарии в коде переведу в течении суток :)

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: www.blog.themeforest.net
Перевел: Максим Шкурупий
Урок создан: 6 Октября 2009
Просмотров: 67593
Правила перепечатки


5 последних уроков рубрики "Разное"

^ Наверх ^