Страница 5 из 7
Выдача себя за другого (ВСД) Распространено неправильное представление, что родной PHP-шный механизм управления сессией сам предпринимает меры безопасности против атак, основанных на сессии. Наоборот, PHP только предоставляет подходящий для этого механизм. Ответственность же за обеспечение соответствующих мер безопасности ложится на разработчика. Как упоминалось ранее, не существует безупречного, идеального способа решения, как и наилучшего решения, правильного для каждого. Для объяснения опасности ВСД рассмотрим следующую последовательность событий: - Мальчиш-Кибальчиш заходит на https://www.example.org/ и авторизируется.
- Web-сайт устанавливает куку PHPSESSID=12345.
- Мальчиш-Плохиш заходит на https://www.example.org/ и предоставляет куку PHPSESSID=12345.
- Web-сайт ошибочно думает, что Мальчиш-Плохиш в действительности является Мальчишом-Кибальчишом.
Конечно, этот сценарий требует, чтобы Плохиш каким-либо образом узнал или угадал правильный PHPSESSID, принадлежащий Кибальчишу. Хоть это и кажется малообещающим, — это пример обеспечения безопасности с помощью НДП {Б.С.: в оригинале — obscurity.} — неизвестности для постороннего; он не является чем-то, на что стоит полагаться. Такая неизвестность — вещь, конечно, неплохая, и она может помогать, но необходимо что-то более существенное, что предложит надёжную защиту против подобной атаки. Предотвращение ВСД Существует много способов, которые могут быть использованы для затруднения ВСД или других основанных на сессии атак. Общим подходом здесь является создание систем настолько, насколько это возможно, удобными для ваших законных пользователей и, настолько, насколько возможно, — сложными и запутанными для атакующих. Это может оказаться очень труднодостижимым балансом, и в значительной степени идеальный баланс зависит от дизайна приложения. Поэтому, в конечном счёте, лучший судья — это вы сами. Простейший корректный с точки зрения HTTP/1.1 запрос, как упоминалось ранее, состоит из строки-запроса и заголовка Host: GET / HTTP/1.1 Host: www.example.org Клиент может передать идентификатор сессии PHPSESSID в заголовке Cookie: GET / HTTP/1.1 Host: www.example.org Cookie: PHPSESSID=12345 В качестве альтернативы клиент может передать идентификатор сессии в URLе запроса: GET /?PHPSESSID=12345 HTTP/1.1 Host: www.example.org Идентификатор сессии также может быть включён в POST-данные, но обычно это менее удобно для пользователя и распространено меньше всего. Так как информация, полученная от TCP/IP, не может быть надёжно использована в усилении безопасности механизма, то кажется, что web-разработчик мало что может сделать для затруднения ВСД. Как-никак, атакующий должен лишь предоставить тот же уникальный идентификатор, что и легальный, законный пользователь, для того, чтобы выдать себя за этого пользователя и подделать сессию. Таким образом, представляется, что единственная защита — либо скрывать идентификатор сессии, либо делать его трудным для угадывания (а лучше — и то, и другое). PHP генерирует случайный идентификатор сессии, который практически невозможно угадать, таким образом, об этом можно почти не заботиться. Предотвратить же раскрытие атакующим правильного идентификатора сессии гораздо сложнее, так как большая часть ответственности за это лежит вне области контроля разработчика. Есть много ситуаций, которые могут привести к раскрытию пользовательского идентификатора сессии. GET-данные могут быть ошибочно кэшированы, замечены случайным наблюдателем, сохранены в закладках или переданы по электронной почте. Куки обеспечивают несколько более безопасный механизм, но пользователи могут отключить их поддержку, исключая возможность их использования, а уязвимости браузеров известны случайной утечкой информации из кук на несанкционированные сайты (смотрите www.peacefire.org/security/iecookies/ и www.solutions.fi/iebug/ для дополнительной информации). Итак, разработчик может быть вполне убеждён, что идентификатор сессии не может быть угадан, однако возможность, что он может быть выведан атакующим, гораздо более вероятна независимо от метода, использующегося для его передачи. Нужны какие-то дополнительные средства для предотвращения ВСД. На практике типичный HTTP-запрос помимо Host содержит множество необязательных заголовков. К примеру, рассмотрим следующий: GET / HTTP/1.1 Host: www.example.org Cookie: PHPSESSID=12345 User-Agent: Mozilla/5.0 Galeon/1.2.6 (X11; Linux i686; U;) Gecko/20020916 Accept: text/html;q=0.9, */*;q=0.1 Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66 Accept-Language: en Этот запрос содержит четыре необязательных заголовка: User-Agent, Accept, Accept-Charset и Accept-Language. Из-за того, что заголовки эти необязательны, будет не очень разумно надеяться на их наличие. Однако если браузер пользователя всё же послал эти заголовки, безопасно ли полагать, что они будут присутствовать и в последующих запросах от того же браузера? Ответом является "да" с очень немногими исключениями. Предполагая, что предыдущий пример — это запрос, посланный пользователем с активной сессией, рассмотрим следующий запрос, посланный незадолго после этого: GET / HTTP/1.1 Host: www.example.org Cookie: PHPSESSID=12345 User-Agent: Mozilla/5.0 (compatible; IE 6.0 Microsoft Windows XP) Так как предоставлен тот же уникальный идентификатор, будет получен доступ к той же PHP-сессии. Если браузер идентифицирует себя иначе, чем в предыдущем взаимодействии, надо ли полагать, что это тот же пользователь? Надеюсь вам понятно, что это не желательно, тем не менее, это именно то, что произойдёт, если вы пишете код, который не проверяет специально такие ситуации. Даже в случаях, когда вы не можете быть уверены, что запрос является ВСД-атакой, простое требование ввода пользователем пароля может помочь предотвратить ВСД без причинения особого неудобства вашим пользователям. Вы можете добавить проверку браузера пользователя в вашу модель безопасности с помощью кода, подобного представленному на листинге 3. |