防XSS注入攻击

防XSS注入攻击,第1张

防XSS注入攻击 一.首先大概理解下什么是XSS注入攻击

XSS注入攻击本质上就是通过你服务本身的接口把一些HTML,CSS,JS,SQL语句等内容存储进你的服务里面,一般是数据库里面,这时候就可以通过这些存储进去的内容拿取到一些你的数据库隐藏内容或者破坏你的页面排版,比如乱d窗。

二.解决的方法

首先声明,解决方案不止这一种,这只是最简单的一种

1.使用拦截器拦截所有请求,一定要在最顶层
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Controller;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;


@Order(-100)    //拦截器级别,越小越在前面
@Controller
@ServletComponentScan
@WebFilter(urlPatterns = "
    @Override
    public void init(FilterConfig filterConfig) {
        System.out.println("程序启动");
    }

    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 允许哪些Origin发起跨域请求
        String orgin = request.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Origin", orgin);
        // 允许请求的请求类型
        response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PUT");
        //多少秒内,不需要再发送预检验请求,可以缓存该结果
        response.setHeader("Access-Control-Max-Age", "3600");
        //表明它允许跨域请求头中有哪些参数
        response.setHeader("Access-Control-Allow-Headers", "x-auth-token,Origin,Access-Token,X-Requested-With,Content-Type,Accept,token");
        //是否允许浏览器携带用户身份信息(cookie)
        response.setHeader("Access-Control-Allow-Credentials", "true");
        //cors试探性请求,拦截到OPTIONS类型请求,直接返回结果
        String urlType = request.getMethod();
        if (urlType.equals("OPTIONS")) {
            response.setStatus(200);
            return;
        }

        //不进行XSS攻击处理的接口(一般都是要用到富文本的接口),只是不用过滤HTML字符
        List urlList=new ArrayList<>();
        urlList.add("/assess/addAssessUser");
        urlList.add("/article/addJournalism");
        urlList.add("/article/updateArticle");
        urlList.add("/course/addCourse");
        urlList.add("/course/updateCourse");
        urlList.add("/course_chapters/updateCourseChapters");
        urlList.add("/course_chapters/addCourseChapters");
        urlList.add("/competitionTitbits/updateCompetitionTitbitsOne");
        urlList.add("/competitionTitbits/addCompetitionTitbitsOne");
        urlList.add("/user/addUser");
        urlList.add("/user/updateUser");
        urlList.add("/text/addText");
        urlList.add("/text/updateText");
        urlList.add("/practice_finance/addOrUpdatePracticeFinanceSystem");
        urlList.add("/practice_structure/addOrUpdatePracticeStructureSynopsis");
        //判断当前接口是要进行XSS攻击处理的还是不要的(在不过滤列表里面有就是不过滤,没有则要过滤),只是不用过滤HTML字符
        if(urlList.stream().filter(data -> data.equals(request.getRequestURI())).collect(Collectors.toList()).isEmpty()){
            XssHttpServletRequestWrapper.HTML_TYPE = true;
            XssHttpServletRequestWrapper.SQL_TYPE = true;
        }else {
            XssHttpServletRequestWrapper.HTML_TYPE = false;
            XssHttpServletRequestWrapper.SQL_TYPE = true;
        }
        //处理XSS攻击(其实就是SQL和HTML/CSS/JS注入攻击),方法是重写HttpServletRequest这些请求实体类的参数过滤规则,然后替换掉原生默认的
        XssHttpServletRequestWrapper xssHttpServletRequestWrapper=new XssHttpServletRequestWrapper(request);
        chain.doFilter(xssHttpServletRequestWrapper, response);
    }

    
    @Override
    public void destroy() {
        System.out.println("程序关闭");
    }
}
2.自拟定XSS过滤工具

其实就是拿取所有的request对象里面的参数,进行过滤,去除一些关键字,转义一些特殊字符

import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    //要过滤数据库SQL的关键字
    private final static String key = "and|exec|insert|select|delete|update|count|chr|mid|master|truncate|char|declare|or";
    private static Set notAllowedKeyWords = new HashSet(0);
    //SQL过滤到要加的标记文字
    private static String replacedString = "INVALID";
    //是否要过滤HTML符号
    public static Boolean HTML_TYPE = true;
    //是否要过滤SQL关键字
    public static Boolean SQL_TYPE = true;

    static {
        String keyStr[] = key.split("\|");
        for (String str : keyStr) {
            notAllowedKeyWords.add(str);
        }
    }

    private String currentUrl;

    public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
        super(servletRequest);
        currentUrl = servletRequest.getRequestURI();
    }


    
    @Override
    public String getParameter(String parameter) {
        String value = super.getParameter(parameter);
        if (value == null) {
            return null;
        }
        return cleanXSS(value);
    }

    @Override
    public String[] getParameterValues(String parameter) {
        String[] values = super.getParameterValues(parameter);
        if (values == null) {
            return null;
        }
        int count = values.length;
        String[] encodedValues = new String[count];
        for (int i = 0; i < count; i++) {
            encodedValues[i] = cleanXSS(values[i]);
        }
        return encodedValues;
    }

    @Override
    public Map getParameterMap() {
        Map values = super.getParameterMap();
        if (values == null) {
            return null;
        }
        Map result = new HashMap<>();
        for (String key : values.keySet()) {
            String encodedKey = cleanXSS(key);
            int count = values.get(key).length;
            String[] encodedValues = new String[count];
            for (int i = 0; i < count; i++) {
                encodedValues[i] = cleanXSS(values.get(key)[i]);
            }
            result.put(encodedKey, encodedValues);
        }
        return result;
    }

    
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (value == null) {
            return null;
        }
        return cleanXSS(value);
    }

    
    private String cleanXSS(String valueP) {
        String value = valueP;
        //判断是否过滤HTML字符,是则过滤
        if(HTML_TYPE){
            value = value.replaceAll("<", "<").replaceAll(">", ">");
            value = value.replaceAll("<", "<").replaceAll(">", ">");
            value = value.replaceAll("\(", "(").replaceAll("\)", ")");
            value = value.replaceAll("'", "'");
            value = value.replaceAll("eval\((.*)\)", "");
            value = value.replaceAll("[\"\'][\s]*javascript:(.*)[\"\']", """");
            value = value.replaceAll("alert", "");
        }
        //判断是否过滤SQL关键字,是则过滤
        if(SQL_TYPE){
            value = cleanSqlKeyWords(value);
        }
        return value;
    }

    
    private String cleanSqlKeyWords(String value) {
        String paramValue = value;
        if (value.indexOf("q=0.01") == -1) {
            for (String keyword : notAllowedKeyWords) {
                if (paramValue.length() > keyword.length() + 4 && (paramValue.contains(" " + keyword) || paramValue.contains(keyword + " ") || paramValue.contains(" " + keyword + " "))) {
                    paramValue = StringUtils.replace(paramValue, keyword, replacedString);
                }
            }
        }
        return paramValue;
    }

}

三.一些过滤以后会出现的问题

1.比如我碰见的layui富文本就会出现转义以后的字符回显在富文本不会回显样式的问题,暂时没有好的解决方案

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5685064.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存