Java 在spring筛选器中解析多部分/表单数据请求
我正试图在Spring MVC 3中开发我自己的Java 在spring筛选器中解析多部分/表单数据请求,java,spring,forms,spring-mvc,servlets,Java,Spring,Forms,Spring Mvc,Servlets,我正试图在Spring MVC 3中开发我自己的CSRF过滤器(有一些额外的培训促使我这么做,这就是为什么我不考虑Spring安全性。) 我的过滤器适用于所有表单,除了那些具有enctype=“multipart/form data”的表单。因此,我无法从正常的HttpServletRequest获取请求参数 我曾尝试将HttpServletRequest转换为multipartttpServletrequest,但我发现我也不能这样做 我的目标不是从请求中获取文件,而是只获取名为csrf的简单
CSRF过滤器
(有一些额外的培训促使我这么做,这就是为什么我不考虑Spring安全性。)
我的过滤器适用于所有表单,除了那些具有enctype=“multipart/form data”
的表单。因此,我无法从正常的HttpServletRequest获取请求参数
我曾尝试将HttpServletRequest
转换为multipartttpServletrequest
,但我发现我也不能这样做
我的目标不是从请求中获取文件,而是只获取名为csrf
的简单表单输入。(我已经上传了我表格中的文件)
这是我到目前为止的代码:
CSRFilter
public class CSRFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
CSRF csrf = new CSRF(req);
if(csrf.isOk()){
chain.doFilter(req, res);
}else {
//todo : Show Error Page
String redirect = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/access-forbidden";
response.sendRedirect(redirect);
}
}
}
CSRF
public class CSRF {
HttpServletRequest request;
ServletRequest req;
String token;
boolean ok;
private static final Logger logger = Logger.getLogger(CSRF.class);
public CSRF(ServletRequest request) {
this.request = (HttpServletRequest) request;
this.req = request;
init();
}
public CSRF() {
}
public void setRequest(HttpServletRequest request) {
this.request = (HttpServletRequest) request;
this.req = request;
init();
}
private void init() {
if (request.getMethod().equals("GET")) {
generateToken();
addCSRFTokenToSession();
addCSRFTokenToModelAttribute();
ok = true;
} else if (request.getMethod().equals("POST")) {
if (checkPostedCsrfToken()) {
ok = true;
}
}
}
private void generateToken() {
String token;
java.util.Date date = new java.util.Date();
UUID uuid = UUID.randomUUID();
token = uuid.toString() + String.valueOf(new Timestamp(date.getTime()));
try {
this.token = sha1(token);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
this.token = token;
}
}
private void addCSRFTokenToSession() {
request.getSession().setAttribute("csrf", token);
}
private void addCSRFTokenToModelAttribute() {
request.setAttribute("csrf", token);
}
private boolean checkPostedCsrfToken() {
System.out.println("____ CSRF CHECK POST _____");
if (request.getParameterMap().containsKey("csrf")) {
String csrf = request.getParameter("csrf");
if (csrf.equals(request.getSession().getAttribute("csrf"))) {
return true;
}
}else {
//Check for multipart requests
MultipartHttpServletRequest multiPartRequest = new DefaultMultipartHttpServletRequest((HttpServletRequest) req);
if (multiPartRequest.getParameterMap().containsKey("csrf")) {
String csrf = multiPartRequest.getParameter("csrf");
if (csrf.equals(request.getSession().getAttribute("csrf"))) {
return true;
}
}
}
log();
return false;
}
private void log() {
HttpSession session = request.getSession();
String username = (String) session.getAttribute("username");
if(username==null){
username = "unknown (not logged in)";
}
String ipAddress = request.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
ipAddress = request.getRemoteAddr();
}
String userAgent = request.getHeader("User-Agent");
String address = request.getRequestURI();
System.out.println("a CSRF attack detected from IP: " + ipAddress + " in address \"" + address + "\" - Client User Agent : " + userAgent + " Username: " + username);
logger.error("a CSRF attack detected from IP: " + ipAddress + " in address \"" + address + "\" - Client User Agent : " + userAgent + " Username: " + username);
}
public boolean isOk() {
return ok;
}
static String sha1(String input) throws NoSuchAlgorithmException {
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] result = mDigest.digest(input.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < result.length; i++) {
sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
}
公共类CSRF{
HttpServletRequest请求;
ServletRequest-req;
字符串标记;
布尔ok;
私有静态最终记录器=Logger.getLogger(CSRF.class);
公共CSRF(ServletRequest){
this.request=(HttpServletRequest)请求;
this.req=请求;
init();
}
公共服务{
}
公共void setRequest(HttpServletRequest){
this.request=(HttpServletRequest)请求;
this.req=请求;
init();
}
私有void init(){
if(request.getMethod().equals(“GET”)){
generateToken();
addCSRFTokenToSession();
addCSRFTokenToModelAttribute();
ok=正确;
}else if(request.getMethod().equals(“POST”)){
if(checkPostedCsrfToken()){
ok=正确;
}
}
}
私有void generateToken(){
字符串标记;
java.util.Date Date=新建java.util.Date();
UUID UUID=UUID.randomUUID();
token=uuid.toString()+String.valueOf(新的时间戳(date.getTime());
试一试{
this.token=sha1(token);
}捕获(无算法异常){
e、 printStackTrace();
this.token=token;
}
}
私有void addCSRFTokenToSession()函数{
request.getSession().setAttribute(“csrf”,令牌);
}
私有void addCSRFTokenToModelAttribute(){
setAttribute(“csrf”,令牌);
}
私有布尔checkPostedCsrfToken(){
System.out.println(“CSRF检查柱”);
if(request.getParameterMap().containsKey(“csrf”)){
字符串csrf=request.getParameter(“csrf”);
if(csrf.equals(request.getSession().getAttribute(“csrf”)){
返回true;
}
}否则{
//检查多部分请求
MultipartTTpServletRequest multiPartRequest=新的默认MultipartTTpServletRequest((HttpServletRequest)req);
if(multiPartRequest.getParameterMap().containsKey(“csrf”)){
字符串csrf=multiPartRequest.getParameter(“csrf”);
if(csrf.equals(request.getSession().getAttribute(“csrf”)){
返回true;
}
}
}
log();
返回false;
}
私有无效日志(){
HttpSession session=request.getSession();
字符串用户名=(字符串)session.getAttribute(“用户名”);
如果(用户名==null){
用户名=“未知(未登录)”;
}
字符串ipAddress=request.getHeader(“X-FORWARDED-FOR”);
如果(ipAddress==null){
ipAddress=request.getRemoteAddr();
}
字符串userAgent=request.getHeader(“用户代理”);
字符串地址=request.getRequestURI();
System.out.println(“从IP检测到CSRF攻击:“+ipAddress+”地址\”“+address+“\”-客户端用户代理:“+userAgent+”用户名:“+Username”);
logger.error(“从IP检测到CSRF攻击:“+ipAddress+”,地址\“+address+”\”-客户端用户代理:“+userAgent+”用户名:“+Username”);
}
公共布尔isOk(){
返回ok;
}
静态字符串sha1(字符串输入)抛出NoSuchAlgorithmException{
MessageDigest mDigest=MessageDigest.getInstance(“SHA1”);
byte[]result=mDigest.digest(input.getBytes());
StringBuffer sb=新的StringBuffer();
for(int i=0;i
我的调度员中也有这一行:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="40000000"/>
</bean>
我还使用springMultipartResolver过滤器
<filter>
<display-name>springMultipartFilter</display-name>
<filter-name>springMultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>springMultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</filter>
springMultipartFilter
springMultipartFilter
org.springframework.web.multipart.support.MultipartFilter
springMultipartFilter
/*
当我在多部分/表单数据表单上尝试时,我得到java.lang.IllegalStateException:Multipart请求未初始化
异常
我看了很多互联网上的例子。其中大多数都是为了文件上传的目的,对我没有帮助,我还尝试了不同的方法将HttpServletRequest转换为任何其他对象,这些对象会给我解析的多部分请求,但我没有成功
我怎么做
谢谢。您不能将
HttpServletRequest
强制转换为multipartttpServletrequest
,因为您首先必须解决您的请求
我使用了commonmultipartresolver
类,并使用commonmultipartresolver.resolveMultipart(request)
方法获得了multipartttpServletRequest
)
下面是我的CSRF类,checkPostedCsrfToken()
方法:
private boolean checkPostedCsrfToken() {
if (request.getParameterMap().containsKey("csrf")) {
String csrf = request.getParameter("csrf");
if (csrf.equals(request.getSession().getAttribute("csrf"))) {
return true;
}
} else if (request.getContentType() != null && request.getContentType().toLowerCase().contains("multipart/form-data")) {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
MultipartHttpServletRequest multipartRequest = commonsMultipartResolver.resolveMultipart(request);
if (multipartRequest.getParameterMap().containsKey("csrf")) {
String csrf = multipartRequest.getParameter("csrf");
if (csrf.equals(request.getSession().getAttribute("csrf"))) {
return true;
}
}
}
log();
return false;
}
但是,请注意,使用这种方法最终会丢失所有请求参数和数据。因此,您必须扩展HttpServletRequestWrapper
类来读取请求字节并使用它们获取参数
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
private ByteArrayOutputStream cachedBytes;
public MultiReadHttpServletRequest(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (cachedBytes == null)
cacheInputStream();
return new CachedServletInputStream();
}
@Override
public BufferedReader getReader() throws IOException{
return new BufferedReader(new InputStreamReader(getInputStream()));
}
private void cacheInputStream() throws IOException {
/* Cache the inputstream in order to read it multiple times. For
* convenience, I use apache.commons IOUtils
*/
cachedBytes = new ByteArrayOutputStream();
IOUtils.copy(super.getInputStream(), cachedBytes);
}
/* An inputstream which reads the cached request body */
public class CachedServletInputStream extends ServletInputStream {
private ByteArrayInputStream input;
public CachedServletInputStream() {
/* create a new input stream from the cached request body */
input = new ByteArrayInputStream(cachedBytes.toByteArray());
}
@Override
public int read() throws IOException {
return input.read();
}
}
}
public class CSRFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// The important part!! wrap the request:
MultiReadHttpServletRequest multiReadHttpServletRequest = new MultiReadHttpServletRequest(request);
CSRF csrf = new CSRF(multiReadHttpServletRequest);
if(csrf.isOk()){
chain.doFilter(multiReadHttpServletRequest, res);
}else {
//todo : Show Error Page
String redirect = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/access-forbidden";
response.sendRedirect(redirect);
}
}
}
HttpServletRequest requestWrapper = new RereadableServletRequest(servletRequest);