当前位置:   article > 正文

springboot防止XSS攻击&&SQL防注入_springboot防止 sql注入

springboot防止 sql注入

一.结构:

XssAndSqlHttpServletRequestWrapper      请求过滤类

CrosXssFilterConfigUtil                               注入防护开关工具类

CrosXssFilterConfig                                    sql xss过滤器

二.代码 

1. 创建请求过滤类XssAndSqlHttpServletRequestWrapper

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import org.springframework.util.StreamUtils;
  4. import javax.servlet.ReadListener;
  5. import javax.servlet.ServletInputStream;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletRequestWrapper;
  8. import java.io.BufferedReader;
  9. import java.io.ByteArrayInputStream;
  10. import java.io.IOException;
  11. import java.io.InputStreamReader;
  12. import java.util.*;
  13. import java.util.regex.Pattern;
  14. /**
  15. * @Description 请求过滤类
  16. */
  17. public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {
  18. private final Logger logger = LoggerFactory.getLogger(XssAndSqlHttpServletRequestWrapper.class);
  19. private String key = "and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+";
  20. private Set<String> notAllowedKeyWords = new HashSet<String>(0);
  21. HttpServletRequest orgRequest = null;
  22. private Map<String, String[]> parameterMap;
  23. private final byte[] body; //用于保存读取body中数据
  24. public XssAndSqlHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
  25. super(request);
  26. orgRequest = request;
  27. parameterMap = request.getParameterMap();
  28. body = StreamUtils.copyToByteArray(request.getInputStream());
  29. String keyStr[] = key.split("\\|");
  30. for (String str : keyStr) {
  31. notAllowedKeyWords.add(str);
  32. }
  33. }
  34. // 重写几个HttpServletRequestWrapper中的方法
  35. /**
  36. * 获取所有参数名
  37. *
  38. * @return 返回所有参数名
  39. */
  40. @Override
  41. public Enumeration<String> getParameterNames() {
  42. Vector<String> vector = new Vector<String>(parameterMap.keySet());
  43. return vector.elements();
  44. }
  45. /**
  46. * 覆盖getParameter方法,将参数名和参数值都做xss &amp; sql过滤。<br>
  47. * 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br>
  48. * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
  49. */
  50. @Override
  51. public String getParameter(String name) {
  52. String[] results = parameterMap.get(name);
  53. if (results == null || results.length == 0)
  54. return null;
  55. else {
  56. String value = results[0];
  57. if (value != null) {
  58. value = xssEncode(value);
  59. }
  60. return value;
  61. }
  62. }
  63. @Override
  64. public Map<String, String[]> getParameterMap() {
  65. Map<String,String[]> values = super.getParameterMap();
  66. if(null == values){
  67. return null;
  68. }
  69. Map<String,String[]> result = new HashMap<>();
  70. for (String key : values.keySet()) {
  71. String encodedKey = xssEncode(key);
  72. int count = values.get(key).length;
  73. String[] encodedValues = new String[count];
  74. for(int i = 0;i < count;i++){
  75. encodedValues[i] = xssEncode(values.get(key)[i]);
  76. }
  77. result.put(encodedKey,encodedValues);
  78. }
  79. return result;
  80. }
  81. /**
  82. * 获取指定参数名的所有值的数组,如:checkbox的所有数据 接收数组变量 ,如checkobx类型
  83. */
  84. @Override
  85. public String[] getParameterValues(String name) {
  86. String[] results = parameterMap.get(name);
  87. if (results == null || results.length == 0)
  88. return null;
  89. else {
  90. int length = results.length;
  91. for (int i = 0; i < length; i++) {
  92. results[i] = xssEncode(results[i]);
  93. }
  94. return results;
  95. }
  96. }
  97. /**
  98. * 覆盖getHeader方法,将参数名和参数值都做xss &amp; sql过滤。<br>
  99. * 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br>
  100. * getHeaderNames 也可能需要覆盖
  101. */
  102. @Override
  103. public String getHeader(String name) {
  104. String value = super.getHeader(xssEncode(name));
  105. if (value != null) {
  106. value = xssEncode(value);
  107. }
  108. return value;
  109. }
  110. /**
  111. * 将容易引起xss &amp; sql漏洞的半角字符直接替换成全角字符
  112. *
  113. * @param s
  114. * @return
  115. */
  116. private String xssEncode(String s) {
  117. if (s == null || s.isEmpty()) {
  118. return s;
  119. } else {
  120. s = stripXSSAndSql(s);
  121. }
  122. StringBuilder sb = new StringBuilder(s.length() + 16);
  123. for (int i = 0; i < s.length(); i++) {
  124. char c = s.charAt(i);
  125. switch (c) {
  126. case '>':
  127. sb.append(">");// 转义大于号
  128. break;
  129. case '<':
  130. sb.append("<");// 转义小于号
  131. break;
  132. case '\'':
  133. sb.append("'");// 转义单引号
  134. break;
  135. case '\"':
  136. sb.append(""");// 转义双引号
  137. break;
  138. case '&':
  139. sb.append("&");// 转义&
  140. break;
  141. case '#':
  142. sb.append("#");// 转义#
  143. break;
  144. default:
  145. sb.append(c);
  146. break;
  147. }
  148. }
  149. return sb.toString();
  150. }
  151. /**
  152. * 获取最原始的request
  153. *
  154. * @return
  155. */
  156. public HttpServletRequest getOrgRequest() {
  157. return orgRequest;
  158. }
  159. /**
  160. * 获取最原始的request的静态方法
  161. *
  162. * @return
  163. */
  164. @SuppressWarnings("unused")
  165. public HttpServletRequest getOrgRequest(HttpServletRequest req) {
  166. if (req instanceof XssAndSqlHttpServletRequestWrapper) {
  167. return ((XssAndSqlHttpServletRequestWrapper) req).getOrgRequest();
  168. }
  169. return req;
  170. }
  171. /**
  172. *
  173. * 防止xss跨脚本攻击(替换,根据实际情况调整)
  174. */
  175. public String stripXSSAndSql(String value) {
  176. if (value != null) {
  177. // NOTE: It's highly recommended to use the ESAPI library and
  178. // uncomment the following line to
  179. // avoid encoded attacks.
  180. // value = ESAPI.encoder().canonicalize(value);
  181. // Avoid null characters
  182. /** value = value.replaceAll("", ""); ***/
  183. // Avoid anything between script tags
  184. Pattern scriptPattern = Pattern.compile(
  185. "&lt;[\r\n| | ]*script[\r\n| | ]*&gt;(.*?)<!--[\r\n| | ]*script[\r\n| | ]*-->", Pattern.CASE_INSENSITIVE);
  186. value = scriptPattern.matcher(value).replaceAll("");
  187. // Avoid anything in a
  188. // src="http://www.yihaomen.com/article/java/..." type of
  189. // e-xpression
  190. scriptPattern = Pattern.compile("src[\r\n| | ]*=[\r\n| | ]*[\\\"|\\\'](.*?)[\\\"|\\\']",
  191. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  192. value = scriptPattern.matcher(value).replaceAll("");
  193. // Remove any lonesome tag
  194. scriptPattern = Pattern.compile("<!--[\r\n| | ]*script[\r\n| | ]*-->", Pattern.CASE_INSENSITIVE);
  195. value = scriptPattern.matcher(value).replaceAll("");
  196. // Remove any lonesome <script ...> tag
  197. scriptPattern = Pattern.compile("<[\r\n| | ]*script(.*?)>",
  198. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  199. value = scriptPattern.matcher(value).replaceAll("");
  200. // Avoid eval(...) expressions
  201. scriptPattern = Pattern.compile("eval\\((.*?)\\)",
  202. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  203. value = scriptPattern.matcher(value).replaceAll("");
  204. // Avoid e-xpression(...) expressions
  205. scriptPattern = Pattern.compile("e-xpression\\((.*?)\\)",
  206. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  207. value = scriptPattern.matcher(value).replaceAll("");
  208. // Avoid javascript:... expressions
  209. scriptPattern = Pattern.compile("javascript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);
  210. value = scriptPattern.matcher(value).replaceAll("");
  211. // Avoid vbscript:... expressions
  212. scriptPattern = Pattern.compile("vbscript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);
  213. value = scriptPattern.matcher(value).replaceAll("");
  214. // Avoid οnlοad= expressions
  215. scriptPattern = Pattern.compile("onload(.*?)=",
  216. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  217. value = scriptPattern.matcher(value).replaceAll("");
  218. }
  219. return value;
  220. }
  221. public boolean checkXSSAndSql(String value) {
  222. boolean flag = false;
  223. if (value != null) {
  224. // NOTE: It's highly recommended to use the ESAPI library and
  225. // uncomment the following line to
  226. // avoid encoded attacks.
  227. // value = ESAPI.encoder().canonicalize(value);
  228. // Avoid null characters
  229. /** value = value.replaceAll("", ""); ***/
  230. // Avoid anything between script tags
  231. Pattern scriptPattern = Pattern.compile(
  232. "<[\r\n| | ]*script[\r\n| | ]*>(.*?)</[\r\n| | ]*script[\r\n| | ]*>", Pattern.CASE_INSENSITIVE);
  233. flag = scriptPattern.matcher(value).find();
  234. if (flag) {
  235. return flag;
  236. }
  237. // Avoid anything in a
  238. // src="http://www.yihaomen.com/article/java/..." type of
  239. // e-xpression
  240. scriptPattern = Pattern.compile("src[\r\n| | ]*=[\r\n| | ]*[\\\"|\\\'](.*?)[\\\"|\\\']",
  241. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  242. flag = scriptPattern.matcher(value).find();
  243. if (flag) {
  244. return flag;
  245. }
  246. // Remove any lonesome </script> tag
  247. scriptPattern = Pattern.compile("<!--[\r\n| | ]*script[\r\n| | ]*-->", Pattern.CASE_INSENSITIVE);
  248. flag = scriptPattern.matcher(value).find();
  249. if (flag) {
  250. return flag;
  251. }
  252. // Remove any lonesome <script ...> tag
  253. scriptPattern = Pattern.compile("<[\r\n| | ]*script(.*?)>",
  254. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  255. flag = scriptPattern.matcher(value).find();
  256. if (flag) {
  257. return flag;
  258. }
  259. // Avoid eval(...) expressions
  260. scriptPattern = Pattern.compile("eval\\((.*?)\\)",
  261. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  262. flag = scriptPattern.matcher(value).find();
  263. if (flag) {
  264. return flag;
  265. }
  266. // Avoid e-xpression(...) expressions
  267. scriptPattern = Pattern.compile("e-xpression\\((.*?)\\)",
  268. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  269. flag = scriptPattern.matcher(value).find();
  270. if (flag) {
  271. return flag;
  272. }
  273. // Avoid javascript:... expressions
  274. scriptPattern = Pattern.compile("javascript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);
  275. flag = scriptPattern.matcher(value).find();
  276. if (flag) {
  277. return flag;
  278. }
  279. // Avoid vbscript:... expressions
  280. scriptPattern = Pattern.compile("vbscript[\r\n| | ]*:[\r\n| | ]*", Pattern.CASE_INSENSITIVE);
  281. flag = scriptPattern.matcher(value).find();
  282. if (flag) {
  283. return flag;
  284. }
  285. // Avoid οnlοad= expressions
  286. scriptPattern = Pattern.compile("onload(.*?)=",
  287. Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  288. flag = scriptPattern.matcher(value).find();
  289. if (flag) {
  290. return flag;
  291. }
  292. flag = checkSqlKeyWords(value);
  293. }
  294. return flag;
  295. }
  296. public boolean checkSqlKeyWords(String value){
  297. String paramValue = value;
  298. for (String keyword : notAllowedKeyWords) {
  299. if (paramValue.length() > keyword.length() + 4
  300. && (paramValue.contains(" "+keyword)||paramValue.contains(keyword+" ")||paramValue.contains(" "+keyword+" "))) {
  301. logger.error(this.getRequestURI()+ "参数中包含不允许sql的关键词(" + keyword
  302. + ")");
  303. return true;
  304. }
  305. }
  306. return false;
  307. }
  308. public final boolean checkParameter() {
  309. @SuppressWarnings({ "unchecked", "rawtypes" })
  310. Map<String, String[]> submitParams = new HashMap(parameterMap);
  311. Set<String> submitNames = submitParams.keySet();
  312. for (String submitName : submitNames) {
  313. Object submitValues = submitParams.get(submitName);
  314. if ((submitValues instanceof String)) {
  315. if (checkXSSAndSql((String) submitValues)) {
  316. return true;
  317. }
  318. } else if ((submitValues instanceof String[])) {
  319. for (String submitValue : (String[])submitValues){
  320. if (checkXSSAndSql(submitValue)) {
  321. return true;
  322. }
  323. }
  324. }
  325. }
  326. return false;
  327. }
  328. @Override
  329. public BufferedReader getReader() throws IOException {
  330. return new BufferedReader(new InputStreamReader(getInputStream()));
  331. }
  332. @Override
  333. public ServletInputStream getInputStream() throws IOException {
  334. final ByteArrayInputStream bais = new ByteArrayInputStream(body);
  335. return new ServletInputStream() {
  336. @Override
  337. public int read() throws IOException {
  338. return bais.read();
  339. }
  340. @Override
  341. public boolean isFinished() {
  342. // TODO Auto-generated method stub
  343. return false;
  344. }
  345. @Override
  346. public boolean isReady() {
  347. // TODO Auto-generated method stub
  348. return false;
  349. }
  350. @Override
  351. public void setReadListener(ReadListener arg0) {
  352. // TODO Auto-generated method stub
  353. }
  354. };
  355. }
  356. }

2. 创建防注入开关工具类

  1. import org.springframework.beans.factory.annotation.Value;
  2. import org.springframework.stereotype.Component;
  3. /**
  4. * @Description: 注入防护开关工具类
  5. */
  6. @Component
  7. public class CrosXssFilterConfigUtil {
  8. /**
  9. * 注入防护开关配置
  10. */
  11. public static Boolean openFilter;
  12. /**
  13. * 注入防护开关配置,默认为开启
  14. */
  15. public static Boolean getOpenFilterProtect() {
  16. return openFilter == null ? true : openFilter;
  17. }
  18. @Value("${api.filter}")
  19. public void setOpenFilter(Boolean openFilter) {
  20. CrosXssFilterConfigUtil.openFilter = openFilter;
  21. }
  22. }

yml配置:

  1. api:
  2. filter: true

3. 把请求过滤类XssAndSqlHttpServletRequestWrapper添加到Filter中,注入容器

  1. import com.example.util.CrosXssFilterConfigUtil;
  2. import com.example.wrapper.XssAndSqlHttpServletRequestWrapper;
  3. import org.apache.commons.lang3.StringUtils;
  4. import org.springframework.stereotype.Component;
  5. import javax.servlet.*;
  6. import javax.servlet.annotation.WebFilter;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.io.BufferedReader;
  10. import java.io.IOException;
  11. import java.io.PrintWriter;
  12. /**
  13. * SQL && XSS过滤器
  14. */
  15. @WebFilter
  16. @Component
  17. public class CrosXssFilterConfig implements Filter {
  18. @Override
  19. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  20. HttpServletRequest request = (HttpServletRequest) servletRequest;
  21. ServletResponse response = servletResponse;
  22. // 如果防注入关闭,则不执行后续校验操作
  23. if(!CrosXssFilterConfigUtil.getOpenFilterProtect()) {
  24. filterChain.doFilter(request,response);
  25. }else{
  26. XssAndSqlHttpServletRequestWrapper xssRequest = new XssAndSqlHttpServletRequestWrapper(request);
  27. String method = ((HttpServletRequest) request).getMethod();
  28. String param = "";
  29. if ("POST".equalsIgnoreCase(method)) {
  30. param = this.getBodyString(xssRequest.getReader());
  31. if(StringUtils.isNotBlank(param)){
  32. if(xssRequest.checkXSSAndSql(param)){
  33. servletResponse.setCharacterEncoding("UTF-8");
  34. servletResponse.setContentType("application/json;charset=UTF-8");
  35. PrintWriter out = servletResponse.getWriter();
  36. out.write("param is invalid");
  37. return;
  38. }
  39. }
  40. }
  41. if (xssRequest.checkParameter()) {
  42. servletResponse.setCharacterEncoding("UTF-8");
  43. servletResponse.setContentType("application/json;charset=UTF-8");
  44. PrintWriter out = servletResponse.getWriter();
  45. out.write("param is invalid");
  46. return;
  47. }
  48. filterChain.doFilter(xssRequest, servletResponse);
  49. }
  50. }
  51. // 获取request请求body中参数
  52. public String getBodyString(BufferedReader br) {
  53. String inputLine;
  54. String str = "";
  55. try {
  56. while ((inputLine = br.readLine()) != null) {
  57. str += inputLine;
  58. }
  59. br.close();
  60. } catch (IOException e) {
  61. e.printStackTrace();
  62. }
  63. return str;
  64. }
  65. @Override
  66. public void destroy() {
  67. }
  68. }

 完成!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/131099
推荐阅读
相关标签
  

闽ICP备14008679号