XSS漏洞

247 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,[点击查看活动详情]

攻击者利用XSS(Cross-site scripting)漏洞攻击可以在用户的浏览器中执行JS恶意脚本,XSS攻击可以实现用户会话劫持、钓鱼攻击、恶意重定向、点击劫持、挂马、XSS蠕虫等,XSS攻击类型分为:反射型、存储型、DOM型。

  1. 反射型XSS攻击 示例 - 存在反射型XSS的xss.jsp代码:

<%=request.getParameter("input")%> 攻击者通过传入恶意的input参数值可以在用户浏览器中注入一段JavaScript脚本。

示例 - 注入XSS代码:

浏览器请求:http://localhost:8000/modules/servlet/xss.jsp?input=%3Cscript%3Ealert(%27xss%27)%3B%3C/script%3E;%3C/script%3E)

  1. 存储型XSS攻击 示例 - 存在存储型XSS的guestbook.jsp代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="java.text.SimpleDateFormat" %> <%@ page import="java.util.*" %> <% String username = request.getParameter("username"); String content = request.getParameter("content");

String guestBookKey = "GUEST_BOOK";
List<Map<String, String>> comments = new ArrayList<Map<String, String>>();

if (content != null) {
    Object obj = application.getAttribute(guestBookKey);

    if (obj != null) {
        comments = (List<Map<String, String>>) obj;
    }

    Map<String, String> comment = new HashMap<String, String>();
    String              ip      = request.getHeader("x-real-ip");

    if (ip == null) {
        ip = request.getRemoteAddr();
    }

    comment.put("username", username);
    comment.put("content", content);
    comment.put("ip", ip);
    comment.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

    comments.add(comment);

    application.setAttribute(guestBookKey, comments);
}

%>

留言板 * { margin: 0; padding: 0; }

在线留言板

<% Object obj = application.getAttribute(guestBookKey);
            if (obj instanceof List) {
                comments = (List<Map<String, String>>) obj;

                for (Map<String, String> comment : comments) {
        %>
        <dd>
            <div style="min-height: 50px; margin: 20px; border-bottom: 1px solid #9F9F9F;">
                <p><B><%=comment.get("username")%>
                </B>[<%=comment.get("ip")%>] 于 <%=comment.get("date")%> 发表回复:</p>
                <p style="margin: 15px 0 5px 0; font-size: 12px;">
                <pre><%=comment.get("content")%></pre>
                </p>
            </div>
        </dd>
        <%
                }
            }
        %>
    </dl>
</div>
<div style="background-color: #fff; border: 1px solid #C6C6C6;">
    <form action="#" method="POST" style="margin: 20px;">
        昵称: <input type="text" name="username" style="width:250px; height: 28px;"/><br/><br/>
        <textarea name="content" style="overflow: auto;width: 100%; height: 250px;"></textarea>
        <input type="submit" value="提交留言" style="margin-top: 20px; width: 80px; height: 30px;"/>
    </form>
</div>
访问:http://10.10.99.2:8000/modules/servlet/guestbook.jsp,并在留言内容出填入xss测试代码,如下:

提交留言后页面会刷新,并执行留言的xss代码:

  1. DOM XSS 示例 - dom.jsp代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %> Date: <input type="hidden" value="<%=request.getParameter("date")%>" />

正常请求测试:http://localhost:8000/modules/servlet/dom.jsp?date=2020-11-15%2015:57:22

XSS攻击测试:http://localhost:8000/modules/servlet/dom.jsp?date=%3Cimg%20src=1%20onerror=alert(/xss/)%20/%3E%20/%3E)

  1. XSS防御 XSS最为常见的处理方式是转义特殊字符,后端程序在接受任何用户输入的参数时都应当优先考虑是否会存在XSS攻击。

4.1 htmlspecialchars 在PHP中通常会使用htmlspecialchars函数会将一些可能有攻击威胁的字符串转义为html实体编码,这样可以有效的避免XSS攻击。

示例 - htmlspecialchars 转义:

字符 替换后 & (& 符号) & " (双引号) " ' (单引号) '或者' < (小于) <

(大于) > 在Java中虽然没有内置如此简单方便的函数,但是我们可以通过字符串替换的方式实现类似htmlspecialchars函数的功能。

/**

  • 实现htmlSpecialChars函数把一些预定义的字符转换为HTML实体编码
  • @param content 输入的字符串内容
  • @return HTML实体化转义后的字符串 */ public static String htmlSpecialChars(String content) { if (content == null) { return null; }

char[] charArray = content.toCharArray(); StringBuilder sb = new StringBuilder();

for (char c : charArray) { switch (c) { case '&': sb.append("&"); break; case '"': sb.append("""); break; case ''': sb.append("'"); break; case '<': sb.append("<"); break; case '>': sb.append(">"); break; default: sb.append(c); break; } }

return sb.toString(); } 在存储或者输出请求参数的时候使用该方法过滤即可实现XSS防御。

4.2 全局的XSSFilter package com.anbai.sec.vuls.filter;

import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import jav