2009-09-14 17 views
15

Bazı kaynaklar için bir kullanıcı veri kısıtlamasını tanımladığınız:Tomcat oturumu ele geçirme nasıl engellenir? Benim web.xml olarak

<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. benim çerez olarak benim jsessionid ID1 var http sayfayı yüklemek zaman.
  2. Bağlam/kullanıcı/örnek.yüzene geçtiğimde Tomcat, HTTPS'ye 302 yönlendirmesi yapar. Ama benim JSESSIONID hala ID1.

Bu bir güvenlik açığı mı? Yoksa benim yapılandırma hatası mı?

Gördüğüm sorun şudur: HTTP üzerinden çerez ID1 ile gezerken ağ trafiğimi dinleyen bir saldırgan var. Çerez ID1'i "çalıyor". Şimdi HTTPS'ye geçiyorum ve çerezim hala ID1. Giriş yaptım Saldırgan daha sonra benim oturumumun üstesinden gelebilir çünkü o benim kurabimi biliyordur ...

+0

Yorumunuzu yapın: SSLID'nin aynı olmasının nedeni, oturumun aynı olmasıdır (Sadece Firefox'ta yenilendim, sonuçta). Bu gerçeği oturum yönetiminizde kullanabilirsiniz. SSLID'nin nasıl oluşturulduğuna gelince, her bir satıcı kendi mekanizmalarını kullanabilmesi için sunucu özellikleri kapsamında değildir. Tomcat kaynaklarını kontrol etmelisin, bekliyorum. Her neyse, belirli bir uygulamaya güvenmemeniz gerekir - sadece JSESSIONID'i kullandığınız gibi kullanın - opak bir değer olarak. –

cevap

11

Tomcat'in yakın tarihli bir sürümüyse, sorun yaşamayabilirsiniz. Ancak, bu oturumla ilişkili SSL kimliğini kontrol etmenize bağlıdır. Bu tür

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

olarak (- Servlet 3.0 spec parçası olarak özellikte temel javax.servlet.request.ssl_session_id için gelecekte değişebilir unutmayın) kodunu kullanarak mevcuttur.

aşağıdaki doGet yöntemi ile bir sunucu uygulamasını kurmak:

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(); 
} 

Sonra oturumu çerez almak için, Firefox ve Canlı HTTP Başlıkları uzantısını kullanarak, uygun bir korumasız URL çağrılan. Bu benim

http://localhost:8080/EchoWeb/unprotected 

gittiğinizde gönderilen cevap oldu (benim web.xml, sizinki gibi, sadece korur/user/* ve/kişisel/*):

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

İleri, ben çalıştım beklendiği gibi, korumalı bir URL

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

erişebilir ve ben

https://localhost:8443/EchoWeb/personal/protected 
yönlendirildi var

ve tepki çerez/oturum kimliği aynı olduğunu

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

Bildirim oldu, ama biz artık yeni bir SSLID var. Şimdi, sunucuyu oturum çerezini kullanarak aldatmaya çalışalım.Özellikle, Python bilmek gerekmez, Şimdi

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() 

- Ben sadece bir (farklı) korumalı bir kaynak için bir HTTP isteği göndermek çalışıyorum:

Ben bir Python komut dosyası, spoof.py kurmak Çerezde aynı oturum kimliğiyle. İşte yanıtı iki kez benim parodi senaryoyu çalıştırdığınızda var: oturum verileri ilk, korunmasız istekte kuruldu (1254034761932 bir zaman damgası ile bir değer), boyunca gönderildiğini yukarıdaki yanıtlarda

 
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 

Bildirimi Çünkü Tomcat aynı oturumu kullanıyor çünkü oturum kimliği aynı. Bu elbette güvenli değildir. Ancak, SSL kimlik numaraları 'un her seferinde farklı olduğunu ve oturum verilerinizi (örn., Gösterildiği gibi)kullandıysanız, güvende olmanız gerektiğini unutmayın. Ben Firefox sekmeyi yenilemek, burada tepkidir: SSLID önceki Firefox istek gelince aynı olduğunu

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

Bildirim söyledi. Böylece sunucu, SSL ID değerini kullanarak oturumları ayrı olarak söyleyebilir. Özellikle "korumalı veriler" in Firefox oturumundan yapılan her istek için aynı olduğuna, ancak sahte oturumların her biri için farklı ve aynı zamanda Firefox oturumundan farklı olduğuna dikkat edin.

+0

Harika açıklamalar! Ama hala bir sorum var: Nasıl çalışır, firefox'la yaptığınız son çağrı eski SSLID'i gönderir. Bu kimlik nasıl kurulur? Bu özellik herhangi bir yerde belgelenmiş mi? – Marcel

2

Tasarımla bu şekilde çalışır. Erişim kontrolünüzü oturuma dayandıramazsınız. Diğer parametreleri kullanmalısın. Kimlik doğrulaması eklemeniz ve rol tabanlı kontrol kullanmanız gerekir.

Tomcat'te koruma var ama tam tersi. Güvenli bir alanda bir oturum alırsanız, bu oturum korumasız alana aktarılmaz. Tomcat bunu, çerezin HTTP bağlantılarına gönderilmemesi için çerezde "güvenli" bayrak ayarlayarak başarır.

+0

Erişim denetimini oturuma temel almıyorum. Yukarıdaki web.xml, tüm web.xml'nin sadece küçük bir parçasıdır. Tabi ki uygulanmış JAAS tabanlı bir kimlik doğrulama yöntemim var. Açıklamamda biraz daha açık olmaya çalışıyorum. – Marcel

2

Oturum kimliğini doğruladığınızda sessionId değiştirmenizi öneririm.
Bu şekilde, eski sessionId işe yaramaz hale gelir ve oturum kaçırma imkansızdır.
bir servlet kapta SessionID değiştirmek için:

  • geçici koleksiyonu geçerli oturum tüm özelliklerini kopyalamak
  • session.invalidate()
  • seans = req.getSession (doğru)
  • geçici koleksiyonu SSLID Hakkında

gelen özelliklere sahip yeni bir oturum doldurmak, istemci ve sunucu hem herhangi birinde bağlantıyı kapatmak için serbest olduğunu unutmayın saati. Kapatıldığında yeni bir SSL tokalaşması gerçekleşecek ve yeni bir SSID oluşturulacaktır. IMO SSLID, oturumları izlemenin (ya da izlemenize yardımcı olan) güvenilir bir yol değil.

İlgili konular