2010-02-02 32 views
5

Tôi đang tìm cách kiểm tra nội dung của một số HttpServletResponse để ký chúng với một băm MD5.MD5 Ký một HttpServletResponse

Các giả có thể trông như thế này

process(Response response, Request request){ 

defaultProcessingFor(response,request); 

dispatcher.handle(response,request); 

// Here I want to read the contents of the Response object (now filled with data) to create a MD5 hash with them and add it to a header. 
} 

Là có thể?

Trả lời

6

Có, điều đó là có thể. Bạn cần phải trang trí phản hồi với sự trợ giúp của HttpServletResponseWrapper trong đó bạn thay thế ServletOutputStream bằng triển khai tùy chỉnh ghi các byte vào cả bản phân tích MD5 và luồng đầu ra "gốc". Cuối cùng cung cấp một accessor để có được tổng MD5 cuối cùng.

Cập nhật tôi chỉ để cho vui chơi một chút quanh nó, sau đây là một ví dụ Kickoff:

Các wrapper phản ứng:

public class MD5ServletResponse extends HttpServletResponseWrapper { 

    private final MD5ServletOutputStream output; 
    private final PrintWriter writer; 

    public MD5ServletResponse(HttpServletResponse response) throws IOException { 
     super(response); 
     output = new MD5ServletOutputStream(response.getOutputStream()); 
     writer = new PrintWriter(output, true); 
    } 

    public PrintWriter getWriter() throws IOException { 
     return writer; 
    } 

    public ServletOutputStream getOutputStream() throws IOException { 
     return output; 
    } 

    public byte[] getHash() { 
     return output.getHash(); 
    } 

} 

MD5 OutputStream:

public class MD5ServletOutputStream extends ServletOutputStream { 

    private final ServletOutputStream output; 
    private final MessageDigest md5; 

    { 
     try { 
      md5 = MessageDigest.getInstance("MD5"); 
     } catch (NoSuchAlgorithmException e) { 
      throw new ExceptionInInitializerError(e); 
     } 
    } 

    public MD5ServletOutputStream(ServletOutputStream output) { 
     this.output = output; 
    } 

    public void write(int i) throws IOException { 
     byte[] b = { (byte) i }; 
     md5.update(b); 
     output.write(b, 0, 1); 
    } 

    public byte[] getHash() { 
     return md5.digest(); 
    } 

} 

Làm thế nào để sử dụng nó:

// Wrap original response with it: 
MD5ServletResponse md5response = new MD5ServletResponse(response); 

// Now just use md5response instead or response, e.g.: 
dispatcher.handle(request, md5response); 

// Then get the hash, e.g.: 
byte[] hash = md5response.getHash(); 
StringBuilder hashAsHexString = new StringBuilder(hash.length * 2); 
for (byte b : hash) { 
    hashAsHexString.append(String.format("%02x", b)); 
} 
System.out.println(hashAsHexString); // Example af28cb895a479397f12083d1419d34e7. 
+0

@Pablo: Bạn cũng cần ký các tiêu đề? – Thilo

+0

@Thilo chỉ nội dung sẽ là OK –

+0

@BalusC không biết vẫn còn nếu đó là cách tiếp cận tôi sẽ thực hiện nhưng lớp đó 'HttpServletResponseWrapper' là __NICE__ (+1) –

0

Bạn đang cố gắng làm gì?

Bạn có thể nên xem xét định dạng tin nhắn chuẩn và gói nội dung phản hồi của bạn vào một thông báo như vậy và ký tên vào đó. OAuth đến với tâm trí.

Ngoài ra, nếu bạn bật SSL, ứng dụng khách có thể chắc chắn rằng nội dung của phản hồi không bị giả mạo.

+0

Tôi có một ứng dụng đang hoạt động. Tôi muốn thêm chữ ký - hàm băm vào phản hồi đảm bảo nội dung không bị sửa đổi khi chuyển tiếp. –

+0

@Pablo: có thể chỉ cần bật SSL? – Thilo

+0

Thật đáng tiếc đó không phải là một lựa chọn: ( –

1

Về mặt kỹ thuật, thuật ngữ "chữ ký" được dành riêng cho, tốt, chữ ký và hàm băm không tính toán được.

Để đảm bảo rằng dữ liệu không bị thay đổi khi chuyển tiếp, với hàm băm, thì bạn phải có một cách an toàn ngoài băng để truyền giá trị băm; việc thêm giá trị băm trong tiêu đề HTTP sẽ không làm, bởi vì bất kỳ ai có thể thay đổi dữ liệu được truyền có thể tính toán lại băm theo ý muốn, và thay đổi các tiêu đề HTTP khi nó thấy phù hợp.

Với mật mã, bạn có thể "tập trung" để đảm bảo việc truyền dẫn ngoài băng tần thành khóa có thể sử dụng lại được. Nếu máy khách và máy chủ có một giá trị bí mật được chia sẻ, không biết đến kẻ tấn công được cho là, thì từ viết tắt là MAC, như trong "Mã xác thực thư"; một MAC thông thường là HMAC.

Trong nhiều trường hợp thực tế, không thể sử dụng MAC vì MAC yêu cầu bí mật dùng chung và bí mật được chia sẻ quá nhiều lần không thực sự bí mật nữa. Mỗi người giữ bí mật đều có khả năng tính toán lại MAC. Nếu mỗi khách hàng biết bí mật, thì về cơ bản nó không phải là một bí mật và nó là an toàn để giả định rằng kẻ tấn công cũng biết điều đó. Do đó, bạn có thể tiến thêm một bước và sử dụng các chữ ký số số (thực tế, những người sử dụng RSA, DSS, ECDSA ...) trong đó máy chủ sử dụng khóa riêng (chỉ máy chủ biết) và khách hàng chỉ biết khóa công khai tương ứng. Kiến thức về khóa công khai là đủ để xác minh chữ ký, nhưng không phải để tạo ra các chữ ký mới, và khóa riêng không thể được tính toán lại từ khóa công khai (mặc dù chúng được liên kết toán học với nhau).Tuy nhiên, việc thực hiện một chữ ký số và sử dụng nó đúng cách thì khó hơn nhiều so với nó thường được giả định; đặt cược tốt nhất của bạn là sử dụng giao thức đã được sửa lỗi, với các triển khai hiện có và giao thức đó xảy ra được gọi là "SSL".

Điểm ở đây là không có SSL, rất có thể là bất cứ điều gì bạn làm sẽ không ngăn chặn kẻ tấn công được xác định; nó sẽ chỉ sử dụng các chu trình CPU và băng thông mạng, và cho bạn cảm giác mờ ấm áp.

+0

Cả khách hàng và máy chủ chia sẻ một _secret_ phổ biến Các MD5 là sau đó _signed_ bằng cách sử dụng bí mật đó (trên thực tế tôi cũng sử dụng thuật toán HMAC-SHA để ký). Tôi đã không chỉ định những người bởi vì nó không phải làm gì với câu hỏi này. –