VUE前端发送post请求,在SQL注入过滤时,后台通过request.getparamter无法获取属性值的解决

最近做vue项目,后端在写sql注入过滤器的时候,遇上vue发送post请求,后端request.getparamter无法获取到传递参数变量的属性值,进过使用postman工具测试分析出

vue前端和post工具传输入数据格式不一致

1.vue前端post请求采用的是json数据格式

2.而用postman测试工具采用的是form表单方式,相当于URL带参数传递

所以导致后端request.getparamter无法获取数据

解决方法:

读取输入流来获取

 post请求不是application/x-www-form-urlencoded的,全部直接返回,不作处理,即不会解析表单数据来放到requestparametermap中。所以通过request.getParameter(name)是获取不到的。只能使用最原始的方式,读取输入流来获取。

而在filter过滤器使用输入流来获取数据的时候,又发生了getInputStream has already been called for this request错误,导致过滤器过不去,登录不进去系统

报错原因:

HttpServletRequest.getReader()
HttpServletRequest.getInputStream() 不能在过滤器中读取一次二进制流(字符流),又在另外一个Servlet中读取一次,即一个InputSteam(BufferedReader)对象在被读取完成后,将无法再次被读取。

也就是从请求中获取流以后,流被filter中的这个 inputStreamToString(InputStream in) 这个方法处理后就被“消耗”了,这会导致,chain.doFilter(request, res)这个链在传递 request对象的时候,里面的请求流为空,导致责任链模式下,其他下游的链无法获取请求的body,从而导致程序无法正常运行,这也使得我们的这个filter虽然可以获取请求信息,但是它会导致整个应用程序不可用

报错解决思路如下:

将取出来的字符串,再次转换成流,然后把它放入到新request 对象中,在chain.doFiler方法中 传递新的request对象;

要实现这种思路,需要自定义一个类继承HttpServletRequestWrapper,然后重写public BufferedReader getReader()方法,public ServletInputStream getInputStream()方法;(这两个方法的重写实现逻辑如下:getInputStream()方法中将body体中的字符串转换为字节流(它实质上返回的是一个ServletInputStream 对象);然后通过getReader()调用---->getInputStream()方法;),继承实现重写逻辑以后,在sql过滤器filter(SqlInjectionFilter)中,使用自定义的HttpServletRequestWrapper(RepeatedlyReadRequestWrapper)将原始的HttpServletRequest对象进行再次封装;再通过RepeatedlyReadRequestWrapper对象去做dofilter(req,res)的req对象;

一、sql过滤代码 SqlInjectionFilter.java

package com.hitek.module.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;

import com.alibaba.fastjson.JSONObject;
 
public class SqlInjectionFilter implements Filter {
 

	public void destroy() {
		// TODO Auto-generated method stub
		
	}


	public void doFilter(ServletRequest args0, ServletResponse args1,
            FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req=(HttpServletRequest)args0;
        HttpServletResponse res=(HttpServletResponse)args1;
         //获得所有请求参数名
        Enumeration params = req.getParameterNames();
        String sql = "";
        String url = ((HttpServletRequest) req).getRequestURL().toString().trim();
        HttpSession userSession = req.getSession();
        while (params.hasMoreElements()) {
            //得到参数名
            String name = params.nextElement().toString();
            if (StringUtils.isNotBlank(name)) {
            	if (name.equalsIgnoreCase("method") || name.equalsIgnoreCase("fileCode")) {
            		continue;
            	}
            }
            //System.out.println("name===========================" + name + "--");
            //得到参数对应值
            String[] value = req.getParameterValues(name);
            for (int i = 0; i < value.length; i++) {
                sql = sql + value[i];
            }
        }
       //vue请求重新包装一个ServletRequest
        ServletRequest requestWrapper = new RepeatedlyReadRequestWrapper(req);
        String body = HttpHelper.getBodyString(requestWrapper);		    
 		//如果是POST请求则需要获取 param 参数
	   String param = URLDecoder.decode(body,"utf-8");
 		if(param!=null&&!"".equals(param)||"".equals(sql)){
 	        //System.out.println("============================SQL"+sql);
 			sql = param;
 			sql = sql.replaceAll("\\{", "");
 			sql = sql.replaceAll("\\}", "");
 			sql = sql.replaceAll("\"", "");
 			sql = sql.replaceAll(":", "");
 			sql = sql.replaceAll(",", "");
 			if (sqlValidate(sql)) {
                 throw new IOException("您发送请求中的参数中含有非法字符");
                 //String ip = req.getRemoteAddr();
             } else {
            	 chain.doFilter(requestWrapper,args1);
             } 
 		}else{
			if (sqlValidate(sql)) {
             throw new IOException("您发送请求中的参数中含有非法字符");
             //String ip = req.getRemoteAddr();
         } else {
             chain.doFilter(args0,args1);
         }
 		}
	}


	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	//效验
    protected static boolean sqlValidate(String str) {
        str = str.toLowerCase();//统一转为小写
        String badStr = "and|exec|execute|insert|select|delete|update|count|drop|*|chr|mid|master|truncate|" +
                "char|declare|sitename|net user|xp_cmdshell|;|or|-|+|and|exec|execute|insert|create|drop|" +
                "table|from|grant|use|group_concat|column_name|" +
                "information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|" +
                "chr|mid|master|truncate|char|declare|or|;|-|--|+|like|#";//过滤掉的sql关键字,可以手动添加
        String[] badStrs = badStr.split("\\|");
        for (int i = 0; i < badStrs.length; i++) {
            if (str.indexOf(badStrs[i]) >= 0) {
            	if (!validateSpecialKeyword(badStrs[i],str)) {
            		return true;
            	}
            }
        }
        return false;
    }
    
    private static boolean validateSpecialKeyword(String keyword,String str) {
    	if (StringUtils.isNotBlank(keyword)) {
    		if (StringUtils.isNotBlank(str)) {
    			if (!keyword.equals(";")) {
    				String[] arrStr = splitStr(keyword,str);
    				for (int i = 0; i < arrStr.length; i++) {
    					String s = arrStr[i];
    					if (s.startsWith(keyword)) {
    						if (s.length() == keyword.length()) {
    							continue;
    						}
    						System.out.println(keyword.length()+"-----"+s.charAt(keyword.length()));
    						if (s.charAt(keyword.length()) != ' ') {
    							continue;
    						} else {
    							return false;
    						}
    					}
    				} 
    			} else {
    				String[] arrStr = splitStr(keyword,str);
    				for (int i = 0; i < arrStr.length; i++) {
    					String s = arrStr[i];
    					System.out.println("s.length=====>"+s.length());
    					if (s.startsWith(keyword)) {
    						if (s.length() == keyword.length()) {
    							continue;
    						}
    						if (s.charAt(keyword.length()) == '*') {
    							continue;
    						} else {
    							return false;
    						}
    					}
    				} 
    			}
    		}
    	}
    	return true;
    }
    
    private static String[] splitStr(String keyword,String str) {
    	List<String> sList = new ArrayList<String>();
    	String s = str;
    	int nu = -1;
    	Character c = null;
    	while ((nu = s.indexOf(keyword)) >= 0) {
    		String tmpStr = "";
    		if (c != null) {
    			tmpStr = c.toString();
    			tmpStr += s.substring(0,nu);
    		} else {
    			tmpStr = s.substring(0,nu);
    		}
    		s = s.substring(nu);
    		c = s.charAt(0);
    		s = s.substring(1);
    		sList.add(tmpStr);
    	}
    	if (c != null) {
    		sList.add(c.toString() + s);
    	} else {
    		sList.add(s);
    	}
    	
    	String[] arr = new String[sList.size()];
    	sList.toArray(arr);
    	return arr;
    }
    
}

重新包装类:RepeatedlyReadRequestWrapper.java

package com.hitek.module.util;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;

/**
 * @author zhuningyi
 * @desc 重复读取HttpServletRequest reader/inputstream
 * @date 2023/8/9
 */
public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper {

	private final byte[] body;

    public RepeatedlyReadRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        System.out.println("-------------------------------------------------");  
        Enumeration e = request.getHeaderNames()   ;  
         while(e.hasMoreElements()){  
             String name = (String) e.nextElement();  
             String value = request.getHeader(name);  
             System.out.println(name+" = "+value);  
               
         }  
        body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        final ByteArrayInputStream bais = new ByteArrayInputStream(body);

        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }

	@Override
	public String getHeader(String name) {
		return super.getHeader(name);
	}

	@Override
	public Enumeration<String> getHeaderNames() {
		return super.getHeaderNames();
	}

	@Override
	public Enumeration<String> getHeaders(String name) {
		return super.getHeaders(name);
	}
}

HttpHelper.java

package com.hitek.module.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import javax.servlet.ServletRequest;

public class HttpHelper {
	/**
     * 获取请求Body
     *
     * @param request
     * @return
     */
    public static String getBodyString(ServletRequest request) {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过在发送 POST 请求,在请求头中添加一个标记,然后在接收响应再移除这个标记。在 Vue.js 中,可以使用 Axios 的拦截器来实现这个功能。 首先,在 Vue.js 中引入 Axios: ```javascript import axios from 'axios'; ``` 然后,定义一个 Axios 实例: ```javascript const axiosInstance = axios.create({ baseURL: 'http://example.com/api', timeout: 5000, headers: { 'Content-Type': 'application/json' } }); ``` 接下来,在 Axios 实例中添加请求拦截器: ```javascript axiosInstance.interceptors.request.use(config => { // 在请求头中添加一个标记 config.headers['X-Loading'] = true; return config; }, error => { return Promise.reject(error); }); ``` 在请求拦截器中,可以在请求头中添加一个名为 X-Loading 的标记。这个标记的可以是任意,我们可以通过这个标记来判断是否需要显示加载动画。 接着,在 Axios 实例中添加响应拦截器: ```javascript axiosInstance.interceptors.response.use(response => { // 移除请求头中的标记 delete response.config.headers['X-Loading']; return response; }, error => { delete error.config.headers['X-Loading']; return Promise.reject(error); }); ``` 在响应拦截器中,可以移除请求头中的 X-Loading 标记。 最后,在 Vue.js 中使用 Axios 发送 POST 请求,可以在发送请求前显示加载动画,在接收响应隐藏加载动画: ```javascript export default { data() { return { loading: false }; }, methods: { async submitForm() { try { this.loading = true; await axiosInstance.post('/login', { username: 'test', password: 'test' }); this.loading = false; } catch (error) { this.loading = false; console.log(error); } } } }; ``` 在 Vue.js 组件中,可以定义一个 loading 变量来控制加载动画的显示和隐藏。在调用 Axios 的 post 方法,可以先将 loading 变量设置为 true,表示正在加载中。在接收响应,再将 loading 变量设置为 false,表示加载完成。如果发生错误,也需要将 loading 变量设置为 false。 在模板中可以使用 loading 变量来控制加载动画的显示和隐藏: ```html <template> <div> <form @submit.prevent="submitForm"> <input type="text" v-model="username" placeholder="Username"> <input type="password" v-model="password" placeholder="Password"> <button type="submit">Submit</button> </form> <div v-if="loading">Loading...</div> </div> </template> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值