Skip to content

Commit 78ff85c

Browse files
committed
fix payment module
1 parent 9a1ef00 commit 78ff85c

File tree

2 files changed

+165
-50
lines changed

2 files changed

+165
-50
lines changed

src/main/resources/static/js/staticcode.js

Lines changed: 164 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
* @Date: 2024/5/19 19:03
66
*/
77
const vul1ReflectRaw = "// 原生漏洞场景,未加任何过滤,Controller接口返回Json类型结果\n" +
8-
"public R vul1(String content) {\n" +
9-
" return R.ok(content);\n" +
8+
"public R vul1(String payload) {\n" +
9+
" return R.ok(payload);\n" +
1010
"}\n" +
1111
"// R 是对返回结果的封装工具util\n" +
1212
"// 返回结果:\n" +
@@ -17,19 +17,19 @@ const vul1ReflectRaw = "// 原生漏洞场景,未加任何过滤,Controller接
1717
"// payload在json中是不会触发xss的 需要解析到页面中\n" +
1818
"\n" +
1919
"// 原生漏洞场景,未加任何过滤,Controller接口返回String类型结果\n" +
20-
"public String vul2(String content) {\n" +
21-
" return content;\n" +
20+
"public String vul2(String payload) {\n" +
21+
" return payload;\n" +
2222
"}"
2323
const vul2ReflectContentType = "// Tomcat内置HttpServletResponse,Content-Type导致反射XSS\n" +
24-
"public void vul3(String type,String content, HttpServletResponse response) {\n" +
24+
"public void vul3(String type,String payload, HttpServletResponse response) {\n" +
2525
" switch (type) {\n" +
2626
" case \"html\":\n" +
27-
" response.getWriter().print(content);\n" +
27+
" response.getWriter().print(payload);\n" +
2828
" response.setContentType(\"text/html;charset=utf-8\");\n" +
2929
" response.getWriter().flush();\n" +
3030
" break;\n" +
3131
" case \"plain\":\n" +
32-
" response.getWriter().print(content);\n" +
32+
" response.getWriter().print(payload);\n" +
3333
" response.setContentType(\"text/plain;charset=utf-8\");\n" +
3434
" response.getWriter().flush();\n" +
3535
" ...\n" +
@@ -51,51 +51,51 @@ const safe1CheckUserInput = "// 对用户输入的数据进行验证和过滤,
5151
"private static final String WHITELIST_REGEX = \"^[a-zA-Z0-9_\\\\s]+$\";\n" +
5252
"private static final Pattern pattern = Pattern.compile(WHITELIST_REGEX);\n" +
5353
"\n" +
54-
"Matcher matcher = pattern.matcher(content);\n" +
54+
"Matcher matcher = pattern.matcher(payload);\n" +
5555
"if (matcher.matches()){\n" +
56-
" return R.ok(content);\n" +
56+
" return R.ok(payload);\n" +
5757
"}else return R.error(\"输入内容包含非法字符,请检查输入\");"
5858
const safe2CSP = "// 内容安全策略(Content Security Policy)是一种由浏览器实施的安全机制,旨在减少和防范跨站脚本攻击(XSS)等安全威胁。它通过允许网站管理员定义哪些内容来源是可信任的,从而防止恶意内容的加载和执行\n" +
5959
"// 前端Meta配置\n" +
6060
"<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; script-src 'self' https://apis.example.com; style-src 'self' https://fonts.googleapis.com; img-src 'self' data: https://*.example.com;\">\n" +
6161
"\n" +
6262
"\n" +
6363
"// 后端Header配置\n" +
64-
"public String safe2(String content,HttpServletResponse response) {\n" +
64+
"public String safe2(String payload,HttpServletResponse response) {\n" +
6565
" response.setHeader(\"Content-Security-Policy\",\"default-src self\");\n" +
66-
" return content;\n" +
66+
" return payload;\n" +
6767
"}"
6868

6969
const safe3EntityEscape = '// 特殊字符实体转义是一种将HTML中的特殊字符转换为预定义实体表示的过程\n' +
7070
'// 这种转义是为了确保在HTML页面中正确显示特定字符,同时避免它们被浏览器误解为HTML标签或JavaScript代码的一部分,从而导致页面结构混乱或安全漏洞\n' +
71-
'public R safe3(@ApiParam(String type, String content) {\n' +
71+
'public R safe3(@ApiParam(String type, String payload) {\n' +
7272
' String filterContented = "";\n' +
7373
' switch (type){\n' +
7474
' case "manual":\n' +
75-
' content = StringUtils.replace(content, "&", "&amp;");\n' +
76-
' content = StringUtils.replace(content, "<", "&lt;");\n' +
77-
' content = StringUtils.replace(content, ">", "&gt;");\n' +
78-
' content = StringUtils.replace(content, "\\"", "&quot;");\n' +
79-
' content = StringUtils.replace(content, "\'", "&#x27;");\n' +
80-
' content = StringUtils.replace(content, "/", "&#x2F;");\n' +
81-
' filterContented = content;\n' +
75+
' payload = StringUtils.replace(payload, "&", "&amp;");\n' +
76+
' payload = StringUtils.replace(payload, "<", "&lt;");\n' +
77+
' payload = StringUtils.replace(payload, ">", "&gt;");\n' +
78+
' payload = StringUtils.replace(payload, "\\"", "&quot;");\n' +
79+
' payload = StringUtils.replace(payload, "\'", "&#x27;");\n' +
80+
' payload = StringUtils.replace(payload, "/", "&#x2F;");\n' +
81+
' filterContented = payload;\n' +
8282
' break;\n' +
8383
' case "spring":\n' +
84-
' filterContented = HtmlUtils.htmlEscape(content);\n' +
84+
' filterContented = HtmlUtils.htmlEscape(payload);\n' +
8585
' break;\n' +
8686
' ...\n' +
8787
' }\n' +
8888
'}'
8989

9090
const safe4HttpOnly = "// HttpOnly是HTTP响应头属性,用于增强Web应用程序安全性。它防止客户端脚本访问(只能通过http/https协议访问)带有HttpOnly标记的 cookie,从而减少跨站点脚本攻击(XSS)的风险\n" +
9191
"// 单个接口配置\n" +
92-
"public R safe4(String content, HttpServletRequest request,HttpServletResponse response) {\n" +
92+
"public R safe4(String payload, HttpServletRequest request,HttpServletResponse response) {\n" +
9393
" Cookie cookie = request.getCookies()[ueditor];\n" +
9494
" cookie.setHttpOnly(true); // 设置为 HttpOnly\n" +
9595
" cookie.setMaxAge(600); // 这里设置生效时间为十分钟\n" +
9696
" cookie.setPath(\"/\");\n" +
9797
" response.addCookie(cookie);\n" +
98-
" return R.ok(content);\n" +
98+
" return R.ok(payload);\n" +
9999
"}\n" +
100100
"\n" +
101101
"// 全局配置\n" +
@@ -120,9 +120,9 @@ const safe4HttpOnly = "// HttpOnly是HTTP响应头属性,用于增强Web应用
120120

121121
const vul1StoreRaw = "// 原生漏洞场景,未加任何过滤,将用户输入存储到数据库中\n" +
122122
"// Controller层\n" +
123-
"public R vul(String content,HttpServletRequest request) {\n" +
123+
"public R vul(String payload,HttpServletRequest request) {\n" +
124124
" String ua = request.getHeader(\"User-Agent\");\n" +
125-
" final int code = xssService.insertOne(content,ua);\n" +
125+
" final int code = xssService.insertOne(payload,ua);\n" +
126126
" ...\n" +
127127
"}\n" +
128128
"// Service层\n" +
@@ -203,11 +203,11 @@ const vul1OtherUpload = "public String uploadFile(MultipartFile file, String suf
203203
" }\n" +
204204
"}"
205205

206-
const vul2OtherTemplate = "public String handleTemplateInjection(String content,String type, Model model) {\n" +
206+
const vul2OtherTemplate = "public String handleTemplateInjection(String payload,String type, Model model) {\n" +
207207
" if (\"html\".equals(type)) {\n" +
208-
" model.addAttribute(\"html\", content);\n" +
208+
" model.addAttribute(\"html\", payload);\n" +
209209
" } else if (\"text\".equals(type)) {\n" +
210-
" model.addAttribute(\"text\", content);\n" +
210+
" model.addAttribute(\"text\", payload);\n" +
211211
" }\n" +
212212
" return \"vul/xss/other\";\n" +
213213
"}\n" +
@@ -1177,7 +1177,121 @@ const safeHorizon = "public R safe(String username){\n" +
11771177
"}"
11781178

11791179
// 支付漏洞
1180+
const vul1Pay = "public R vul1(@RequestParam String count, @RequestParam String price) {\n" +
1181+
" try {\n" +
1182+
" double totalPrice = Integer.parseInt(count) * Double.parseDouble(price);\n" +
1183+
" log.info(\"用户需支付金额:\" + totalPrice);\n" +
1184+
" \n" +
1185+
" // 直接使用客户端传入的价格,未与服务端商品实际价格进行校验\n" +
1186+
" BigDecimal currentMoney = userMoney.get();\n" +
1187+
" if (currentMoney.compareTo(BigDecimal.valueOf(totalPrice)) < 0) {\n" +
1188+
" return R.error(\"支付金额不足,支付失败!\");\n" +
1189+
" }\n" +
1190+
" userMoney.set(currentMoney.subtract(BigDecimal.valueOf(totalPrice)));\n" +
1191+
" return R.ok(\"支付成功!剩余余额:\" + userMoney.get());\n" +
1192+
" } catch (Exception e) {\n" +
1193+
" return R.error(e.toString());\n" +
1194+
" }\n" +
1195+
"}";
11801196

1197+
const vul2Pay = "public R vul2(@RequestParam String orderId, @RequestParam double amount) {\n" +
1198+
" // 未检查订单是否已支付\n" +
1199+
" // 这里应该使用paymentStatusMap检查订单是否已支付,但为了演示漏洞,故意不检查\n" +
1200+
" BigDecimal currentMoney = userMoney.get();\n" +
1201+
" if (currentMoney.compareTo(BigDecimal.valueOf(amount)) < 0) {\n" +
1202+
" return R.error(\"余额不足\");\n" +
1203+
" }\n" +
1204+
" userMoney.set(currentMoney.subtract(BigDecimal.valueOf(amount)));\n" +
1205+
" return R.ok(\"支付成功!剩余余额:\" + userMoney.get());\n" +
1206+
"}";
1207+
1208+
const vul3Pay = "public R vul3(@RequestParam String orderId, @RequestParam double amount) {\n" +
1209+
" // 模拟处理延迟\n" +
1210+
" try {\n" +
1211+
" Thread.sleep(1000);\n" +
1212+
" } catch (InterruptedException e) {\n" +
1213+
" Thread.currentThread().interrupt();\n" +
1214+
" }\n" +
1215+
"\n" +
1216+
" BigDecimal currentMoney = userMoney.get();\n" +
1217+
" if (currentMoney.compareTo(BigDecimal.valueOf(amount)) < 0) {\n" +
1218+
" return R.error(\"余额不足\");\n" +
1219+
" }\n" +
1220+
" userMoney.set(currentMoney.subtract(BigDecimal.valueOf(amount)));\n" +
1221+
" return R.ok(\"支付成功!剩余余额:\" + userMoney.get());\n" +
1222+
"}";
1223+
1224+
const vul4Pay = "@ApiOperation(\"支付流程绕过漏洞 - 创建订单\")\n" +
1225+
"@RequestMapping(\"/vul4/create\")\n" +
1226+
"public R createOrder(@RequestParam String orderId, @RequestParam double amount) {\n" +
1227+
" OrderStatus status = new OrderStatus(orderId, BigDecimal.valueOf(amount));\n" +
1228+
" orderStatusMap.put(orderId, status);\n" +
1229+
" Map<String, Object> data = new HashMap<>();\n" +
1230+
" data.put(\"orderId\", orderId);\n" +
1231+
" data.put(\"amount\", amount);\n" +
1232+
" return R.ok(\"订单创建成功\").put(\"data\", data);\n" +
1233+
"}\n" +
1234+
"\n" +
1235+
"@ApiOperation(\"支付流程绕过漏洞 - 查询订单状态\")\n" +
1236+
"@RequestMapping(\"/vul4/status\")\n" +
1237+
"public R getOrderStatus(@RequestParam String orderId) {\n" +
1238+
" OrderStatus status = orderStatusMap.get(orderId);\n" +
1239+
" if (status == null) {\n" +
1240+
" return R.error(\"订单不存在\");\n" +
1241+
" }\n" +
1242+
" Map<String, Object> data = new HashMap<>();\n" +
1243+
" data.put(\"orderId\", status.orderId);\n" +
1244+
" data.put(\"amount\", status.amount);\n" +
1245+
" data.put(\"isPaid\", status.isPaid);\n" +
1246+
" return R.ok().put(\"data\", data);\n" +
1247+
"}\n" +
1248+
"\n" +
1249+
"@ApiOperation(\"支付流程绕过漏洞 - 支付通知\")\n" +
1250+
"@RequestMapping(\"/vul4/notify\")\n" +
1251+
"public R paymentNotify(@RequestParam String orderId, @RequestParam boolean success) {\n" +
1252+
" // 未验证通知来源,直接更新订单状态\n" +
1253+
" OrderStatus status = orderStatusMap.get(orderId);\n" +
1254+
" if (status == null) {\n" +
1255+
" return R.error(\"订单不存在\");\n" +
1256+
" }\n" +
1257+
" status.isPaid = success;\n" +
1258+
" return R.ok(\"状态更新成功\");\n" +
1259+
"}";
1260+
const vul5Pay = "public R integerOverflow(@RequestParam String count, @RequestParam String price) {\n" +
1261+
" try {\n" +
1262+
" Integer countValue = Integer.valueOf(count);\n" +
1263+
" Integer priceValue = Integer.valueOf(price);\n" +
1264+
"\n" +
1265+
" // 整数溢出场景:当 count 或 price 数值过大时,可能会导致溢出\n" +
1266+
" int totalAmount = countValue * priceValue;\n" +
1267+
" log.info(\"用户需支付金额:\" + totalAmount);\n" +
1268+
"\n" +
1269+
" BigDecimal currentMoney = userMoney.get();\n" +
1270+
" if (currentMoney.compareTo(BigDecimal.valueOf(totalAmount)) < 0) {\n" +
1271+
" return R.error(\"支付金额不足,支付失败!\");\n" +
1272+
" }\n" +
1273+
" userMoney.set(currentMoney.subtract(BigDecimal.valueOf(totalAmount)));\n" +
1274+
" return R.ok(\"支付成功!剩余余额:\" + userMoney.get());\n" +
1275+
" } catch (Exception e) {\n" +
1276+
" return R.error(\"无效的输入,请输入有效的数量和价格!\");\n" +
1277+
" }\n" +
1278+
"}";
1279+
const vul6Pay = "public R floatingPointPrecision(@RequestParam String count, @RequestParam String price) {\n" +
1280+
" try {\n" +
1281+
" // 使用BigDecimal处理金额计算,避免浮点数精度问题\n" +
1282+
" BigDecimal amountValue = new BigDecimal(price).multiply(new BigDecimal(count));\n" +
1283+
" log.info(\"用户需支付金额:\" + amountValue);\n" +
1284+
"\n" +
1285+
" BigDecimal currentMoney = userMoney.get();\n" +
1286+
" if (currentMoney.compareTo(amountValue) < 0) {\n" +
1287+
" return R.error(\"支付金额不足,支付失败!\");\n" +
1288+
" }\n" +
1289+
" userMoney.set(currentMoney.subtract(amountValue));\n" +
1290+
" return R.ok(\"支付成功!剩余余额:\" + userMoney.get());\n" +
1291+
" } catch (Exception e) {\n" +
1292+
" return R.error(\"无效的输入,请输入有效的数量和价格!\");\n" +
1293+
" }\n" +
1294+
"}";
11811295

11821296
// 其他漏洞
11831297
const vul1SpringMvcRedirect = "// 基于Spring MVC的重定向方式\n" +
@@ -1766,6 +1880,11 @@ const vul2Reverse = "const publicKey = `-----BEGIN PUBLIC KEY-----\n" +
17661880
"{\"encryptedUsername\":\"iDF5BNv1zaM0V9qog0qzlUES3sCGYqmvrKiqPIvUgP5qE0pYn9XN3btW3PbRwLuySeruK2i8lem+L67w5+fFQBuRrpettLrHl8izIRp2W+nq9o9Kg/LSa3/+JynFoUHxrvQ2taNM1nustROpkBjJMbTOK52S6ZBa0quMw+wjfR1XExlzc99U1WJQfRAqj7Gsl9EPydRIh8vs4S/Nen5kf/dL3ZikfMbCUUBonRlYy6a3nWJ412P+hxRbSl80Z8aQKw9lH4+Iju80oFmQ6DuS6Ce70h88z/Va+xzXHDzM8w6h5iqQLzq3Kj/E+b/wsn6eM7v+LEC8LwLQ/t8z8tki9g==\",\n" +
17671881
"\"encryptedPassword\":\"nDI0/PBwsFHnRRw7Z4gHZ6G8Uaq7BUjUxnTDw7bkR9nrTkoHfcDLKUddj2JS7WWbOyuwsUFce3/tXJYQWNMFQqGRtf6jXxFAlvTvBkRdsZXOIU+Abb4EqYw670xd5UTeAQ0lI5KNXtw6e/VbnXyX+STJdN2SO7FLbvZ4sM6gLQSVWLo/+pZsYxKlEUNxew2svlzDZtqKnyF12bzakWfzaWuovLnYCCEXV1oAJCErjgfoOS2wJADdgU0wE6KlFDMNjsCvONmO6KZpmJQ1GOq3MpyqySq8eyJkYG3cDSRo5nDo2YOcevOHifzMnKbrU9gh4/RUj8sxrykdqgLmzX3rhw==\"}"
17681882

1883+
const vul1Credential = "vul1Credential"
1884+
1885+
const vul2Credential = "vul2Credential"
1886+
1887+
17691888
// java专题 SPEL注入
17701889
const spelVul = "public R vul(String ex) {\n" +
17711890
" // 创建SpEL解析器,ExpressionParser接口用于表示解析器,SpelExpressionParser为默认实现\n" +
@@ -2075,3 +2194,21 @@ const vulShiro = "public R getShiroKey(){\n" +
20752194
" <artifactId>shiro-spring</artifactId>\n" +
20762195
" <version>1.2.4</version>\n" +
20772196
"</dependency>"
2197+
const JdbcDeserial = "public R vul() {\n" +
2198+
" ...\n" +
2199+
" Connection conn = DriverManager.getConnection(url, username, password);\n" +
2200+
" String selectQuery = \"SELECT malicious_object FROM objects WHERE id = 1\";\n" +
2201+
" Statement stmt = conn.createStatement();\n" +
2202+
" ResultSet rs = stmt.executeQuery(selectQuery);\n" +
2203+
"\n" +
2204+
" if (rs.next()) {\n" +
2205+
" // 查询并获取恶意对象的字节数据\n" +
2206+
" byte[] maliciousObjectBytes = rs.getBytes(\"malicious_object\");\n" +
2207+
" // 反序列化恶意对象\n" +
2208+
" ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(maliciousObjectBytes);\n" +
2209+
" ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);\n" +
2210+
"\n" +
2211+
" // 触发反序列化漏洞\n" +
2212+
" MaliciousObject maliciousObject = (MaliciousObject) objectInputStream.readObject();\n" +
2213+
" }\n" +
2214+
" ..."

src/main/resources/templates/vul/logic/pay/pay.html

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -471,19 +471,16 @@ <h1><span class="iconfont icon-code"> 缺陷代码</span></h1>
471471

472472
// 模拟并发请求
473473
for (var i = 0; i < requestCount; i++) {
474-
// 添加一个随机参数,避免浏览器缓存
475474
var requestData = Object.assign({}, data.field, {_t: new Date().getTime() + i});
476475

477476
$.ajax({
478477
url: '/logic/pay/vul3',
479478
type: 'post',
480479
data: requestData,
481480
success: function(res) {
482-
// 将每个请求的结果添加到结果区域
483-
$("#vul3-pay-result").append("<p>请求 #" + (++completedCount) + " 结果: " +
481+
$("#vul3-pay-result").append("<p>请求 #" + (++completedCount) + " 结果: " +
484482
(res.code === 0 ? "成功 - " + res.msg : "失败 - " + res.msg) + "</p>");
485483

486-
// 所有请求完成后关闭加载提示
487484
if (completedCount >= requestCount) {
488485
layer.close(loadingMsg);
489486
}
@@ -569,25 +566,6 @@ <h1><span class="iconfont icon-code"> 缺陷代码</span></h1>
569566

570567
});
571568

572-
$('.shiro').hover(function () {
573-
$(this).css('cursor', 'pointer');
574-
layer.tips('RememberMe序列化过程', this, {
575-
tips: [1, '#0051ff'],
576-
time: 2000
577-
});
578-
});
579-
580-
$('.shiro').on('click', function () {
581-
layer.open({
582-
type: 1,
583-
title: false,
584-
closeBtn: 1,
585-
area: ['975px', '672px'], // 宽高缩小为0.9倍
586-
shadeClose: true,
587-
content: '<div style="text-align: center;"><img src="/static/images/vul/components/shiro.png" style="width: 100%; height: 100%;"></div>'
588-
});
589-
});
590-
591569

592570
});
593571
</script>

0 commit comments

Comments
 (0)