**1. UploadFilter **
package com.filter;
import com.framework.ModelAndView; import com.proxy.ReReadableHttpServletRequest;
import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;
@WebFilter public class UploadFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("验证文件完整性开始"); HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; // 获取客户端传入的签名方法和签名: String digest = req.getHeader("Signature-Method"); String signature = req.getHeader("Signature"); if (digest == null || digest.isEmpty() || signature == null || signature.isEmpty()) { resp.sendRedirect("/uploadError"); return; }
// 读取Request的Body并验证签名: MessageDigest md = getMessageDigest(digest); InputStream input = new DigestInputStream(request.getInputStream(), md); byte[] buffer = new byte[request.getContentLength()]; for (;;) { int len = input.read(buffer); if (len == -1) { break; } } String actual = toHexString(md.digest()); if (!signature.equals(actual)) { resp.sendRedirect("/uploadError"); return; } System.out.println("文件完整性验证成功"); // 验证成功后继续处理: //chain.doFilter(request, response); chain.doFilter(new ReReadableHttpServletRequest(req, buffer),response); }
// 将byte[]转换为hex string: private String toHexString(byte[] digest) { StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); } return sb.toString(); }
// 根据名称创建MessageDigest: private MessageDigest getMessageDigest(String name) throws ServletException { try { return MessageDigest.getInstance(name); } catch (NoSuchAlgorithmException e) { throw new ServletException(e); } } }
2. ReReadableHttpServletRequest 参考教程
**3. uploadController **
package com.controller;
import com.framework.ModelAndView; import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map;
public class uploadController { @PostMapping(value = "/upload/txt") public ModelAndView uploadText(HttpServletRequest request, HttpServletResponse response) throws IOException { ModelAndView mv=new ModelAndView(); // 读取Request Body: InputStream input = request.getInputStream(); int length=request.getContentLength(); ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[length]; StringBuilder sb=new StringBuilder(); int n; while((n=input.read())!=-1){ sb.append((char)n); } String uploadedText = output.toString(String.valueOf(StandardCharsets.UTF_8));
return new ModelAndView("/showText.html",Map.of("text",sb)); }
@PostMapping(value = "/uploadError") public ModelAndView uploadError(HttpServletRequest request, HttpServletResponse response) throws IOException { Map<String,Object> map=new HashMap<>(); map.put("errorMsg","文件上传失败,请重新上传"); return new ModelAndView("/uploadError.html",map); } }
4. 上传文件展示页面、上传错误页面
<!DOCTYPE html\>
<html lang\="en"\> <head> <meta charset\="UTF-8"\> <title>Title</title> </head> <body> {{text}} </body> </html>
<html lang\="en"\> <head> <meta charset\="UTF-8"\> <title>Title</title> </head> <body> <span style\="color:darkred"\> <h1><b>{{ errorMsg }}}</b></h1> </span> </body> </html>
5. burpsuite模拟上传文件请求
POST /upload/txt HTTP/1.1
Host: 192.168.110.66:8085
Proxy-Connection: keep-alive
Content-Length: 9
Cache-Control: max-age=0
Signature-Method: SHA-1
Signature: 7115e9890f5b5cc6914bdfa3b7c011db1cdafedb
Upgrade-Insecure-Requests: 1
Origin: http://192.168.110.66:8085
Content-Type: application/octet-stream
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.47
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.110.66:8085/signin
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
test-data
Sign in to make a reply
净净一隅
**1. UploadFilter **
package com.filter;
import com.framework.ModelAndView;
import com.proxy.ReReadableHttpServletRequest;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@WebFilter
public class UploadFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("验证文件完整性开始");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// 获取客户端传入的签名方法和签名:
String digest = req.getHeader("Signature-Method");
String signature = req.getHeader("Signature");
if (digest == null || digest.isEmpty() || signature == null || signature.isEmpty()) {
resp.sendRedirect("/uploadError");
return;
}
// 读取Request的Body并验证签名:
MessageDigest md = getMessageDigest(digest);
InputStream input = new DigestInputStream(request.getInputStream(), md);
byte[] buffer = new byte[request.getContentLength()];
for (;;) {
int len = input.read(buffer);
if (len == -1) {
break;
}
}
String actual = toHexString(md.digest());
if (!signature.equals(actual)) {
resp.sendRedirect("/uploadError");
return;
}
System.out.println("文件完整性验证成功");
// 验证成功后继续处理:
//chain.doFilter(request, response);
chain.doFilter(new ReReadableHttpServletRequest(req, buffer),response);
}
// 将byte[]转换为hex string:
private String toHexString(byte[] digest) {
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
// 根据名称创建MessageDigest:
private MessageDigest getMessageDigest(String name) throws ServletException {
try {
return MessageDigest.getInstance(name);
} catch (NoSuchAlgorithmException e) {
throw new ServletException(e);
}
}
}
2. ReReadableHttpServletRequest 参考教程
**3. uploadController **
package com.controller;
import com.framework.ModelAndView;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class uploadController {
@PostMapping(value = "/upload/txt")
public ModelAndView uploadText(HttpServletRequest request, HttpServletResponse response) throws IOException {
ModelAndView mv=new ModelAndView();
// 读取Request Body:
InputStream input = request.getInputStream();
int length=request.getContentLength();
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[length];
StringBuilder sb=new StringBuilder();
int n;
while((n=input.read())!=-1){
sb.append((char)n);
}
String uploadedText = output.toString(String.valueOf(StandardCharsets.UTF_8));
return new ModelAndView("/showText.html",Map.of("text",sb));
}
@PostMapping(value = "/uploadError")
public ModelAndView uploadError(HttpServletRequest request, HttpServletResponse response) throws IOException {
Map<String,Object> map=new HashMap<>();
map.put("errorMsg","文件上传失败,请重新上传");
return new ModelAndView("/uploadError.html",map);
}
}
4. 上传文件展示页面、上传错误页面
<!DOCTYPE html\>
<html lang\="en"\> <head> <meta charset\="UTF-8"\> <title>Title</title> </head> <body> {{text}} </body> </html>
<!DOCTYPE html\>
<html lang\="en"\> <head> <meta charset\="UTF-8"\> <title>Title</title> </head> <body> <span style\="color:darkred"\> <h1><b>{{ errorMsg }}}</b></h1> </span> </body> </html>
5. burpsuite模拟上传文件请求
POST /upload/txt HTTP/1.1
Host: 192.168.110.66:8085
Proxy-Connection: keep-alive
Content-Length: 9
Cache-Control: max-age=0
Signature-Method: SHA-1
Signature: 7115e9890f5b5cc6914bdfa3b7c011db1cdafedb
Upgrade-Insecure-Requests: 1
Origin: http://192.168.110.66:8085
Content-Type: application/octet-stream
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.47
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.110.66:8085/signin
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
test-data