Как предотвратить угон сеанса tomcat? - PullRequest
15 голосов
/ 14 сентября 2009

В моем web.xml я определил ограничение пользовательских данных для некоторых ресурсов:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Personal Area</web-resource-name>
        <url-pattern>/personal/*</url-pattern>
    </web-resource-collection>
    <web-resource-collection>
        <web-resource-name>User Area</web-resource-name>
        <url-pattern>/user/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>
  1. Когда я загружаю страницу с http, в моем cookie-файле появляется мой JSESSIONID ID1.
  2. Когда я изменяю на context / user / sample.faces, Tomcat перенаправляет 302 на HTTPS. Но мой JSESSIONID по-прежнему ID1.

Я думаю, что это уязвимость? Или это моя ошибка конфигурации?

Проблема, которую я вижу, заключается в следующем: при просмотре по HTTP с cookie ID1 обнаруживается злоумышленник, который прослушивает мой сетевой трафик. Он "крадет" мое печенье ID1. Теперь я переключаюсь на HTTPS, и мой cookie все еще ID1. Я вхожу Затем злоумышленник может перехватить мою сессию, потому что он знает мое печенье ...

Ответы [ 3 ]

11 голосов
/ 26 сентября 2009

Если это последняя версия Tomcat, у вас может не быть проблем. Однако это зависит от вашей проверки SSL-идентификатора, связанного с сеансом. Это доступно с использованием кода, такого как

String sslId = (String) req.getAttribute("javax.servlet.request.ssl_session");

(Обратите внимание, что ключ атрибута в будущем может измениться на javax.servlet.request.ssl_session_id - как часть спецификации Servlet 3.0).

Я настроил сервлет с помощью следующего doGet метода:

protected void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
    HttpSession session = request.getSession(true);
    String sid = session.getId();
    String sslId = (String) request.getAttribute(
                "javax.servlet.request.ssl_session");
    String uri = request.getRequestURI();
    OutputStream out = response.getOutputStream();
    PrintWriter pw = new PrintWriter(out);
    HashMap<String, Object> secrets;
    Object secret = null;
    Object notSecret;
    Date d = new Date();

    notSecret = session.getAttribute("unprotected");
    if (notSecret == null) {
        notSecret = "unprotected: " + d.getTime();
        session.setAttribute("unprotected", notSecret);
    }
    secrets = (HashMap<String, Object>) session.getAttribute("protected");
    if (secrets == null) {
        secrets = new HashMap<String, Object>();
        session.setAttribute("protected", secrets);
    }
    if (sslId != null) {
        if (secrets.containsKey(sslId))
            secret = secrets.get(sslId);
        else {
            secret = "protected: " + d.getTime();
            secrets.put(sslId, secret);
        }
    }
    response.setContentType("text/plain");
    pw.println(MessageFormat.format("URI: {0}", new Object[] { uri }));
    pw.println(MessageFormat.format("SID: {0}", new Object[] { sid }));
    pw.println(MessageFormat.format("SSLID: {0}", new Object[] { sslId }));
    pw.println(MessageFormat.format("Info: {0}", new Object[] { notSecret }));
    pw.println(MessageFormat.format("Secret: {0}", new Object[] { secret }));
    pw.println(MessageFormat.format("Date: {0}", new Object[] { d }));
    pw.close();
}

Затем я вызвал подходящий незащищенный URL-адрес, используя Firefox и расширение Live HTTP Headers, чтобы получить файл cookie сеанса. Это был ответ, отправленный, когда я перешел на

http://localhost:8080/EchoWeb/unprotected

(мой web.xml, как и ваш, защищает только / user / * и / personal / *):

URI: /EchoWeb/unprotected
SID: 9ACCD06B69CA365EFD8C10816ADD8D71
SSLID: null
Info: unprotected: 1254034761932
Secret: null
Date: 27/09/09 07:59

Затем я попытался получить доступ к защищенному URL

http://localhost:8080/EchoWeb/personal/protected

и, как и ожидалось, меня перенаправили на

https://localhost:8443/EchoWeb/personal/protected

и ответ был

URI: /EchoWeb/personal/protected
SID: 9ACCD06B69CA365EFD8C10816ADD8D71
SSLID: 4abf0d67549489648e7a3cd9292b671ddb9dd844b9dba682ab3f381b462d1ad1
Info: unprotected: 1254034761932
Secret: protected: 1254034791333
Date: 27/09/09 07:59

Обратите внимание, что идентификатор cookie / сессии совпадает, но теперь у нас есть новый SSLID. Теперь давайте попробуем подделать сервер с помощью куки-файла сессии.

Я установил скрипт Python, spoof.py:

import urllib2

url = "https://localhost:8443/EchoWeb/personal/protected"
headers = {
    'Host': 'localhost:8080',
    'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en-gb,en;q=0.5',
    'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
    'Cookie' : 'JSESSIONID=9ACCD06B69CA365EFD8C10816ADD8D71'
}
req = urllib2.Request(url, None, headers)
response = urllib2.urlopen(req)
print response.read()

Теперь вам не нужно знать Python, в частности - я просто пытаюсь отправить HTTP-запрос (другому) защищенному ресурсу с тем же идентификатором сеанса в Cookie. Вот ответ, когда я дважды запустил свой сценарий подмены:

C:\temp>spoof
URI: /EchoWeb/personal/protected
SID: 9ACCD06B69CA365EFD8C10816ADD8D71
SSLID: 4abf0eafb4ffa30b6579cf189c402a8411294201e2df94b33a48ae7484f22854
Info: unprotected: 1254034761932
Secret: protected: 1254035119303
Date: 27/09/09 08:05


C:\temp>spoof
URI: /EchoWeb/personal/protected
SID: 9ACCD06B69CA365EFD8C10816ADD8D71
SSLID: 4abf0eb184cb380ce69cce28beb01665724c016903650539d095c671d98f1de3
Info: unprotected: 1254034761932
Secret: protected: 1254035122004
Date: 27/09/09 08:05

Обратите внимание, что в приведенных выше ответах данные сеанса (значение с отметкой времени 1254034761932), которые были установлены в первом незащищенном запросе, были отправлены повсюду, поскольку Tomcat использует один и тот же сеанс, поскольку идентификатор сеанса тот же самый. Это, конечно, небезопасно . Однако обратите внимание, что идентификаторы SSL каждый раз отличались , и если вы используете эти для ввода данных сеанса (например, как показано), вы должны быть в безопасности. Если я обновлю свою вкладку Firefox, вот ответ:

URI: /EchoWeb/personal/protected
SID: 9ACCD06B69CA365EFD8C10816ADD8D71
SSLID: 4abf0d67549489648e7a3cd9292b671ddb9dd844b9dba682ab3f381b462d1ad1
Info: unprotected: 1254034761932
Secret: protected: 1254034791333
Date: 27/09/09 08:05

Обратите внимание, что SSLID такой же , что и для более раннего запроса Firefox. Таким образом, сервер может различать сессии, используя значение SSL ID. Обратите особое внимание на то, что «защищенные данные» одинаковы для каждого запроса, сделанного из сеанса Firefox, но отличаются для каждого из подделанных сеансов, а также отличаются от сеанса Firefox.

2 голосов
/ 10 февраля 2010

Я предлагаю изменить sessionId, когда вы аутентифицируете сеанс.
Таким образом, старый sessionId становится бесполезным, а перехват сеанса невозможен.
Чтобы изменить идентификатор сеанса в контейнере сервлета:

  • скопировать все атрибуты текущего сеанса во временную коллекцию
  • session.invalidate ()
  • session = req.getSession (true)
  • заполнить новый сеанс атрибутами из временной коллекции

Что касается SSLID, обратите внимание, что и клиент, и сервер могут в любой момент закрыть соединение. При закрытии происходит новое рукопожатие SSL и генерируется новый SSID. Таким образом, IMO SSLID не является надежным способом отслеживания (или помощи в отслеживании) сеансов.

2 голосов
/ 14 сентября 2009

Я думаю, что так и работает. Вы не можете основывать свой контроль доступа на сессии. Вам нужно использовать другие параметры. Вам нужно добавить аутентификацию и использовать контроль на основе ролей.

В Tomcat есть защита, но с точностью до наоборот. Если вы получаете сеанс в защищенной области, этот сеанс не переносится в незащищенную область. Tomcat достигает этого, устанавливая флажок «secure» в cookie, чтобы cookie не отправлялся HTTP-соединениям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...