Mushroom Notes Mushroom Notes
🍄首页
  • JavaSE

    • 基础篇
    • 数据结构
    • IO流
    • Stream流
    • 函数式接口
    • JUC
    • 反射
    • 网络编程
    • 设计模式
  • JavaEE

    • Servlet
    • JDBC
    • 会话技术
    • 过滤器监听器
    • 三层架构
  • JDK

    • 总览
  • JVM

    • 总览
  • 常用mate
  • CSS
  • JavaScript
  • rds 数据库

    • MySQL
    • MySQL 进阶
    • MySQL 库表规范
  • nosql 数据库

    • Redis
    • Redis 进阶
    • Redis 底层
    • MongoDB
  • Spring生态

    • Spring
    • Spring MVC
    • Spring boot
    • Spring Validation
  • Spring Cloud生态

    • Spring Cloud
    • 服务治理
    • 远程调用
    • 网关路由
    • 服务保护
    • 分布式事务
    • 消息中间件
  • 数据库

    • Mybatis
    • Mybatis Plus
    • Elasticsearch
    • Redisson
  • 通信

    • Netty
📚技术
  • 方案专题
  • 算法专题
  • BUG专题
  • 安装专题
  • 网安专题
  • 面试专题
  • 常用网站
  • 后端常用
  • 前端常用
  • 分类
  • 标签
  • 归档

kinoko

一位兴趣使然的热心码农
🍄首页
  • JavaSE

    • 基础篇
    • 数据结构
    • IO流
    • Stream流
    • 函数式接口
    • JUC
    • 反射
    • 网络编程
    • 设计模式
  • JavaEE

    • Servlet
    • JDBC
    • 会话技术
    • 过滤器监听器
    • 三层架构
  • JDK

    • 总览
  • JVM

    • 总览
  • 常用mate
  • CSS
  • JavaScript
  • rds 数据库

    • MySQL
    • MySQL 进阶
    • MySQL 库表规范
  • nosql 数据库

    • Redis
    • Redis 进阶
    • Redis 底层
    • MongoDB
  • Spring生态

    • Spring
    • Spring MVC
    • Spring boot
    • Spring Validation
  • Spring Cloud生态

    • Spring Cloud
    • 服务治理
    • 远程调用
    • 网关路由
    • 服务保护
    • 分布式事务
    • 消息中间件
  • 数据库

    • Mybatis
    • Mybatis Plus
    • Elasticsearch
    • Redisson
  • 通信

    • Netty
📚技术
  • 方案专题
  • 算法专题
  • BUG专题
  • 安装专题
  • 网安专题
  • 面试专题
  • 常用网站
  • 后端常用
  • 前端常用
  • 分类
  • 标签
  • 归档
  • 方案专题

  • 算法专题

  • BUG专题

  • 安装专题

  • 网安专题

    • XSS漏洞
      • XSS漏洞介绍
        • 植入JS代码攻击及危害分析
        • 植入HTML代码攻击及危害分析
      • 分类
      • 对策
        • 输入环节
        • Cookie防护
        • X-Frame-Options 响应头 (是否允许frame、iframe等标记)
        • 输出环节
      • 内容安全策略Content Security Policy(CSP)
      • 如何检测XSS漏洞
    • CSRF漏洞
    • 后台常见安全漏洞
    • SQL注入漏洞
    • API接口安全性
  • 面试专题

  • 专题
  • 网安专题
kinoko
2023-12-26
目录

XSS漏洞安全

# XSS漏洞介绍


XSS是Cross Site Scripting的缩写,中文翻译过来就是跨站脚本攻击,由于CSS的缩写与前端的层叠样式表(Cascading Style Sheets)的缩写混淆,所以在安全领域就把跨站脚本攻击缩写为XSS。
是一种通过植入JS脚本来引发的安全漏洞。

# 植入JS代码攻击及危害分析


外在表现形式

  • 直接注入JavaScript代码
  • 引用外部JS文件

基本实现原理

  • 通过img标签的src发送数据
  • 构造表单诱导用户输入账密
  • 构造隐藏的form表单自动提交
  • 页面强制跳转
  • 植入文字链接、图片链接

潜在危害

  • 获取管理员或者其他用户Cookie,冒充身份登录
  • 构造表单诱导用户输入账号、密码,获取账密
  • 跳转到其他网站,网站流量被窃取
  • 植入广告、外链等 通过隐藏友链提升其他网站百度权重(SEO黑帽)

# 植入HTML代码攻击及危害分析


外在表现形式

  • 构造img标签
  • 构造a标签
  • 构造iframe
  • 构造其他HTML标签直接注入JavaScript代码

基本实现原理

  • 通过img标签的src发送数据
  • 通过img的onerror触发脚本代码
  • 通过a标签被动触发脚本代码
  • href/onclick 通过iframe引入第三方页面
  • 直接构造文字链接或图片链接
  • style属性嵌入脚本代码 background-image:url("javascript:…");(浏览器已可防范)

潜在危害

  • 获取管理员或者其他用户Cookie,冒充身份登录
  • 构造表单诱导用户输入账号、密码,获取账密
  • 跳转到其他网站,网站流量被窃取
  • 植入广告、外链等 通过隐藏友链提升其他网站百度权重(SEO黑帽)

# 分类


分为存储型、反射型、DOM型:

  • 存储型XSS:经过后端服务处理,数据存储在数据库端
  • 反射型XSS:经过后端服务处理,不存储数据库
  • DOM型XSS:不经过后端服务处理,不存储数据库

image.png

# 对策


# 输入环节

  • 页面限制输入长度、特殊字符限制,后端代码限制输入长度、处理特殊字符
  • Filter过滤器统一处理(自定义处理规则、使用apache text、使用owasp AntiSamy)
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@WebFilter(filterName = "XSSFilter", urlPatterns = "/*")
public class XSSFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse
		response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		String path = req.getServletPath();
		//注解配置的是urlPatterns="/*"(过滤所有请求),所以这里对不需要过滤的静态资源url,作忽略处理(大家可以依照具体需求配置)
		String[] exclusionsUrls = {".js", ".gif", ".jpg", ".png", ".css", ".ico"};
		for (String str : exclusionsUrls) {
			if (path.contains(str)) {
				chain.doFilter(request, response);
				return;
			}
		}
		// 处理请求,在XssHttpServletRequestWrapper里定义XSS漏洞预防代码
		XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(req);
		chain.doFilter(xssRequest, response);
	}
    // Cookie防护
	// HttpServletResponse resp = (HttpServletResponse)response;
	// resp.setHeader("SET-COOKIE", "JSESSIONID=" + req.getSession().getId()+ "; HttpOnly");
	// resp.setHeader("x-frame-options","SAMEORIGIN"); //X-Frame-Options
	// resp.setHeader("Content-Security-Policy","default-src http: https:");
	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{

	}
	@Override
	public void destroy() {

	}

}
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
import com.alibaba.fastjson.JSON;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

	HttpServletRequest orgRequest;

	public XssHttpServletRequestWrapper(HttpServletRequest request) {
		super(request);
		orgRequest = request;
	}

	/**
	 * 获取最原始的request的静态方法
	 * @return R
	 */
	public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
		if (req instanceof XssHttpServletRequestWrapper) {
			return ((XssHttpServletRequestWrapper) req).getOrgRequest();
		}
		return req;
	}

	/**
	 * 核心 XSS检测 处理
	 * @param str 字符串
	 * @return 处理结果
	 */
	private String xssEncode(String str) {
		// 通过改变这个对象来达到执行不同XSS预防策略实现
		return XSSEncode.xssEncode(str);
	}

	/**
	 * 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>
	 * 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>
	 * getParameterNames,getParameterValues和getParameterMap也可能需要覆
	 * 盖
	 */
	@Override
	public String getParameter(String name) {
		String value = super.getParameter(xssEncode(name));
		if (value != null) {
			value = xssEncode(value);
		}
		return value;
	}

	/**
	 * 重写getParameterMap
	 */
	@Override
	public Map<String, String[]> getParameterMap() {
		HashMap<String, String[]> paramMap = (HashMap<String,
			String[]>) super.getParameterMap();
		paramMap = (HashMap<String, String[]>) paramMap.clone();
		for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {
			String[] values = entry.getValue();
			for (int i = 0; i < values.length; i++) {
				if (values[i] instanceof String) {
					values[i] = xssEncode(values[i]);
				}
			}
			entry.setValue(values);
		}
		return paramMap;
	}

	/**
	 * 重写getParameterValues
	 */
	@Override
	public String[] getParameterValues(String name) {
		String[] values = super.getParameterValues(name);
		if (values == null) {
			values = new String[]{};
		}
		int count = values.length;
		String[] encodedValues = new String[count];
		for (int i = 0; i < count; i++) {
			encodedValues[i] = xssEncode(values[i]);
		}
		return encodedValues;
	}

	/**
	 * 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>
	 * 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/>
	 * getHeaderNames 也可能需要覆盖
	 */
	@Override
	public String getHeader(String name) {
		String value = super.getHeader(xssEncode(name));
		if (value != null) {
			value = xssEncode(value);
		}
		return value;
	}

	@Override
	public String getQueryString() {
		return xssEncode(super.getQueryString());
	}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		String str = getRequestBody(super.getInputStream());
		Map<String, Object> map = JSON.parseObject(str, Map.class);
		Map<String, Object> resultMap = new HashMap<>(map.size());
		for (String key : map.keySet()) {
			Object val = map.get(key);
			if (map.get(key) instanceof String) {
				resultMap.put(key, xssEncode(val.toString()));
			} else {
				resultMap.put(key, val);
			}
		}
		str = JSON.toJSONString(resultMap);
		final ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
		return new ServletInputStream() {
			@Override
			public int read() {
				return bais.read();
			}

			@Override
			public boolean isFinished() {
				return false;
			}

			@Override
			public boolean isReady() {
				return false;
			}

			@Override
			public void setReadListener(ReadListener listener) {
			}
		};
	}

	/**
	 * 处理比较的json字符串
	 * @param stream	输入流
	 * @return	R
	 */
	private String getRequestBody(InputStream stream) {
		String line = "";
		StringBuilder body = new StringBuilder();
		// 读取POST提交的数据内容
		BufferedReader reader = new BufferedReader(new
			InputStreamReader(stream, StandardCharsets.UTF_8));
		try {
			while ((line = reader.readLine()) != null) {
				body.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return body.toString();
	}

	/**
	 * 获取最原始的request
	 * @return R
	 */
	public HttpServletRequest getOrgRequest() {
		return orgRequest;
	}
}
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<dependency>
    <groupId>org.owasp.antisamy</groupId>
    <artifactId>antisamy</artifactId>
    <version>1.5.8</version>
</dependency>
1
2
3
4
5
import org.owasp.validator.html.*;

/**
 * @author liujunkai
 * @date 2022/11/10 16:46
 */
public class XSSEncode {

	private static Policy policy;

	// 加载默认预防策略文件
	static {
		String path = XSSEncode.class.getClassLoader().getResource("antisamy-anythinggoes.xml").getFile();
		System.out.println("policy_filepath:" + path);
		if (path.startsWith("file")){
			path = path.substring(6);
		}
		try {
			policy = Policy.getInstance(path);
		} catch (PolicyException e) {
			e.printStackTrace();
		}
	}

	public static String xssEncode(String str) {
		// XSS漏洞处理具体实现
		AntiSamy antiSamy = new AntiSamy();
		try {
			final CleanResults cr = antiSamy.scan(str, policy);
			return cr.getCleanHTML();
		} catch (ScanException | PolicyException e) {
			e.printStackTrace();
		}
		return str;
	}

	public static void main(String[] args) {
		System.out.println(xssEncode("hyf<script>alert(1)</script>"));
	}

}
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

antisamy提供的策略选择:

提示

antisamy-slashdot.xml
Slashdot (http://www.slashdot.org/) (opens new window))是一个提供技术新闻的网站,它允许用户用有限的HTML格式的内容匿名回帖。
Slashdot不仅仅是目前同类中最酷的网站之一,而且同时也曾是最容易被成功攻击的网站之一。更不幸的是,导致大部分用户遭受攻击的原由是臭名昭着的goatse.cx 图片(请你不要刻意去看)。
Slashdot的安全策略非常严格:用户只能提交下列的html标签:<b>, <u>, <i>, <a>, <blockquote>,并且还不支持CSS.
因此我们创建了这样的策略文件来实现类似的功能。它允许所有文本格式的标签来直接修饰字体、颜色或者强调作用。

antisamy-ebay.xml
众所周知,eBay (http://www.ebay.com/) (opens new window))是当下最流行的在线拍卖网站之一。它是一个面向公众的站点,因此它允许任何人发布一系列富HTML的内容。
我们对eBay成为一些复杂XSS攻击的目标,并对攻击者充满吸引力丝毫不感到奇怪。由于eBay允许输入的内容列表包含了比Slashdot更多的富文本内容,所以它的受攻击面也要大得多。下面的标签看起来是eBay允许的(eBay没有公开标签的验证规则):<a>,...

antisamy-myspace.xml
MySpace (http://www.myspace.com/) (opens new window))是最流行的一个社交网站之一。用户允许提交几乎所有的他们想用的HTML和CSS,只要不包含JavaScript。
MySpace现在用一个黑名单来验证用户输入的HTML,这就是为什么它曾受到Samy蠕虫攻击(http://namb.la/) (opens new window))的原因。Samy蠕虫攻击利用了一个本应该列入黑名单的单词(eval)来进行组合碎片攻击的,其实这也是AntiSamy立项的原因。

antisamy-anythinggoes.xml
我也很难说出一个用这个策略文件的用例。如果你想允许所有有效的HTML和CSS元素输入(但能拒绝JavaScript或跟CSS相关的网络钓鱼攻击),你可以使用这个策略文件。其实即使MySpace也没有这么疯狂。然而,它确实提供了一个很好的参考,因为它包含了对于每个元素的基本规则,所以你在裁剪其它策略文件的时候可以把它作为一个知识库。

# Cookie防护


  • cookie设置httponly,一般servlet容器默认httponly true (java的servlet容器 默认为true)

在yaml里server.servlet.session.cookie.http-only可以设置,默认为true

  • resp.setHeader("SET-COOKIE", "JSESSIONID=" + request.getSession().getId()+ "; HttpOnly")

# X-Frame-Options 响应头 (是否允许frame、iframe等标记)


  • DENY 不允许、SAMEORIGIN 可在相同域名页面的 frame 中展示、ALLOW-FROM uri 可在指定页 的 frame 中展示
  • 在nginx的http或server节点中配置:add_header X-Frame-Options SAMEORIGIN;
  • 也可通过filter设置 resp.setHeader("x-frame-options","SAMEORIGIN");

保证自己的页面不会被嵌入到非同源的网页中

# 输出环节


  • 使用 OWASP ESAPI for Java
  • 显示时对字符进行转义处理,各种模板都有相关语法,注意标签的正确使用
  • 避免 .innerHTML、.outerHTML、document.write(),应使用 .textContent、.setAttribute() 等。
  • Vue/React 技术栈,避免使用 v-html/dangerouslySetInnerHTML
  • 尤其注意onclick、onerror、onload、onmouseover 、eval()、setTimeout()、setInterval() 以及 的 href 可使用OWASP esapi4js: esapi.js

# 内容安全策略Content Security Policy(CSP)


开启CSP方法

  • 设置 HTTP 的 头部字段 resp.setHeader("Content-Security-Policy","default-src http: https:");
  • 设置网页的标签
    | 策略 | 含义 | | --- | --- | | default-srchttp:https:; | 只能通过外联的方式引用js和css | | default-src'self'http://aa.com/ (opens new window); | 只能在指定的域下加载文件(包含img) | | form-action'self''; | form表单的只能在指定域提交 | | script-src'self'; | 只限制js文件在同域加载文件 | | report-uri/report; | 向指定uri发送违规报告(不支持meta方式) |

# 如何检测XSS漏洞


  1. 使用通用 XSS 攻击字符串手动检测 XSS 漏洞
    https://github.com/0xsobky/HackVault/wiki/Unleashing-an-Ultimate-XSS-Polyglot (opens new window)
JaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert()
)//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/-
-!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
1
2
3
  1. 使用扫描工具自动检测 XSS 漏洞
    Arachni : https://github.com/Arachni/arachni (opens new window)
    Mozilla HTTP Observatory:https://github.com/mozilla/http-observatory/ (opens new window) w3af:https://github.com/andresriancho/w3af (opens new window)
#xss#安全
上次更新: 2023/12/29 11:32:56
NVM安装
CSRF漏洞

← NVM安装 CSRF漏洞→

最近更新
01
JVM 底层
09-13
02
JVM 理论
09-13
03
JVM 应用
09-13
更多文章>
Theme by Vdoing | Copyright © 2022-2024 kinoko | MIT License | 粤ICP备2024165634号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式