Вопрос или проблема
В процессе разработки уязвимого приложения на основе jsp/servlet я попытался внедрить уязвимость фиксации сессии.
Обратившись к документации, я разработал следующий код, который, когда используется в сервлете для создания новой сессии, должен возвращать существующую HTTP-сессию, если она существует, в противном случае он должен возвращать null. В любом случае новая сессия не должна создаваться.
if(obj.checkLogin(username, password))//если учетные данные действительны
{
HttpSession session = request.getSession(false);//возврат существующей сессии
if(session != null)
response.sendRedirect("LoginSuccess.jsp");
else
response.sendRedirect("error.jsp");
}
Чтобы протестировать код, я развернул его с использованием tomcat 7 и проверил на фиксацию сессии:
- Наблюдайте за куки (
c1
), когда загружается страница входа (используя перехватывающий прокси) - Введите правильные учетные данные в форму входа. Аутентификация прошла успешно, и меня перенаправили на LoginSuccess.jsp
- Наблюдайте за куки (
c2
) после аутентификации.
Я обнаружил, что куки c1
и c2
отличаются. Это подразумевает, что код не уязвим к фиксации сессии. У меня возникают проблемы с пониманием такого поведения. Почему исходный куки c1
не сохраняется после аутентификации?
Это очень старый вопрос. Но поскольку он остался без ответа, вот ответ:
Ваш код безопасен благодаря конфигурации Tomcat. Возможно, вы используете что-то подобное Basic Authenticator Valve.
Посмотрите в документацию:
https://tomcat.apache.org/tomcat-7.0-doc/config/valve.html#Authentication/Attributes
changeSessionIdOnAuthentication по умолчанию равно “true”
Документация гласит:
“Управляет тем, будет ли идентификатор сессии изменен, если сессия существует в точке, где пользователи аутентифицируются. Это сделано для предотвращения атак фиксации сессий. Если не установлено, будет использовано значение по умолчанию true.”
Если вы хотите воспроизвести атаку фиксации сессии, вам, вероятно, нужно изменить это значение на “false”.
Вероятно, нам это больше не нужно… Тем не менее, я все еще думаю, что это ценная информация, так как она может быть полезна кому-то в будущем. Люди все еще используют старые технологии, такие как COBOL 😉
Сервлетный движок, который вы используете, надежно обрабатывает сессионные куки, когда вы вызываете request.getSession(), и не подвержен фиксации.
(как обсуждалось в комментариях) Это поведение намеренное и правильное. Будь то вызов getSession(), getSession(true) или getSession(false), сервер полагается на свою собственную память, чтобы определить, существует ли действительная сессия, соответствующая значению, полученному от клиента. Если такой сессии нет в памяти сервера, то сервлетный движок игнорирует идентификатор сессии от клиента. Это предотвращает фиксацию сессий, так как сервер никогда не позволяет клиенту определять идентификатор сессии новой сессии (новой с точки зрения сервера, у которого нет этого идентификатора сессии в памяти).
Вам нужно либо найти более старый, сломанный сервлетный движок, который подвержен фиксации сессий, либо заменить код управления сессиями. Если вы выберете последнее, вам нужно будет определить, можете ли вы заменить генерацию сессий на месте или вам придется написать свой собственный код управления сессиями.
Подход, который вы выберете, должен соответствовать тому, что вы пытаетесь научить. Если вы хотите, чтобы люди научили…
- поддерживать ваши вещи в исправном состоянии, тогда используйте сломанный старый движок
- не писать свой собственный механизм управления сессиями, тогда напишите свой собственный
- не модифицировать существующий механизм управления сессиями, тогда модифицируйте существующий
Ответ или решение
Сессии в Java, особенно в контексте приложений JSP/Servlet, могут представлять собой уязвимость для атак с использованием фиксации сессии (session fixation). Давайте рассмотрим, что происходит в вашем коде, и почему он не подвержен этой уязвимости.
Ваш код проверяет учетные данные пользователя и использует метод request.getSession(false)
, чтобы вернуть существующую сессию, если таковая имеется, и не создавать новую. Однако, вы заметили, что при успешной аутентификации происходит смена идентификатора сессии (сессионного ID), что отражается в различии между значениями cookies c1
и c2
. Это значит, что после успешной аутентификации сервер заменяет исходный сессионный ID на новый, что и является защитой от атаки с фиксацией сессий.
Почему это происходит?
-
Безопасная обработка сессий в Tomcat: Вы используете Tomcat 7, который обеспечивает защиту от атак с фиксацией сессий по умолчанию. В конфигурации Valve для аутентификации, как правило, установлено значение атрибута
changeSessionIdOnAuthentication
вtrue
. Это означает, что при успешной аутентификации идентификатор сессии изменится, что предотвращает возможность использования старого идентификатора сессии злоумышленником. -
Работа сервера с сессионными ID: При вызове метода
request.getSession()
, сервер проверяет хранимые в его памяти сессии, и если идентификатор от клиента не соответствует ни одной из них, то новый идентификатор не будет принят. Это гарантирует, что сервер не подвержен атаке с фиксацией сессии, так как злоумышленник не сможет задать желаемый идентификатор для новой сессии.
Как воспроизвести уязвимость на старом сервере?
Если вы хотите воспроизвести уязвимость к фиксации сессий для учебных целей, вы можете попробовать следующее:
-
Использовать более старую версию сервера приложений, которая не имеет этой защиты, или настроить Tomcat 7 таким образом, чтобы отключить атрибут
changeSessionIdOnAuthentication
. -
Для этого вам нужно будет изменить значение атрибута
changeSessionIdOnAuthentication
наfalse
в конфигурации Tomcat:
<Context>
<Valve className="org.apache.catalina.valves.BasicAuthenticatorValve"
changeSessionIdOnAuthentication="false"/>
</Context>
- После этого протестируйте свою программу и проверьте, сохраняется ли исходный идентификатор сессии после аутентификации.
Заключение
Ваш текущий подход является безопасным и правильным с точки зрения обработки сессий в Java. Изменение сессионного идентификатора после аутентификации является стандартной практикой, обеспечивающей защиту от фиксации. Чтобы продемонстрировать уязвимость, необходимо использовать устаревший механизм управления сессиями или отключить рекомендуемые практики безопасности в современных серверах приложений.