若依源码学习8:防XSS攻击以及全局异常处理

首图

1、防 XSS 攻击

1.1、什么是XSS攻击?

**XSS 即(Cross Site Scripting)中文名称为:跨站脚本攻击。**XSS的重点不在于跨站点,而在于脚本的执行。那么XSS的原理是:

恶意攻击者在web页面中会插入一些恶意的script代码。当用户浏览该页面的时候,那么嵌入到web页面中script代码会执行,因此会达到恶意攻击用户的目的。

那么XSS攻击最主要有如下分类:反射型、存储型、及 DOM-based型。 反射性和DOM-baseed型可以归类为非持久性XSS攻击。存储型可以归类为持久性XSS攻击。

1.2、SQL 注入

SQL注入是通过客户端的输入把SQL命令注入到一个应用的数据库中,从而执行恶意的SQL语句。

什么意思呢?我们来打个比方:我们有一个登录框,需要输入用户名和密码对吧,然后我们的密码输入 'or ‘123’ = '123 这样的。我们在查询用户名和密码是否正确的时候,本来执行的sql语句是:select * from user where username = ‘’ and password = ‘’. 这样的sql语句,现在我们输入密码是如上这样的,然后我们会通过参数进行拼接,拼接后的sql语句就是:

select * from user where username = ‘’ and password = ’ ’ or ‘123’ = '123 '; 这样的了,那么会有一个or语句,只要这两个有一个是正确的话,就条件成立,因此 123 = 123 是成立的。因此验证就会被跳过。这只是一个简单的列子,比如还有密码比如是这样的:’; drop table user;, 这样的话,那么sql命令就变成了:

select * from user where username = ‘’ and password = ‘’; drop table user;’ , 那么这个时候我们会把user表直接删除了。

sql被攻击的原因是:sql语句伪造参数,然后对参数进行拼接后形成xss攻击的sql语句。最后会导致数据库被攻击了。

防范的方法:

1、我们可以使用预编译语句(PreparedStatement,这样的话即使我们使用sql语句伪造成参数,到了服务端的时候,这个伪造sql语句的参数也只是简单的字符,并不能起到攻击的作用。

2、数据库中密码不应明文存储的,可以对密码使用md5进行加密,为了加大破解成本,所以可以采用加盐的方式。

1.3、知识点补充

Filter介绍

过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。(理解:就是一堆字母中取一个B)

在java web中将你传入的request、response提前过滤掉一些信息,或者提前设置一些参数。

1、Filter的用处

1、在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。

2、根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。

3、在HttpServletResponse到达客户端之前,拦截HttpServletResponse。

4、根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

2、方法介绍
@Override
public void init(FilterConfig arg0) throws ServletException {

}
@Override 
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    System.out.println("before...");
    chain.doFilter(request, response);
    System.out.println("after...");
}
@Override
public void destroy() {

}

1、void init(FilterConfig config):用于完成Filter的初始化。

2、void doFilter(ServletRequest request,ServletResponse response,FilterChain chain):实现过滤功能,该方法就是对每个请求及响应增加的额外处理。该方法可以实现对用户请求进行预处理(ServletRequest request),也可实现对服务器响应进行后处理(ServletResponse response)。

它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。

3、void destory():用于Filter销毁前,完成某些资源的回收。

3、使用步骤

1、创建自定义Filter处理类

2、通过FilterRegistrationBean实例注册,可以设置优先级排序

bean.setOrder(6); //优先级,越低越优先

Interceptor介绍

拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。(理解:就是一堆字母中,干预它,通过验证的少点,顺便干点别的东西)

拦截器是aop的一种实现方案,是aop思想的体现。在我们调用方法之前,调用拦截器的一个方法或者在调用方法之后,调用拦截器的一个方法。

1、方法介绍
public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

1、preHandle 方法,在请求处理之前进行调用。SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。

该方法的返回值是布尔值Boolean类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller方法。

2、postHandle 方法,在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。

3、afterCompletion 方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行,主要作用是用于进行资源清理工作的。

2、执行顺序

1、请求到达 DispatcherServlet

2、DispatcherServlet 发送至 Interceptor ,执行 preHandle

3、请求达到 Controller

4、请求结束后,postHandle 执行

3、使用步骤

1、SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式:

第一种方式是要定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter ;

第二种方式是实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。

2、创建一个配置类并实现WebMvcConfigurer 接口,重写addInterceptors方法

拦截器(Interceptor)和过滤器(Filter)的区别

1、大体执行顺序

img

2、具体方法执行顺序

img

3、区别
FilterInterceptorSummary
Filter 接口定义在 javax.servlet 包中接口 HandlerInterceptor 定义在org.springframework.web.servlet 包中
Filter是在Servlet规范中定义的,是Servlet容器支持的拦截器是在Spring容器内的,是Spring框架支持的。规范不同
Filter不由Spring进行管理,对于各种Service只能通过IOC容器手动获取拦截器是Spring的组件,归Spring管理,因此能使用Spring里的任何资源,例如 Service对象、数据源、事务管理等,能通过IOC自动注入Spring使用Interceptor更容易
Filter 是被 Server(like Tomcat) 调用Interceptor 是被 Spring 调用因此Filter总是优于Interceptor执行
Filter在只在 Servlet 前后起作用。Filters 通常将 请求和响应(request/response) 当做黑盒子,Filter 通常不考虑servlet 的实现。拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。允许用户介入(hook into)请求的生命周期,在请求过程中获取信息,Interceptor 通常和请求更加耦合。在Spring构架的程序中,要优先使用拦截器。几乎所有 Filter 能够做的事情, interceptor 都能够轻松的实现

1.4、XSS 攻击解决方案

1、配置文件

# 防止XSS攻击
xss: 
  # 过滤开关
  enabled: true
  # 排除链接(多个用逗号分隔)
  excludes: /system/notice/*
  # 匹配链接
  urlPatterns: /system/*,/monitor/*,/tool/*

2、自定义XSS攻击的过滤器

对于匹配的请求路径进行过滤,装饰者模式使用自定义的 Request 替换 原ServletRequest,继承HttpServletRequestWrapper重写 getParameterValues方法,对前端传递过来的参数进行检验和过滤。

因此,想要改变在httpServletRequest中的参数,可以通过httpServletRequest的装饰类HttpServletRequestWrapper来实现,只需要在装饰类中按照需要重写其getParameter(getParameterValues)方法即可。

image-20210412140622918

/**
 * XSS过滤处理
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
{
    /**
     * @param request
     */
    public XssHttpServletRequestWrapper(HttpServletRequest request)
    {
        super(request);
    }

    @Override
    public String[] getParameterValues(String name)
    {
        String[] values = super.getParameterValues(name);
        if (values != null)
        {
            int length = values.length;
            String[] escapseValues = new String[length];
            for (int i = 0; i < length; i++)
            {
                // 防xss攻击和过滤前后空格
                escapseValues[i] = EscapeUtil.clean(values[i]).trim();
            }
            return escapseValues;
        }
        return super.getParameterValues(name);
    }
}

其中对参数的过滤方法是clean,具体实现就是剔除文本中的HTML标签

/**
     * 清除所有HTML标签,但是不删除标签内的内容
     * 
     * @param content 文本
     * @return 清除标签后的文本
     */
public static String clean(String content)
{
    return new HTMLFilter().filter(content);
}

那么过滤器要做的工作就是在满足条件的情况下,将自定义的xssRequest替换原本的request,从而达到每次获取参数的时候,使用xssRequest重载的方法对每一个参数都进行检测和过滤!

/**
 * 防止XSS攻击的过滤器
 */
public class XssFilter implements Filter
{
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException
    {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        if (handleExcludeURL(req, resp))
        {
            chain.doFilter(request, response);
            return;
        }
        // 在此替换 xssRequest
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
        chain.doFilter(xssRequest, response);
    }

}

2、全局异常处理

Spring boot/mvc项目中通过@RestControllerAdvice或者@ControllerAdvice配合@ExceptionHandler实现全局异常统一处理。

@RestControllerAdvice相当于Controller的切面,对异常统一处理,定制,这样更好返回给前端。

/**
 * 全局异常处理器
 * 
 * @author ruoyi
 */
@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    // 通过 AjaxResult 返回统一结果,以及日志的记录
    1、请求方式不支持异常
    2、拦截未知的运行时异常
    3、自定义业务异常
    4、自定义验证异常,也就是数据传入时的检查
    5、运行时异常和系统异常
}

1、请求方式不支持异常

/**
     * 请求方式不支持
     */
@ExceptionHandler({ HttpRequestMethodNotSupportedException.class })
public AjaxResult handleException(HttpRequestMethodNotSupportedException e)
{
    log.error(e.getMessage(), e);
    return AjaxResult.error("不支持' " + e.getMethod() + "'请求");
}

2、拦截未知的运行时异常

/**
     * 拦截未知的运行时异常
     */
@ExceptionHandler(RuntimeException.class)
public AjaxResult notFount(RuntimeException e)
{
    log.error("运行时异常:", e);
    return AjaxResult.error("运行时异常:" + e.getMessage());
}

3、自定义业务异常

/**
     * 业务异常
     */
@ExceptionHandler(BusinessException.class)
public Object businessException(HttpServletRequest request, BusinessException e)
{
    log.error(e.getMessage(), e);
    if (ServletUtils.isAjaxRequest(request))
    {
        return AjaxResult.error(e.getMessage());
    }
    else
    {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("errorMessage", e.getMessage());
        modelAndView.setViewName("error/business");
        return modelAndView;
    }
}

4、自定义验证异常

/**
     * 自定义验证异常
     */
@ExceptionHandler(BindException.class)
public AjaxResult validatedBindException(BindException e)
{
    log.error(e.getMessage(), e);
    String message = e.getAllErrors().get(0).getDefaultMessage();
    return AjaxResult.error(message);
}

5、运行时异常和系统异常

/**
     * 拦截未知的运行时异常
     */
@ExceptionHandler(RuntimeException.class)
public AjaxResult notFount(RuntimeException e)
{
    log.error("运行时异常:", e);
    return AjaxResult.error("运行时异常:" + e.getMessage());
}

/**
     * 系统异常
     */
@ExceptionHandler(Exception.class)
public AjaxResult handleException(Exception e)
{
    log.error(e.getMessage(), e);
    return AjaxResult.error("服务器错误,请联系管理员");
}
  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值