Skip to content

Commit ad10c6a

Browse files
committed
Optimize XSS module
1 parent 35af310 commit ad10c6a

4 files changed

Lines changed: 99 additions & 32 deletions

File tree

docs/instructions.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,101 @@
11
# 常规漏洞
22

33
## 跨站脚本
4+
跨站脚本模块适合作为综合性Java靶场的核心模块:当前覆盖了反射型、存储型、DOM型、模板引擎不安全渲染、文件上传导致的存储型XSS、第三方组件XSS、WebSocket XSS、postMessage XSS、CSP、HttpOnly、输出编码等常见场景。
5+
6+
本次已将页面描述统一为:XSS的本质是不可信数据进入浏览器页面执行上下文后,被当作HTML、脚本、URL或可执行DOM操作解析。修复优先按输出上下文处理数据,普通文本使用HTML实体编码或安全DOM API,URL/属性/JavaScript/CSS等位置使用对应编码与白名单校验;CSP、HttpOnly、输入过滤是辅助防护,不能替代根因修复。
7+
8+
已覆盖类型
9+
10+
| 分类 | 已有场景 | 结论 |
11+
| --- | --- | --- |
12+
| 反射型XSS | GET/POST参数、String直出、Content-Type差异 | 覆盖请求即触发、响应类型影响浏览器解析的基础成因 |
13+
| 反射型安全写法 | 前后端白名单、CSP、HTML正文输出编码、HttpOnly | 覆盖常见防护,并明确白名单/CSP/HttpOnly不是根因修复 |
14+
| 存储型XSS | 表单内容、User-Agent持久化、表格不安全渲染 | 覆盖先存储后触发,也包含Header进入持久化链路 |
15+
| 存储型安全写法 | 表格渲染阶段输出编码 | 说明数据库可保存原始值,进入页面前必须按上下文编码或净化 |
16+
| DOM型XSS | innerHTML、localStorage、hash跳转、location、eval、document.write | 覆盖常见Source到Sink的客户端链路 |
17+
| DOM型安全写法 | textContent、URL协议白名单、命令映射、createTextNode | 覆盖DOM侧推荐修复方式 |
18+
| 其他场景 | Thymeleaf `th:utext`、文件上传、jQuery/Swagger/UEditor、WebSocket、postMessage | 覆盖模板、文件、供应链与HTML5通信场景 |
19+
20+
模块覆盖整体符合综合性靶场定位。JSONP类XSS/脚本回调污染在项目中已有跨域模块承载,不建议在XSS模块重复堆叠;后续如需扩展,可优先补充“属性上下文XSS”“JavaScript字符串上下文XSS”“富文本白名单净化绕过对比”“Markdown/预览器XSS”等更贴近真实业务的场景。
21+
22+
### 反射型XSS测试
23+
24+
页面:`/xss/reflect/vul`
25+
26+
| 场景 | 请求 | 测试输入 | 预期结果 |
27+
| --- | --- | --- | --- |
28+
| GET型JSON返回 | `GET /xss/reflect/vul1?payload=<img src=x onerror=alert(1)>` | HTML事件载荷 | 接口返回payload;页面结果区使用不安全HTML渲染时可触发 |
29+
| POST型JSON返回 | `POST /xss/reflect/vul1` | `payload=<img src=x onerror=alert(1)>` | 接口返回payload;验证POST入口同样可控 |
30+
| String直出 | `GET /xss/reflect/vul2?payload=<script>alert(1)</script>` | 脚本标签 | 响应体直接包含payload,用于观察浏览器解析行为 |
31+
| text/plain | `GET /xss/reflect/vul3?type=plain&payload=<script>alert(1)</script>` | 脚本标签 | `Content-Type``text/plain;charset=utf-8`,浏览器按文本展示 |
32+
| text/html | `GET /xss/reflect/vul3?type=html&payload=<script>alert(1)</script>` | 脚本标签 | `Content-Type``text/html;charset=utf-8`,浏览器按HTML解析 |
33+
| 流量包/示例载荷 | 页面下拉与按钮 | 标签探测、流量劫持、Cookie读取、页面篡改 | 示例可填充,按钮可提交 |
34+
35+
### 反射型安全场景测试
36+
37+
页面:`/xss/reflect/safe`
38+
39+
| 场景 | 请求 | 测试输入 | 预期结果 |
40+
| --- | --- | --- | --- |
41+
| 前端白名单 | `GET /xss/reflect/safe1?type=frontEnd&payload=<script>alert(1)</script>` | 非白名单字符 | 页面按钮触发时前端拦截;直接请求仍会返回,说明前端不是安全边界 |
42+
| 后端白名单 | `GET /xss/reflect/safe1?type=backEnd&payload=<script>alert(1)</script>` | 非白名单字符 | 返回“输入内容包含非法字符,请检查输入” |
43+
| CSP Header | `GET /xss/reflect/safe2?payload=<script>alert(1)</script>` | 脚本标签 | 响应包含`Content-Security-Policy`,用于演示防御层 |
44+
| HTML正文手动编码 | `GET /xss/reflect/safe3?type=manual&payload=<img src=x onerror=alert(1)>` | HTML事件载荷 | 返回实体编码后的内容,不作为标签执行 |
45+
| Spring HTML编码 | `GET /xss/reflect/safe3?type=spring&payload=<img src=x onerror=alert(1)>` | HTML事件载荷 | 返回Spring编码后的内容 |
46+
| HttpOnly | `GET /xss/reflect/safe4?payload=<script>alert(document.cookie)</script>` | Cookie读取载荷 | 返回设置结果,响应`Set-Cookie`应带`HttpOnly` |
47+
48+
### 存储型XSS测试
49+
50+
页面:`/xss/store`
51+
52+
| 场景 | 请求 | 测试输入 | 预期结果 |
53+
| --- | --- | --- | --- |
54+
| 原生写入 | `POST /xss/store/vul` | `payload=<img src=x onerror=alert(1)>` | 写入成功,漏洞表格不安全渲染时可触发 |
55+
| User-Agent持久化 | `POST /xss/store/vul` | Header `User-Agent: <img src=x onerror=alert(1)>` | UA字段被持久化,漏洞表格不安全渲染时可触发 |
56+
| 列表查询 | `GET /xss/store/getXssList?page=1&limit=10` || 返回分页数据,包含刚写入记录 |
57+
| 安全表格 | 页面安全场景表格 | 已存储恶意内容 | Content与User-Agent经HTML实体编码展示,不执行脚本 |
58+
| 删除记录 | `POST /xss/store/deleteOne?id=<记录ID>` | 已存在ID | 返回删除成功,页面表格记录消失 |
59+
60+
### DOM型XSS测试
61+
62+
页面:`/xss/dom`
63+
64+
| 场景 | 入口 | 测试输入 | 预期结果 |
65+
| --- | --- | --- | --- |
66+
| innerHTML | 多种代码场景/innerHTML | `123<img src=x onerror=alert(1)>123` | 结果区使用`innerHTML`写入,事件载荷可执行 |
67+
| LocalStorage | 多种代码场景/LocalStorage | `123<img src=x onerror=alert(1)>123` | 先写入`localStorage`,再读取并不安全写入DOM |
68+
| hash跳转 | `/xss/dom/href#javascript:alert(1)` | `javascript:`伪协议 | 页面读取`location.hash`并赋值给`location.href` |
69+
| location | 多种代码场景/location对象 | `javascript:alert(1)` | 直接赋值给`window.location`,用于演示危险URL Sink |
70+
| eval | 多种代码场景/eval执行 | `alert(1)` | 用户输入被`eval`执行 |
71+
| document.write | 多种代码场景/document对象 | `<img src=x onerror=alert(1)>` | `document.write`写入HTML并可能触发 |
72+
| 文本安全输出 | 安全场景/文本输出 | `<img src=x onerror=alert(1)>` | 使用`textContent`,作为文本展示 |
73+
| URL安全校验 | 安全场景/URL跳转 | `javascript:alert(1)` | 拦截危险协议 |
74+
| 替代eval | 安全场景/替代eval | `alert(1)` | 命令白名单无匹配,拒绝执行 |
75+
| DOM API | 安全场景/DOM API | `<img src=x onerror=alert(1)>` | 使用文本节点展示,不执行脚本 |
76+
77+
### 其他XSS场景测试
78+
79+
页面:`/xss/other`
80+
81+
| 场景 | 请求/入口 | 测试输入 | 预期结果 |
82+
| --- | --- | --- | --- |
83+
| Thymeleaf `th:utext` | `GET /xss/other/vul2OtherTemplate?type=html&payload=<img src=x onerror=alert(1)>` | HTML事件载荷 | `th:utext`按HTML渲染,演示模板不安全输出 |
84+
| Thymeleaf `th:text` | `GET /xss/other/vul2OtherTemplate?type=text&payload=<img src=x onerror=alert(1)>` | HTML事件载荷 | `th:text`实体转义,作为文本展示 |
85+
| HTML文件上传 | `POST /xss/other/vul1Upload?type=html` | `xss.html` | 返回可访问文件路径,访问后按浏览器解析策略触发/展示 |
86+
| SVG文件上传 | `POST /xss/other/vul1Upload?type=svg` | `xss.svg` | 返回可访问文件路径,用于验证可解析文件风险 |
87+
| XML文件上传 | `POST /xss/other/vul1Upload?type=xml` | `xss.xml` | 后端解析成功后落盘,返回访问路径 |
88+
| PDF文件上传 | `POST /xss/other/vul1Upload?type=pdf` | `xss.pdf` | 返回访问路径;PDF脚本执行能力取决于阅读器实现 |
89+
| jQuery组件XSS | `/xss/other/jquery-xss` | 页面内示例 | 页面可打开,用于演示旧版jQuery风险 |
90+
| Swagger UI组件XSS | `/swagger-ui/index.html?configUrl=...` | 恶意配置URL示例 | 页面可打开,用于供应链组件风险演示 |
91+
| UEditor | `/ueditor``/ueditor/config` | 编辑器上传/配置 | 页面与配置接口可访问,上传接口返回UEditor格式结果 |
92+
| WebSocket XSS | 页面HTML5特性/WebSocket XSS | `<img src=x onerror=alert(1)>` | 服务端广播消息,前端用`innerHTML`写入消息区 |
93+
| postMessage XSS | 页面HTML5特性/PostMessage XSS | `<img src=x onerror=alert(1)>` | 接收窗口未校验origin且用`innerHTML`写入消息 |
494

595

696

797
## SQL注入
98+
899
SQL注入模块适合作为综合性Java靶场的核心模块:当前覆盖了JDBC原生拼接、伪预编译拼接、JdbcTemplate拼接、参数化查询、MyBatis动态SQL、Hibernate HQL/原生SQL、JPA JPQL/动态排序等常见开发栈。
9100

10101
本次已将页面描述统一为:SQL注入的本质是不可信输入进入SQL语法结构并改变原SQL语义;修复优先使用参数化查询,列名、表名、排序方向等SQL结构必须使用枚举或白名单映射。黑名单、类型校验、ESAPI编码只作为辅助方案,不应作为首选修复方案。

src/main/java/top/whgojp/modules/xss/controller/UEditorController.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,8 @@ public String ueditor() {
4646
public void getConfigInfo(HttpServletRequest request, HttpServletResponse response) {
4747
response.setContentType("application/json");
4848

49-
String rootPath = "";
50-
// 判断当前系统是否是Windows系统
51-
if (isWindowsSystem()) {
52-
rootPath = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "static/ueditor/jsp";
53-
} else {
54-
// 将config.json文件放在jar包同级目录下
55-
rootPath = "/Users/whgojp/Desktop/Security/JAVA/JavaSecLab/src/main/resources/static/lib/ueditor/jsp";
56-
}
49+
String rootPath = Objects.requireNonNull(ClassUtils.getDefaultClassLoader().getResource("")).getPath()
50+
+ "static/lib/ueditor/jsp";
5751
log.info("rootPath:{}", rootPath);
5852
try {
5953
response.setCharacterEncoding("UTF-8");

src/main/resources/templates/vul/xss/other.html

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,9 @@ <h1><span class="iconfont icon-bug"> 漏洞场景:HTML5特性XSS</span></h1>
409409
<div class="layui-card-body layui-text layadmin-text">
410410
<pre style="color: #28333e;font-size: 12px;">
411411
1. WebSocket XSS
412-
- WebSocket通信不受同源策略限制,可以连接到任意域名的WebSocket服务器
412+
- 浏览器会在WebSocket握手中携带Origin,但是否允许连接取决于服务端校验
413413
- WebSocket消息内容可能包含恶意代码,如果直接插入DOM会导致XSS
414-
- 缺乏消息验证和过滤机制,攻击者可以发送任意内容
414+
- 服务端缺少Origin校验、认证授权和消息内容校验时,攻击者可以发送非预期内容
415415
2. PostMessage XSS
416416
- postMessage跨域通信可能被滥用,特别是targetOrigin设置为*时
417417
- 接收方没有正确验证消息来源,可能处理恶意消息
@@ -449,24 +449,6 @@ <h1><span class="iconfont icon-code"> 缺陷代码</span></h1>
449449
</div>
450450

451451
<script th:replace="~{common/common::script}"></script>
452-
<script src="/lib/ueditor/ueditor.config.js" charset="utf-8"></script>
453-
<script src="/lib/ueditor/ueditor.all.min.js" charset="utf-8"></script>
454-
<script src="/lib/ueditor/lang/zh-cn/zh-cn.js" charset="utf-8"></script>
455-
<script th:inline="none">
456-
UE.Editor.prototype._bkGetActionUrl = UE.Editor.prototype.getActionUrl;
457-
UE.Editor.prototype.getActionUrl = function (action) {
458-
if (action === 'uploadimage') {
459-
return '/ueditor/upload';
460-
} else {
461-
return this._bkGetActionUrl.call(this, action);
462-
}
463-
}
464-
465-
var uee = UE.getEditor('ueditorContent', {
466-
toolbars: [['fullscreen', 'source', '|', 'undo', 'redo', '|', 'simpleupload', 'insertimage', '|', 'drafts']]
467-
});
468-
</script>
469-
470452
<script>
471453
layui.use(['layer', 'miniTab', 'common', 'upload', 'form'], function () {
472454
var $ = layui.jquery,

src/main/resources/templates/vul/xss/reflect/safe.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ <h1><span class="iconfont icon-anquan"> 安全场景:上下文输出编码</sp
191191
123&lt;a href=javascript:alert(/xss/)&gt;Click Me&lt;/a&gt;123
192192
</option>
193193
</select>
194-
<button class="layui-btn layui-btn-normal" style="width: 100px; margin-left: 10px;" lay-filter="safe3-EntityEscape" lay-submit="">
194+
<button class="layui-btn layui-btn-normal" style="width: 100px; margin-left: 10px;" lay-filter="safe3-EntityEscape-manual" lay-submit="">
195195
<span class="iconfont icon-zhihang">Run</span>
196196
</button>
197197
</div>
@@ -206,7 +206,7 @@ <h1><span class="iconfont icon-anquan"> 安全场景:上下文输出编码</sp
206206
lay-verify="required" value="<script>alert(/xss/)</script>" autocomplete="off"
207207
class="layui-input" id="safe3-EntityEscape">
208208
<p>使用Spring框架内置安全工具类实体转义</p>
209-
<button class="layui-btn layui-btn-normal" style="width: 100px; margin-left: 10px;" lay-filter="safe3-EntityEscape" lay-submit="">
209+
<button class="layui-btn layui-btn-normal" style="width: 100px; margin-left: 10px;" lay-filter="safe3-EntityEscape-spring" lay-submit="">
210210
<span class="iconfont icon-zhihang">Run</span>
211211
</button>
212212
</form>
@@ -335,8 +335,8 @@ <h1><span class="iconfont icon-code"> 安全代码</span></h1>
335335
common.formListenFun("safe1-CheckUserInput-back", "backEnd", "/xss/reflect/safe1", "safe1-CheckUserInput-result", "get");
336336
common.selectListenFun("safe1-CheckUserInput-front", "safe1-CheckUserInput-front-input");
337337

338-
common.formListenFun("safe3-EntityEscape", "manual", "/xss/reflect/safe3", "safe3-EntityEscape-result", "get");
339-
common.formListenFun("safe3-EntityEscape", "spring", "/xss/reflect/safe3", "safe3-EntityEscape-result", "get");
338+
common.formListenFun("safe3-EntityEscape-manual", "manual", "/xss/reflect/safe3", "safe3-EntityEscape-result", "get");
339+
common.formListenFun("safe3-EntityEscape-spring", "spring", "/xss/reflect/safe3", "safe3-EntityEscape-result", "get");
340340
common.selectListenFun("safe3-EntityEscape", "safe3-EntityEscape-input");
341341

342342
common.formListenFun("safe4-HttpOnly", "", "/xss/reflect/safe4", "safe4-HttpOnly-result", "get");

0 commit comments

Comments
 (0)