INTRO Сейчас я опишу грабли, на которые чуть сам не наступил. А они могли бы привести к серьёзным последствиям... BODY (показываю на примере PHP) Пусть у нас есть код, в котором используются сессии. Пусть в сессиях хранится, скажем, уровень доступа пользователя - число, которое может увеличиться, если пользователь что-то сделает. Этот же уровень доступа хранится в БД. Пусть пользователю для увеличения уровня доступа надо ответить на вопрос. Можно написать такой код, выполняющий соответствующее действие: 1-ый косяк: PHP: // при логине аналогично level берётся из БД. session_start(); // проверка существования сессии: (isset($_SESSION['id'])) or die("who r u?"); $answer = //из бд получаем ответ к уровню $_SESSION['level']; if ($_GET['answer'] === $answer){ print "ok"; $_SESSION['level']++; //коннект к БД mysql_query("Update `auth` set level=level+1 where id=".$_SESSION['id']); //отключение от БД } 2-ой косяк: PHP: // при логине аналогично level берётся из БД. session_start(); // проверка существования сессии: (isset($_SESSION['id'])) or die("who r u?"); $answer = //из бд получаем ответ к уровню $_SESSION['level']; if ($_GET['answer'] === $answer){ print "ok"; $level = ++$_SESSION['level']; if ($level === $maximum_level){ //выполняем секретный код для очень крутых пацанов } } //лирическое отступление, положенное в таких случаях Казалось бы - всё правильно, но... это не так. //лирическое отступление закончилось //Пояснение к первому косяку Что можно сделать в таком случае? Пусть мошенник (пользуясь именами от Брюса Шнаера) Ева знает ответ на первый вопрос. Сейчас я покажу, что ей этого достаточно, чтобы попасть на любой уровень. Для этого она открывает несколько сессий с первым уровнем (в банальном случае - несколькими броузерами), и в каждой сессии отвечает на вопрос. При каждом ответе инкрементируется как уровень в сессии, так и уровень в БД. Сессии друг от друга не зависят, зато БД - общая! Тем самым мы неограниченное количество раз переходим на следующий уровень. ////Фикс 1 Фикс не очень хороший, ибо при случайном использовании двух сессий (открыл человек двумя броузерами, потом запутался, заново ответил на уже пройденный вопрос) может привести к нежелательному откату назад. PHP: // при логине аналогично level берётся из БД. session_start(); // проверка существования сессии: (isset($_SESSION['id'])) or die("who r u?"); $answer = //из бд получаем ответ к уровню $_SESSION['level']; if ($_GET['answer'] === $answer){ session_start(); print "ok"; $level=++$_SESSION['level']; //коннект к БД mysql_query("Update `auth` set `level`='$level' where id=".$_SESSION['id']); //отключение от БД } ////Конец фикса 1 ////Фикс 2 PHP: // при логине аналогично level берётся из БД. session_start(); // проверка существования сессии: (isset($_SESSION['id'])) or die("who r u?"); $bdlev = //из бд получаем уровнь пользователя $_SESSION['id']; ($bdlev===$_SESSION['level']) or die("Relogin please!"); $answer = //из бд получаем ответ к уровню $_SESSION['level']; if ($_GET['answer'] === $answer){ session_start(); print "ok"; $level = ++$_SESSION['level']; //коннект к БД mysql_query("Update `auth` set `level`='$level' where id=".$_SESSION['id']); //отключение от БД } ////Конец фикса 2 //Пояснение к первому косяку кончилось //Пояснение ко второму косяку Тут аналогичная ошибка, только более общий случай. Мы можем таким образом многократно вызвать один и тот же код, который мог планироваьтся единожды - к примеру, запись в таблицу результатов. ////Фикс Фикс аналогичен Фиксу 2 из 1-го косяка - надо СИНХРОНИЗИРОВАТЬ данные в БД и сессии. ////Фикс кончился //Пояснение ко второму косяку кончилось OUTRO Эх, сколько же ошибок может спровоцировать неправильная синхронизация и распараллеливание! Притом ошибок - трудноисправимых. GREETZ Они сами знают, кому (с) desTiny, 2008