MD5签署HttpServletResponse

我正在寻找一种方法来检查HttpServletResponse的内容,以便用MD5哈希对它们进行签名。

伪代码可能看起来像这样

 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. } 

那可能吗?

是的,那是可能的。 您需要在HttpServletResponseWrapper帮助下修饰响应,其中您使用自定义实现替换ServletOutputStream ,该实现将字节写入MD5摘要和“原始”输出流。 最后提供一个访问器来获得最终的MD5总和。

更新我只是为了好玩而玩了一下,这是一个开球的例子:

响应包装器:

 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输出流:

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

如何使用它:

 // Wrap original response with it: MD5ServletResponse md5response = new MD5ServletResponse(response); // Now just use md5response instead or response, eg: dispatcher.handle(request, md5response); // Then get the hash, eg: 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. 

从技术上讲,术语“签名”保留给签名,散列函数不计算这些。

为了确保数据在传输过程中不会被改变,使用散列函数,那么您必须使用安全的带外方式来传输散列值; 在HTTP头中添加哈希值是行不通的,因为任何能够改变传输数据的人都可以随意重新计算哈希值,并根据需要改变HTTP头。

使用加密技术,您可以“集中”将带外传输安全地转换为可重用密钥。 如果客户端和服务器具有共享的秘密值(假定的攻击者不知道),那么首字母缩写词是MAC,如“消息认证码”中所示; 通常的MAC是HMAC 。

在许多实际情况中,不能使用MAC,因为MAC需要共享秘密,并且共享太多次的秘密不再是真正的秘密。 每个秘密持有者都有权重新计算MAC。 如果每个客户端都知道这个秘密,那么基本上它不是秘密,并且可以安全地假设攻击者也知道它。 因此,您可以更进一步使用数字签名 (真实的,使用RSA,DSS,ECDSA …),其中服务器使用私钥 (只有服务器知道),客户端只知道相应的公钥 。 对公钥的了解足以validation签名,但不能生成新签名,并且私钥不能从公钥中重新计算(尽管它们在数学上彼此链接)。 但是,实施数字签名并正确使用它比通常假设困难得多; 您最好的选择是使用已经调试的协议,使用现有的实现,并且该协议恰好称为“SSL”。

这里的要点是,没有SSL,很可能无论你做什么都不能阻止坚定的攻击者; 它只会使用CPU周期和网络带宽,给你一种温暖的模糊感觉。

你想做什么?

您可能最好看一下标准的消息格式,并在这样的消息中包含您的响应内容,然后签名。 想到了OAuth。

此外,如果启用SSL,则客户端可以确保响应的内容未被篡改。