• XSS攻击和跨站脚本安全漏洞防护


    1、存储型XSS

          指应用程序通过Web请求获取不可信赖的数据,并且在未检验数据是否存在XSS代码的情况下,将其存入数据库。当程序下一次从数据库中获取该数据时,致使页面再次执行XSS代码。存储型XSS可以持续攻击用户,在用户提交了包含XSS代码的数据存储到数据库后,每当用户在浏览网页查询对应数据库中的数据时,那些包含XSS代码的数据就会在服务器解析并加载,当浏览器读到XSS代码后,会当做正常的HTML和JS解析并执行,于是发生存储型XSS攻击。

    **例如**:下面JSP代码片段的功能是根据一个已知用户雇员ID(id)从数据库中查询出该用户的地址,并显示在JSP页面上 。

    1. ```java
    2. <%
    3. ...
    4. Statement stmt = conn.createStatement();
    5. ResultSet rs = stmt.executeQuery("select * from users where id =" + id);
    6. String address = null;
    7. if (rs != null) {
    8. rs.next();
    9. address = rs.getString("address");
    10. }
    11. %>
    12. 家庭地址: <%= address %>
    13. ```

    如果address的值是由用户提供的,且存入数据库时没有进行合理的校验,那么攻击者就可以利用上面的代码进行存储型XSS攻击。

    2、反射型XSS

          指应用程序通过Web请求获取不可信赖的数据,并在未检验数据是否存在恶意代码的情况下,将其发送给用户。反射型XSS一般可以由攻击者构造带有恶意代码参数的URL来实现,在构造的URL地址被打开后,其中包含的恶意代码参数被浏览器解析和执行。这种攻击的特点是非持久化,必须用户点击包含恶意代码参数的链接时才会触发。

    **例如**:下面JSP代码片段的功能是从HTTP请求中读取输入的用户名(username)并显示到页面。

    1. ```java
    2. <%
    3. String name= request.getParameter("username"); %>
    4. ...
    5. 姓名: <%= name%>
    6. ...
    7. ```

    如果name里有包含恶意代码,那么Web浏览器就会像显示HTTP响应那样执行该代码,应用程序将受到反射型XSS攻击。

    3、防范建议

    为了避免存储型XSS攻击,建议采用以下方式进行防御:

    1.对从数据库或其它后端数据存储获取不可信赖的数据进行合理验证(如年龄只能是数字),对特殊字符(如`<、>、'、"`以及`", Pattern.CASE_INSENSITIVE);

  • public static Pattern scriptPattern2 = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  • public static Pattern scriptPattern3 = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  • public static Pattern scriptPattern4 = Pattern.compile("", Pattern.CASE_INSENSITIVE);
  • public static Pattern scriptPattern5 = Pattern.compile("", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  • public static Pattern scriptPattern6 = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  • public static Pattern scriptPattern7 = Pattern.compile("e­xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  • public static Pattern scriptPattern8 = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
  • public static Pattern scriptPattern9 = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
  • public static Pattern scriptPattern10 = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
  • public static Pattern scriptPattern11 = Pattern.compile(".*<.*", Pattern.CASE_INSENSITIVE );
  • public static String striptXSS(String value) {
  • if (value != null) {
  • value = value.replaceAll("", "");
  • value = scriptPattern1.matcher(value).replaceAll("");
  • value = scriptPattern2.matcher(value).replaceAll("");
  • value = scriptPattern3.matcher(value).replaceAll("");
  • value = scriptPattern4.matcher(value).replaceAll("");
  • value = scriptPattern5.matcher(value).replaceAll("");
  • value = scriptPattern6.matcher(value).replaceAll("");
  • value = scriptPattern7.matcher(value).replaceAll("");
  • value = scriptPattern8.matcher(value).replaceAll("");
  • value = scriptPattern9.matcher(value).replaceAll("");
  • value = scriptPattern10.matcher(value).replaceAll("");
  • value = scriptPattern11.matcher(value).replaceAll("");
  • }
  • return value;
  • }
  • }
  • 2、请求过滤业务实现类

    1. package com.hlframe.modules.frame.interceptor;
    2. import java.util.HashMap;
    3. import java.util.Iterator;
    4. import java.util.Map;
    5. import java.util.Set;
    6. import javax.servlet.http.HttpServletRequest;
    7. import javax.servlet.http.HttpServletRequestWrapper;
    8. import com.hlframe.modules.frame.utils.XSSUtils;
    9. import org.springframework.util.StringUtils;
    10. import org.springframework.web.multipart.MultipartHttpServletRequest;
    11. import org.springframework.web.multipart.commons.CommonsMultipartResolver;
    12. /**
    13. * 请求过滤业务实现类
    14. */
    15. public class XssRequestWrappers extends HttpServletRequestWrapper{
    16. private CommonsMultipartResolver multiparResolver = new CommonsMultipartResolver();
    17. public XssRequestWrappers(HttpServletRequest request) {
    18. super(request);
    19. String type = request.getHeader("Content-Type");
    20. if (!StringUtils.isEmpty(type) && type.contains("multipart/form-data")) {
    21. MultipartHttpServletRequest multipartHttpServletRequest = multiparResolver.resolveMultipart(request);
    22. Map stringMap = multipartHttpServletRequest.getParameterMap();
    23. if (!stringMap.isEmpty()) {
    24. for (String key : stringMap.keySet()) {
    25. String value = multipartHttpServletRequest.getParameter(key);
    26. XSSUtils.striptXSS(key);
    27. XSSUtils.striptXSS(value);
    28. }
    29. }
    30. super.setRequest(multipartHttpServletRequest);
    31. }
    32. }
    33. @Override
    34. public String[] getParameterValues(String parameter) {
    35. String[] values = super.getParameterValues(parameter);
    36. if (values == null) {
    37. return null;
    38. }
    39. int count = values.length;
    40. String[] encodedValues = new String[count];
    41. for (int i = 0; i < count; i++) {
    42. encodedValues[i] = XSSUtils.striptXSS(values[i]);
    43. }
    44. return encodedValues;
    45. }
    46. @Override
    47. public String getParameter(String parameter) {
    48. String value = super.getParameter(parameter);
    49. return XSSUtils.striptXSS(value);
    50. }
    51. @Override
    52. public String getHeader(String name) {
    53. String value = super.getHeader(name);
    54. return XSSUtils.striptXSS(value);
    55. }
    56. @Override
    57. public Map getParameterMap() {
    58. Map map1 = super.getParameterMap();
    59. Map escapseMap = new HashMap();
    60. Set keys = map1.keySet();
    61. for (String key : keys) {
    62. String[] valArr = map1.get(key);
    63. if (valArr != null && valArr.length > 0) {
    64. String[] escapseValArr = new String[valArr.length];
    65. for (int i = 0; i < valArr.length; i++) {
    66. String escapseVal = XSSUtils.striptXSS(valArr[i]);
    67. escapseValArr[i] = escapseVal;
    68. }
    69. escapseMap.put(key, escapseValArr);
    70. }
    71. }
    72. return escapseMap;
    73. }
    74. }

     3、XSSFilter拦截类

    1. package com.hlframe.modules.frame.interceptor;
    2. import com.hlframe.modules.frame.utils.XSSUtils;
    3. import org.springframework.stereotype.Component;
    4. import java.io.IOException;
    5. import javax.servlet.*;
    6. import javax.servlet.annotation.WebFilter;
    7. import javax.servlet.http.HttpServletRequest;
    8. import javax.servlet.http.HttpServletResponse;
    9. /**
    10. * 存储型XSS、跨站脚本过滤器
    11. * @author zyw
    12. * @since 2022-09-01 20:09:31
    13. */
    14. @Component
    15. @WebFilter(filterName = "XSSFilter",
    16. /**
    17. * 通配符(*)表示对所有的web资源进行拦截
    18. */
    19. urlPatterns = "/*"
    20. )
    21. public class XSSFilter implements Filter {
    22. @Override
    23. public void init(FilterConfig arg0) throws ServletException {
    24. System.out.println("初始化过滤器!");
    25. }
    26. @Override
    27. public void destroy() {
    28. System.out.println("销毁过滤器!");
    29. }
    30. @Override
    31. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    32. throws IOException, ServletException {
    33. //过滤请求
    34. // chain.doFilter(new XssRequestWrappers((HttpServletRequest) request), response);
    35. //过滤返回
    36. ResponseWrapper wrapperResponse = new ResponseWrapper((HttpServletResponse)response);//转换成代理类
    37. chain.doFilter(new XssRequestWrappers((HttpServletRequest) request), wrapperResponse);
    38. byte[] content = wrapperResponse.getContent();//获取返回值
    39. //判断是否有值
    40. if (content.length > 0)
    41. {
    42. String str = new String(content, "UTF-8");
    43. System.out.println("返回值:" + str);
    44. String ciphertext = null;
    45. try
    46. {
    47. System.out.println("str = " + str);
    48. //......根据需要处理返回值
    49. ciphertext = XSSUtils.striptXSS(str);
    50. System.out.println("ciphertext = " + ciphertext);
    51. }
    52. catch (Exception e)
    53. {
    54. e.printStackTrace();
    55. }
    56. //把返回值输出到客户端
    57. ServletOutputStream out = response.getOutputStream();
    58. out.write(ciphertext.getBytes());
    59. out.flush();
    60. }
    61. }
    62. }

    4、返回值输出代理类

    1. /**
    2. * 返回值输出代理类
    3. *
    4. * @Title: ResponseWrapper
    5. * @Description:
    6. * @author zyw
    7. * @date 9:52:11
    8. */
    9. public class ResponseWrapper extends HttpServletResponseWrapper {
    10. private ByteArrayOutputStream buffer;
    11. private ServletOutputStream out;
    12. public ResponseWrapper(HttpServletResponse httpServletResponse)
    13. {
    14. super(httpServletResponse);
    15. buffer = new ByteArrayOutputStream();
    16. out = new WrapperOutputStream(buffer);
    17. }
    18. @Override
    19. public ServletOutputStream getOutputStream()
    20. throws IOException
    21. {
    22. return out;
    23. }
    24. @Override
    25. public void flushBuffer()
    26. throws IOException
    27. {
    28. if (out != null)
    29. {
    30. out.flush();
    31. }
    32. }
    33. public byte[] getContent()
    34. throws IOException
    35. {
    36. flushBuffer();
    37. return buffer.toByteArray();
    38. }
    39. class WrapperOutputStream extends ServletOutputStream
    40. {
    41. private ByteArrayOutputStream bos;
    42. public WrapperOutputStream(ByteArrayOutputStream bos)
    43. {
    44. this.bos = bos;
    45. }
    46. @Override
    47. public void write(int b)
    48. throws IOException
    49. {
    50. bos.write(b);
    51. }
    52. @Override
    53. public boolean isReady()
    54. {
    55. // TODO Auto-generated method stub
    56. return false;
    57. }
    58. @Override
    59. public void setWriteListener(WriteListener arg0)
    60. {
    61. // TODO Auto-generated method stub
    62. }
    63. }

    注意:SpingBoot3.0.0之前旧版本不支持通过正则表达式对响应进行过滤

    此时可以通过String类中的各种方法直接对响应或请求中的内容进行修改

    1. package com.hlframe.modules.frame.utils;
    2. import java.util.regex.Pattern;
    3. /**
    4. * 跨站脚本和存储型XSS攻击防御工具类
    5. * @author zyw
    6. * @date 16:52:11
    7. */
    8. public class XSSUtils {
    9. public static String striptXSS(String value) {
    10. if (value != null) {
    11. value = value.replaceAll("", "");
    12. value = value.replace('<',' ');
    13. value = value.replace('>',' ');
    14. }
    15. return value;
    16. }
    17. }

  • 相关阅读:
    使用广播信道的数据链路层
    python提效小工具-统计xmind用例数量
    glibc: strlcpy
    29.STM32红外遥控器
    应用层协议——DNS、DHCP、HTTP、FTP
    如何制作网页 ico
    ESP8266-Arduino编程实例-ADXL345三轴加速计驱动
    基于开源流批一体数据同步引擎ChunJun数据还原—DDL解析模块的实战分享
    Day 66 二叉树 排序
    这几个小妙招让你学会如何压缩图片大小
  • 原文地址:https://blog.csdn.net/Zyw907155124/article/details/126707699