【Java代码审计】XSS篇

发布时间:2023年12月20日

1.Java中XSS常见触发位置

XSS漏洞产生后必然会有相关的输入/输出,因此我们只需快速找到这些输入/输出点,即可快速地进行跟踪发现漏洞。输入在Java中通常使用“request.getParameter(param)”或“${param}”获取用户的输入信息。输出主要表现为前端的渲染,我们可以通过定位前端中一些常见的标识来找到它们,然后根据后端逻辑来判断漏洞是否存在

1、JSP表达式

<%=变量%>”是“<%out.println 变量;%>”的简写方式,“<%=%>”用于将已声明的变量或表达式输出到外网页中

通过“request.getParameter”获取msg传入的值,然后通过“<%=msg%>”将其输出到网页中:

<% String msg = request.getParameter("msg");%>
<%= msg %>

2、EL

EL是为了使JSP写起来更加简单。EL的灵感来自于ECMAScript和XPath表达式语言,它提供了在JSP中简化表达式的方法,使得JSP的代码更加简化。例如:“<%=request.getParameter("username")%>”等价于“${param.username}”。JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能

在这里插入图片描述

<c:out>标签用来显示一个表达式的结果,与<%=%>作用相似,它们的区别是,<c:out>标签可以直接通过“.”操作符来访问属性,如下:

<c:out value="${requestScope.message}" />
<c:out value="${5 + 3}" />

<c:if>标签用来判断表达式的值,如果表达式的值为true,则执行其主体内容:

<c:set var="loggedIn" value="true" />

<c:if test="${loggedIn eq 'true'}">
    <p>Welcome, User!</p>
</c:if>
<c:if test="${loggedIn eq 'false'}">
    <p>Please log in to continue.</p>
</c:if>

<c:forEach>标签的作用是迭代输出标签内部的内容。它既可以进行固定次数的迭代输出,也可以依据集合中对象的个数来决定迭代的次数:

<c:forEach var="item" items="${myList}">
    <p>${item}</p>
</c:forEach>

3、ModelAndView类的使用

ModelAndView类用来存储处理完成后的结果数据,以及显示该数据的视图,其前端JSP页面可以使用“${参数}”的方法来获取值:

@GetMapping("/hello")
public ModelAndView sayHello() {
    String message = "Hello, Spring MVC!";
    
    // 创建一个ModelAndView对象,并设置视图名称和模型数据
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("hello"); // 设置视图名称为"hello",这里假设存在名为"hello.jsp"的视图文件
    
    // 添加模型数据
    modelAndView.addObject("message", message);

    return modelAndView;
}

4、ModelMap类的使用

Spring也提供了ModelMap类,这是java.util.Map实现的,可以根据模型属性的具体类型自动生成模型属性的名称

@GetMapping("/hello")
public String hello(ModelMap model) {
    model.addAttribute("message", "Hello, World!");
    return "hello";
}

5、Model类的使用

Model类是一个接口类,通过attribue()添加数据,存储的数据域范围是requestScope

@GetMapping("/hello")
public String hello(Model model) {
    model.addAttribute("message", "Hello, World!");
    return "hello";
}

通过这些常见语法的总结我们不难归纳出一些常见的关键字,通过这些关键字可以快速地定位至具有前后端交互功能的代码片段:

在这里插入图片描述


2.反射型XSS

在审计中我们只需通过搜索特定的关键字找到数据的交互点,然后判断这些数据是否可控以及输出位置。当数据可控并且直接在浏览器页面输出时,可进一步构造XSS攻击代码

在这里插入图片描述

例如:如下是一段简单的导致反射型XSS代码,没对输出做处理。当攻击者输入恶意js语句时可触发:

@GetMapping("/reflect")
public static String input(String content) {
    return content;
}

当我们构造如下的输入参数时:

http://127.0.0.1:8888/XSS/reflect?content=test%3Cscript%3E%0A%20%20%20%20window.onload=function()%20%7B%0A%20%20%20%20%20%20%20%20document.bgColor%20=%20%22black%22;%0A%20%20%20%20%20%20%20%20document.body.innerHTML=%22%3Cfont%20color=white%20size=40%3E%E4%BD%A0%E8%A2%ABXSS%E9%BB%91%E4%BA%86%EF%BC%81%3C/font%3E%22%0A%20%20%20%20%7D%0A%3C/script%3E

XSS攻击成功被触发:

在这里插入图片描述


3.存储型XSS

存储型XSS与反射型XSS核心原理一致,都是将JavaScript通过程序输出到HTML页面中并交由浏览器引擎解析。相比于反射型XSS,存储型XSS危害更大。反射型XSS需构造恶意URL来诱导受害者点击,而存储型XSS由于有效载荷直接被写入了服务器中,且不需要将有效载荷输入到URL中,往往可以伪装成正常页面,迷惑性更强。因此存储型XSS漏洞对于普通用户而言很难及时被发现

网站程序中常见的存储型XSS攻击点一般有:文章编辑、用户留言、个性签名

在这里插入图片描述


4.XSS漏洞修复

1、修复XSS攻击,一个有效的方案是将特殊字符做转义,对所有字符采用HTML实体编码,但是请记住这种方法有局限性:

例如,如下是一个对输入输出转义的方法:

private static String XssFilter(String content) {
    content = StringUtils.replace(content, "&", "&amp;");
    content = StringUtils.replace(content, "<", "&lt;");
    content = StringUtils.replace(content, ">", "&gt;");
    content = StringUtils.replace(content, "\", "&quot;");
    content = StringUtils.replace(content, "'", "&#x27;");
    content = StringUtils.replace(content, "/", "&#x2F;");
    return content;
}

此时,尝试触发XSS:http://127.0.0.1:8888/XSS/filter?content=test%3Cscript%3Ealert(1)%3C/script%3E

没有弹窗,而是将输入文本以字符串的方式展示在页面:

在这里插入图片描述

2、采用Spring自带的方法会对特殊字符全转义

上述转义的方案,有一个更简单的实现方法,使用htmlEscape方法:

@GetMapping("/safe1")
public static String safe1(String content) {
    return HtmlUtils.htmlEscape(content);
}

3、对于富文本编辑器的XSS防御,一般采用白名单标签的方法,因为针对富文本的处理方式,需保留部分标签可以被解析使用:

public static String safe3(String content) {
    Safelist whitelist = (new Safelist())
           .addTags("p", "hr", "div", "img", "span", "textarea")  // 设置允许的标签
           .addAttributes("a", "href", "title")          // 设置标签允许的属性, 避免如nmouseover属性
           .addProtocols("img", "src", "http", "https")  // img的src属性只允许http和https开头
           .addProtocols("a", "href", "http", "https");
    return Jsoup.clean(content, whitelist);
}

4、采用OWASP Java Encoder会对特殊字符全转义

public static String safe5(String content){
    return Encode.forHtml(content);
}

5、使用ESAPI

ESAPI 是一个免费、开源的、网页应用程序安全控件库,它使程序员能够更容易写出更低风险的程序

public static String safe4(String content){
    return ESAPI.encoder().encodeForHTML(content);
}

6、编写全局过滤器实现拦截,并在web.xml进行配置

文章来源:https://blog.csdn.net/Gherbirthday0916/article/details/135031210
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。