springboot项目拦截前端请求中的特殊字符串
项目场景:springboot项目中,需要对前端请求数据进行过滤,拦截特殊字符。问题描述GET请求可以很方便的通过处理URL判断是否包含特殊字符,POST类型请求需要对form-data/json特殊处理,使用@RequestBody注解的controller获取不到数据原因分析:request中的getInputStream()方法和getReader()方法只能获取一次数据,通过@Reques
·
项目场景:
springboot项目中,需要对前端请求数据进行过滤,拦截特殊字符。
问题描述
GET请求可以很方便的通过处理URL判断是否包含特殊字符,POST类型请求需要对form-data/json特殊处理,使用@RequestBody注解的controller获取不到数据
原因分析:
request中的getInputStream()方法和getReader()方法只能获取一次数据,通过@RequestBody注解再次获取getInputStream()拿到结果为空,此处通过重写getInputStream()方法和getReader()解决。贴出完整代码如下。
解决方案:
1、注册拦截器
package com.xxx;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author lsh
* @version 1.0
* @date 2022/4/1 16:54
*/
@Configuration
public class SpecialCharConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
if(registry!=null){
registry.addInterceptor(new SpecialCharInterceptor()).addPathPatterns("/**");
}
}
}
2、注册过滤器
package com.xxx;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author lsh
* @version 1.0
* @date 2022/4/1 17:03
*/
@Component
@WebFilter(filterName="specialCharFilter",urlPatterns="/*")
public class SpecialCharFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest){
requestWrapper = new SpecialCharHttpServletRequestWrapper((HttpServletRequest) request);
}
// 获取请求中的流,将取出来的字符串,再次转换成流,然后把它放入到新request对象中
// 在chain.doFiler方法中传递新的request对象
if(requestWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void destroy() {
}
}
3、自定义保存流数据
package com.xxx;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* 自定义保存流数据
* @author lsh
* @version 1.0
* @date 2022/4/1 16:56
*/
public class SpecialCharHttpServletRequestWrapper extends HttpServletRequestWrapper {
public final HttpServletRequest request;
private final String bodyStr;
public SpecialCharHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.request = request;
this.bodyStr = getBodyString();
}
/**
* 获取请求Body
* @return
*/
public String getBodyString() {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = cloneInputStream(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();
}
/**
* 复制输入流
* @param inputStream 输入流
* @return
*/
public InputStream cloneInputStream(ServletInputStream inputStream) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
try {
while ((len = inputStream.read(buffer)) > -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
byteArrayOutputStream.flush();
}
catch (IOException e) {
e.printStackTrace();
}
InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
return byteArrayInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(bodyStr.getBytes(Charset.forName("UTF-8")));
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public boolean isReady() {
return false;
}
@Override
public boolean isFinished() {
return false;
}
};
}
}
4、特殊字符拦截类(application/json的数据格式只能为json和json数组,根据业务场景自行调整)
package com.xxx;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 拦截请求中包含的特殊字符
* @author lsh
* @version 1.0
* @date 2022/4/1 16:27
*/
public class UrlFilter {
/**
* 特殊字符正则表达式
*/
private final static String REG_EX = "[`~!@#$%^*()+|{}\\[\\].<>/?!()【】‘;:”“’。,、\\\\]";
/**
* 判断url中是否含有特殊字符
* @param urls 前端请求链接
* @return 是否包含特殊字符
*/
public static boolean checkSpecials(String urls) {
try {
if (StringUtils.isNotEmpty(urls)) {
// url参数转义
urls = URLDecoder.decode(urls, "utf-8");
if (Pattern.compile(REG_EX).matcher(urls).find()) {
return true;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return false;
}
/**
* 判断formData值对象中是否包含特殊字符
* @param map formData值对象
* @return 是否包含特殊字符
*/
public static boolean checkSpecials(Map<String,String[]> map){
if(!map.isEmpty()){
for(String[] paraArray : map.values()){
for(String paraStr : paraArray){
if(Pattern.compile(REG_EX).matcher(paraStr).find()){
return true;
}
}
}
}
return false;
}
/**
* 判断前端传过来的json和json数组中是否含有特殊字符
* @param request 前端请求(包含json数据)
* @return 是否包含特殊字符
*/
public static boolean checkSpecials(HttpServletRequest request) {
try {
SpecialCharHttpServletRequestWrapper wrapper = new SpecialCharHttpServletRequestWrapper(request);
InputStream is = wrapper.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
if (sb.length() > 0) {
//判断json是否包含list数组,包含则先遍历数组再遍历对象值
if (sb.toString().contains("[")){
List<Object> objectList = JSONObject.parseObject(sb.toString(), new TypeReference<List<Object>>() {});
for(Object objTemp:objectList){
Map<String, Object> map = JSONObject.parseObject(JSONObject.parseObject(objTemp.toString()).toJSONString(), new TypeReference<Map<String, Object>>() {});
for (Object object : map.values()) {
if (object != null) {
Matcher m = Pattern.compile(REG_EX).matcher(object.toString());
if (m.find()) {
return true;
}
}
}
}
}else{
Map<String, Object> map = JSONObject.parseObject(JSONObject.parseObject(sb.toString()).toJSONString(), new TypeReference<Map<String, Object>>() {});
for (Object object : map.values()) {
if (object != null) {
Matcher m = Pattern.compile(REG_EX).matcher(object.toString());
if (m.find()) {
return true;
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
5、实现拦截器
package com.xxx;
import org.springframework.lang.Nullable;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 特殊字符过滤
* @author lsh
* @version 1.0
* @date 2022/4/1 16:25
*/
public class SpecialCharInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
if("GET".equals(httpServletRequest.getMethod())){
if(UrlFilter.checkSpecials(httpServletRequest.getQueryString())){
throw new Exception("url中包含特殊字符");
}
}else{
String contentType = httpServletRequest.getContentType();
//处理form-data请求类型数据值
if (contentType != null && contentType.contains("multipart/form-data")) {
MultipartResolver resolver = new CommonsMultipartResolver(httpServletRequest.getSession().getServletContext());
MultipartHttpServletRequest multipartRequest = resolver.resolveMultipart(httpServletRequest);
if(UrlFilter.checkSpecials(multipartRequest.getParameterMap())){
throw new Exception("请求参数中包含特殊字符");
}
}
else{
if(UrlFilter.checkSpecials(httpServletRequest)){
throw new Exception("请求的数据中包含特殊字符 ");
}
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
更多推荐
已为社区贡献2条内容
所有评论(0)