2009-09-14 38 views
15

Trong web.xml của tôi, tôi đã xác định một người dùng dữ liệu hạn chế cho một số tài nguyên:Làm thế nào để ngăn chặn tấn công phiên tomcat?

<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. Khi tôi tải trang bằng http Tôi đã có JSESSIONID ID1 tôi trong cookie của tôi.
  2. Khi tôi thay đổi thành ngữ cảnh/người dùng/mẫu.faces thì Tomcat chuyển hướng 302 sang HTTPS. Nhưng JSESSIONID của tôi vẫn là ID1.

Tôi nghĩ đây là lỗ hổng bảo mật? Hay là lỗi cấu hình của tôi?

Vấn đề tôi thấy là như sau: Trong khi duyệt qua HTTP với cookie ID1 có kẻ tấn công đang nghe lưu lượng mạng của tôi. Anh ta "đánh cắp" ID1 của tôi. Bây giờ tôi chuyển sang HTTPS và cookie của tôi vẫn là ID1. Tôi đăng nhập. Kẻ tấn công sau đó có thể taker trong phiên của tôi bởi vì anh ấy biết cookie của tôi ...

+0

Hãy bình luận của bạn: Lý do SSLID giống nhau là phiên là như nhau (tôi chỉ cần nhấp vào làm mới trong Firefox, sau khi tất cả). Bạn có thể sử dụng thực tế này trong quản lý phiên của bạn. Về cách SSLID được xây dựng - nó không được bao hàm bởi đặc tả servlet để mỗi nhà cung cấp có thể sử dụng các cơ chế riêng của họ. Bạn sẽ phải kiểm tra các nguồn Tomcat, tôi mong đợi. Dù sao, bạn không nên dựa vào bất kỳ triển khai cụ thể nào - chỉ cần sử dụng nó như bạn sẽ sử dụng JSESSIONID - như một giá trị mờ đục. –

Trả lời

11

Nếu đó là phiên bản Tomcat gần đây, bạn có thể không gặp sự cố. Tuy nhiên, điều này phụ thuộc vào việc bạn kiểm tra ID SSL được kết hợp với phiên. Đây là có sẵn sử dụng mã như

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

(Lưu ý rằng chìa khóa thuộc tính có thể thay đổi trong tương lai để javax.servlet.request.ssl_session_id - như một phần của spec Servlet 3.0).

tôi thiết lập một servlet với doGet phương pháp sau đây:

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

sau đó tôi gọi một URL không được bảo vệ thích hợp sử dụng Firefox và phần mở rộng Live HTTP Headers, để có được những cookie phiên. Đây là câu trả lời được gửi khi tôi chuyển đến

http://localhost:8080/EchoWeb/unprotected 

(web.xml của tôi, giống như bạn, chỉ bảo vệ/user/* và/cá nhân/*):

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

Tiếp theo, tôi đã cố gắng để truy cập vào một URL được bảo vệ

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

và, như mong đợi, tôi đã chuyển đến

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

và phản ứng là

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

ý rằng ID cookie/session là như nhau, nhưng bây giờ chúng tôi có một SSLID mới. Bây giờ, chúng ta hãy cố gắng giả mạo máy chủ bằng cách sử dụng cookie phiên.

tôi thiết lập một kịch bản 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() 

Bây giờ, bạn không cần phải biết Python, đặc biệt - Tôi chỉ cố gắng để gửi một yêu cầu HTTP tới một tài nguyên (khác nhau) được bảo vệ với cùng một ID phiên trong Cookie. Dưới đây là câu trả lời khi tôi chạy kịch bản giả mạo của tôi hai lần:

 
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 

Lưu ý trong các câu trả lời ở trên rằng các dữ liệu phiên (một giá trị với một dấu thời gian của 1254034761932) được đặt trong yêu cầu đầu tiên, không được bảo vệ, đã được gửi đi khắp , bởi vì Tomcat đang sử dụng cùng một phiên vì ID phiên là như nhau. Đây là khóa học không an toàn. Tuy nhiên, lưu ý rằng các ID SSL khác nhau mỗi lần và nếu bạn sử dụng các mã này để nhập dữ liệu phiên của bạn (ví dụ như được hiển thị), bạn nên an toàn. Nếu tôi làm mới tab Firefox của tôi, đây là phản ứng:

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

Chú ý rằng SSLID là cùng như đối với các yêu cầu Firefox trước đó. Vì vậy, máy chủ có thể phân biệt các phiên bằng cách sử dụng giá trị SSL ID. Lưu ý đặc biệt là "dữ liệu được bảo vệ" giống nhau cho mỗi yêu cầu được thực hiện từ phiên Firefox, nhưng khác nhau cho mỗi phiên giả mạo và cũng khác với phiên Firefox.

+0

Giải thích tuyệt vời! Nhưng tôi vẫn có một câu hỏi: làm thế nào nó hoạt động, rằng cuộc gọi cuối cùng của bạn với firefox gửi SSLID cũ. ID đó được xây dựng như thế nào? Tính năng này có được ghi ở bất kỳ đâu không? – Marcel

2

Tôi nghĩ nó hoạt động như thế này theo thiết kế. Bạn không thể căn cứ vào kiểm soát truy cập của mình trong phiên. Bạn cần sử dụng các thông số khác. Bạn cần thêm xác thực và sử dụng điều khiển dựa trên vai trò.

Trong Tomcat, có sự bảo vệ nhưng hoàn toàn ngược lại. Nếu bạn nhận được một phiên trong khu vực an toàn, phiên đó không được chuyển đến khu vực không được bảo vệ. Tomcat đạt được điều này bằng cách đặt cờ "an toàn" trên cookie để cookie không được gửi đến các kết nối HTTP.

+0

Tôi không kiểm soát quyền truy cập cơ sở trên phiên. Web.xml ở trên chỉ là một phần nhỏ của toàn bộ web.xml. Tất nhiên tôi có một phương pháp xác thực dựa trên JAAS được triển khai. Tôi cố gắng rõ ràng hơn trong mô tả của tôi. – Marcel

2

Tôi đề nghị thay đổi sessionId khi bạn xác thực phiên.
Bằng cách này, sessionId cũ trở nên vô ích và không thể chiếm đoạt phiên.
Để thay đổi sessionId trong một container servlet:

  • sao chép tất cả các thuộc tính của phiên hiện hành về một bộ sưu tập tạm
  • session.invalidate()
  • phiên = req.getSession (true)
  • điền vào phiên mới với các thuộc tính từ bộ sưu tập temp

Giới thiệu về SSLID, xin lưu ý rằng cả khách hàng và máy chủ đều có thể đóng kết nối tại bất kỳ thời gian. Khi đóng một bắt tay SSL mới sẽ xảy ra và một SSID mới được tạo ra. Vì vậy, IMO SSLID không phải là cách đáng tin cậy để theo dõi (hoặc giúp theo dõi) phiên.

Các vấn đề liên quan