当前位置:   article > 正文

Java防XSS攻击实现(AOP+注解+反射)_自定义注解java 防止xss漏洞

自定义注解java 防止xss漏洞

本文使用JSP验证效果
项目结构
在这里插入图片描述
引人依赖

        <!-- springboot-aop -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!-- commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
        <!-- commons-text -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-text</artifactId>
            <version>1.6</version>
        </dependency>
        <!-- JSP依赖 -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

用户注册页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/info" method="post">
        用户名:<input type="text" name="username">
        密码:<input type="text" name="password">
        昵称:<input type="text" name="nickname">
        描述:<input type="text" name="description">
        <input type="submit" value="提交">
    </form>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

用户注册成功后显示用户信息页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
<body>
    <p>用户名:${user.username}</p>
    <p>密码:${user.password}</p>
    <p>昵称:${user.nickname}</p>
    <p>描述:${user.description}</p>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

用户实体对象

package com.dfyang.xss.entity;

/**
 * @Auther: 55411
 * @Date: 2019/6/21 16:20
 * @Description: 用户实体
 */
public class User {

    private String username;

    private String password;

    private String nickname;

    private String description;

	/* 省略get、set */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

编写测试Controller

package com.dfyang.xss.controller;

import com.dfyang.xss.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

/**
 * @Auther: 55411
 * @Date: 2019/6/21 14:19
 * @Description: 测试Controller
 */
@Controller
public class XSSController {

    @GetMapping("/register")
    public String insert() {
        return "register";
    }

    @PostMapping("/info")
    public String info(User user, Model model) {
        model.addAttribute("user", user);
        return "info";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

启动项目,访问 http://localhost:8080/register (请使用火狐浏览器进行测试)
在这里插入图片描述
这里再昵称和描述输入了 <script>alert(123);</script>
下面窗口弹出了两次。
在这里插入图片描述

如何防范XSS攻击

创建@PreventXSSMethod注解,用在需要AOP拦截的Controller方法上

package com.dfyang.xss.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Auther: 55411
 * @Date: 2019/6/21 11:48
 * @Description: 注解在方法上,表示该方法中的参数需要预防XSS
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventXSSMethod {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

创建@PreventXSSParameter注解,用在拦截方法的参数上,表示该参数需要防XSS攻击。

package com.dfyang.xss.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Auther: 55411
 * @Date: 2019/6/21 15:30
 * @Description: 注解在参数上,表示该参数需要预防XSS
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventXSSParameter {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

创建@PreventXSSField注解,如果参数是String类型,我们希望直接进行格式化,但很多情况下,我们的参数并不是一个String类型,比如上面的User对象。所以在需要防XSS且非String类型的对象,在需要防XSS的字段上加@PreventXSSField声明需要防XSS攻击。

package com.dfyang.xss.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Auther: 55411
 * @Date: 2019/6/21 16:20
 * @Description: 注解在字段上,表示该字段需要预防XSS
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventXSSField {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

最后编写我们的AOP代码。
(1)首先,我们将拦截所有加了@PreventXSSMethod的方法。
(2)然后,获取加了@PreventXSSParameter注解1的参数。
(3)如果参数类型为String,直接进行格式化。
(4)如果参数类型不是String,通过反射获取该参数的所有字段。
(5)对加了@PreventXSSField注解的字段进行格式化。
(6)将修改后的参数返回给原方法。

package com.dfyang.xss.aop;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

/**
 * @Auther: 55411
 * @Date: 2019/6/21 11:50
 * @Description: AOP防XSS攻击
 */
@Aspect
@Component
public class PreventXSSAspect {

    /**
     * 拦截controller路径下所有类的所有方法
     */
    @Pointcut("execution(* com.dfyang.xss.controller.*.*(..))")
    public void pointCut() {}

    @Around("pointCut() && @annotation(preventXSSMethod)")
    public Object around(ProceedingJoinPoint joinPoint, PreventXSSMethod preventXSSMethod) throws Throwable {
        Object[] args = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取所有参数上的注解(一个参数可能对应多个注解,因此获取到的是一个二维数组。)
        Annotation[][] paramsAnnotations = signature.getMethod().getParameterAnnotations();
        // 遍历一维数组,获取每个参数对应的注解数组
        for (int i = 0; i < paramsAnnotations.length; i++) {
            Annotation[] paramAnnotations = paramsAnnotations[i];
            // 遍历每个参数的注解数组
            for (Annotation annotation: paramAnnotations) {
                // 如果参数需要预防XSS攻击
                if (annotation instanceof PreventXSSParameter){
                    // 如果是String类型,将其进行格式化
                    // 否则获取该类型的所有字段,对String类型的字段进行格式化
                    if (args[i] instanceof String && StringUtils.isNotEmpty((String) args[i])) {
                        args[i] = format((String) args[i]);
                    } else {
                        Class clazz = args[i].getClass();
                        // 获取类的所有字段
                        Field[] fields = clazz.getDeclaredFields();
                        for (Field field: fields) {
                            // 如果字段上有@PreventXSSField注解
                            if (field.getDeclaredAnnotation(PreventXSSField.class) != null) {
                                // 如果是字段不可访问,设置临时可访问
                                if (!field.isAccessible())
                                    field.setAccessible(true);
                                // 如果字段是字符串类型则进行格式化
                                Object fieldValue = field.get(args[i]);
                                if (fieldValue instanceof String && StringUtils.isNotEmpty((String) fieldValue))
                                    field.set(args[i], format((String) fieldValue));
                            }
                        }
                    }
                }
            }
        }
        // 将参数覆盖到到原方法
        Object proceed = joinPoint.proceed(args);
        return proceed;
    }

    /**
     * 对需要防范的字符串进行格式化
     */
    public String format(String xssStr) {
        return StringEscapeUtils.escapeHtml4(xssStr);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

这里使用的StringEscapeUtils,如果需要自定义防XSS,只需从写上面的format方法即可。
——如果没看懂的朋友建议打断点。

最后在启动类上加上注解

package com.dfyang.xss;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class XssApplication {

    public static void main(String[] args) {
        SpringApplication.run(XssApplication.class, args);
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

接下来修改代码,防XSS攻击。

对于User对象,当我们注册时,可能并不希望用户输入乱七八糟的字符,所以对于用户名和密码,当用户输入非法字符时要求重新输入即可,不需要防XSS。这里仅对昵称和描述防XSS。

public class User {

    private String username;

    private String password;

    @PreventXSSField
    private String nickname;

    @PreventXSSField
    private String description;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在info方法加上@PreventXSSMethod表示该方法需要防XSS,在user参数加上@PreventXSSParameter表示该参数需要防XSS。

    @PreventXSSMethod
    @PostMapping("/info")
    public String info(@PreventXSSParameter User user, Model model) {
        model.addAttribute("user", user);
        return "info";
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

启动项目,验证代码——
同样输入上面代码。
在这里插入图片描述
如果有不正确或需要改进的地方,欢迎指正!

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

闽ICP备14008679号