项目安全问题及解决方法-----xss处理

XSS 问题的根源在于,原本是让用户传入或输入正常数据的地方,被黑客替换为了 JavaScript 脚本,页面没有经过转义直接显示了这个数据,然后脚本就被 执行了。更严重的是,脚本没有经过转义就保存到了数据库中,随后页面加载数据的时候,数据中混入的脚本又当做代码执行了。黑客可以利用这个漏洞 来盗取敏感数据,诱骗用户访问钓鱼网站等。


@RequestMapping("xss")
@Slf4j
@Controller
public class XssController {@Autowiredprivate UserRepository userRepository;//显示xss页面@GetMappingpublic String index(ModelMap modelMap) {//查数据库User user = userRepository.findById(1L).orElse(new User());//给View提供ModelmodelMap.addAttribute("username", user.getName());return "xss";}//保存用户信息@PostMappingpublic String save(@RequestParam("username") String username, HttpServletRequest request) {User user = new User();user.setId(1L);user.setName(username);userRepository.save(user);//保存完成后重定向到首页return "redirect:/xss/";}
}
//用户类,同时作为DTO和Entity
@Entity
@Data
public class User {@Idprivate Long id;private String name;
}

使用Thymeleaf 模板引擎来渲染页面

<div style="font-size: 14px"><form id="myForm" method="post" th:action="@{/xss/}"><label th:utext="${username}"/> <!--对于 Thymeleaf 模板引擎,需要注意的是,使用 th:utext 来显示数据是不会进行转义的,需要使用 th:text--><input id="username" name="username" size="100" type="text"/><button th:text="Register" type="submit"/></form>
</div>

 

解决方法可以使用 HTML 转码。既然是通过 @RequestParam 来获取请求参数,那我们定义一个 @InitBinder 实现数据绑定的时候,对字符串进行转码即 可。

@ControllerAdvice
public class SecurityAdvice {@InitBinderprotected void initBinder(WebDataBinder binder) {//注册自定义的绑定器binder.registerCustomEditor(String.class, new PropertyEditorSupport() {@Overridepublic String getAsText() {Object value = getValue();return value != null ? value.toString() : "";}@Overridepublic void setAsText(String text) {//赋值时进行HTML转义setValue(text == null ? null : HtmlUtils.htmlEscape(text));}});}
}

 

但是解决问题的方式不全面,@InitBinder 是 Spring Web 层面的处理逻辑,如果有代码不通过 @RequestParam 来获取数据,而是直接从 HTTP 请求 获取数据的话,这种方式就不会奏效。比如: user.setName(request.getParameter("username")); 最好的解决方式是,定义一个 servlet Filter,通过 HttpServletRequestWrapper 实现 servlet 层面的统一参数替换。

//自定义过滤器
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class XssFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletExceptio n {chain.doFilter(new XssRequestWrapper((HttpServletRequest) request), response);}
}
public class XssRequestWrapper extends HttpServletRequestWrapper {public XssRequestWrapper(HttpServletRequest request) {super(request);}@Overridepublic String[] getParameterValues(String parameter) {//获取多个参数值的时候对所有参数值应用clean方法逐一清洁return Arrays.stream(super.getParameterValues(parameter)).map(this::clean).toArray(String[]::new);}@Overridepublic String getHeader(String name) {//同样清洁请求头return clean(super.getHeader(name));}@Overridepublic String getParameter(String parameter) {//获取参数单一值也要处理return clean(super.getParameter(parameter));}//clean方法就是对值进行HTML转义private String clean(String value) {return StringUtils.isEmpty(value)? "" : HtmlUtils.htmlEscape(value);}} 

这种方式还是不够彻底,原因是无法处理通过 @RequestBody 注解提交的 JSON 数据。比如,有这样一个 PUT 接口,直接保存了客户端传入的 JSON User 对 象

@PutMapping
public void put(@RequestBody User user) {userRepository.save(user);
}

 

因此我们需要自定义一个json的反序列器进行处理:

    //注册自定义的Jackson反序列器@Beanpublic Module xssModule() {SimpleModule module = new SimpleModule();module.module.addDeserializer(String.class, new XssJsonDeserializer());return module;}
public class XssJsonDeserializer extends JsonDeserializer<String> {@Overridepublic String deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {String value = jsonParser.getValueAsString();if (value != null) {//对于值进行HTML转义return HtmlUtils.htmlEscape(value);}return value;}@Overridepublic Class<String> handledType() {return String.class;}
}

 这样就实现了既能转义 Get/Post 通过请求参数提交的数据,又能转义请求体中直接提交的 JSON 数据。但是目前这种只能堵新漏,确保新数据进入数据 库之前转义。如果因为之前的漏洞,数据库中已经保存了一些 JavaScript 代码,那么读取的时候同样可能出问题。因此,我们还要实现数据读取的时候也 转义。

@GetMapping("user")
@ResponseBody
public User query() {return userRepository.findById(1L).orElse(new User());
}

 

修改之前的 SimpleModule 加入自定义序列化器,并且实现序列化时处理字符串转义

    //注册自定义的Jackson序列器@Beanpublic Module xssModule() {SimpleModule module = new SimpleModule();module.addDeserializer(String.class, new XssJsonDeserializer());module.addSerializer(String.class, new XssJsonSerializer());return module;}
public class XssJsonSerializer extends JsonSerializer<String> {@Overridepublic Class<String> handledType() {return String.class;}@Overridepublic void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {if (value != null) {//对字符串进行HTML转义jsonGenerator.writeString(HtmlUtils.htmlEscape(value));}}
}

 

还要考虑一种情况:如果需要在 Cookie 中写入敏感信息的话,我们可以开启 HttpOnly 属性。这样 JavaScript 代码就无法读取 Cookie 了,即便页面被 XSS 注 入了攻击代码,也无法获得我们的 Cookie。

//服务端读取Cookie
@GetMapping("readCookie")
@ResponseBody
public String readCookie(@CookieValue("test") String cookieValue) {return cookieValue;
}
//服务端写入Cookie
@GetMapping("writeCookie")
@ResponseBody
public void writeCookie(@RequestParam("httpOnly") boolean httpOnly, HttpServletResponse response) {Cookie cookie = new Cookie("test", "zhuye");//根据httpOnly入参决定是否开启HttpOnly属性cookie.setHttpOnly(httpOnly);response.addCookie(cookie);
}

 由于 test 和 _ga 这两个 Cookie 不是 HttpOnly 的。通过 document.cookie 可以输出这两个 Cookie 的内容:

为 test 这个 Cookie 启用了 HttpOnly 属性后,就不能被 document.cookie 读取到了,输出中只有 _ga 一项:

 

 但是服务端可以读取到这个 cookie:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/667211.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】实现顺序表

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解顺序表&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一.概念及结构二.接口实现2.1 创建顺序表结构体2.2 初始化顺序表2.3 销毁顺序表2.4 打印顺序表…

Unity 设置鼠标

目录 前言 图标样式的设置 代码控制 编辑器直接修改 图标的显隐 CursorLockMode Cursor.visible 前言 本章主要对鼠标图标样式还有鼠标显隐进行设置 图标样式的设置 代码控制 有时候需要有改变鼠标样式的需求可以使用如下代码 Cursor.SetCursor(this.mouseTexture, Vec…

[word] 怎么删除文字底纹 #职场发展#其他

怎么删除文字底纹 怎么删除文字底纹?我们在录入文字到文档的时候&#xff0c;或者是复制网上内容时&#xff0c;都会带有格式&#xff0c;有时候还会遇到删除不掉的问题。今天给大家分享小技巧&#xff0c;解决你的问题。 1、删除文字底纹 文档自带的底纹&#xff0c;删除技…

C++实现智能指针(涉及知识点:重载运算符,内存泄露的风险)

案例 有时候代码很长&#xff0c;很容易就忘了释放P。导致内存泄露&#xff0c;在程序结束后才会释放。内存泄露的风险 如果代码需要的内存很大&#xff0c;前面的代码用完了new申请的内容不去释放&#xff0c;就会被一直占用着&#xff0c;后面可能不够用了造成程序崩溃。解决…

linux文件权限备份、恢复-linux文件权限如何备份、恢复-getfacl/setfacl备份恢复文件权限

0、序 在运维这条路上走久了&#xff0c;你能听到或者遇到这样的事情就越多&#xff0c;甚至是你自己干过的&#xff1a; 一个信心满满的运维人员一个不小心&#xff0c;输入 "chmod -R 777 /" 导致一个巨大的悲剧&#xff0c;然后整个部门从上到下被撸一顿。虽然…

牛客周赛 Round 31

D. 思路&#xff1a;使用map构造两个链表。 #include <bits/stdc.h> using namespace std;map<int,int> l,r; int main() {int q;cin>>q;int op-1e9-1;int ed1e91;r[op]ed;l[ed]op;while(q--){int a;cin>>a;if(a1){int x,y;cin>>x>>y;int…

MIT6.5830 实验3

前置回顾 在实验2中&#xff0c;完成了增删查改、排序、分组、聚合、连接等基本操作&#xff0c;在已提供 sql 解析器的基础上&#xff0c;能够运行进本的 sql 语句。都是逻辑层的实现&#xff0c;没有涉及物理存储方面的内容。 实验目标 实现最简单的基于锁的transaction&am…

MicroPython ESP32开发:通过寄存器直接访问外围设备

可以通过直接读写寄存器来控制 ESP32 的外设。这就需要阅读数据手册&#xff0c;了解要使用哪些寄存器以及要写入哪些值。下面的示例展示了如何打开和更改 MCPWM0 外设的预分频器。 from micropython import const from machine import mem32# Define the register addresses …

【STM32+HAL库+CubeMX】UART轮询收发、中断收发、DMA收发方法及空闲中断详解

&#xff08;转载&#xff09;原文链接&#xff1a;https://blog.csdn.net/qq_39344192/article/details/131470735 1. 什么是UART&#xff1f; UART是一种异步串行通信接口&#xff0c;常用于通过串口与外部设备进行通信。它通过发送和接收数据帧来实现数据传输&#xff0c;使…

postman 文档、导出json脚本 导出响应数据 response ,showdoc导入postman json脚本 导出为文档word或markdown

保存、补全尽可能多的数据、描述 保存响应数据 Response&#xff1a;&#xff08;如果导出接口数据&#xff0c;会同步导出响应数据&#xff09; 请求接口后&#xff0c;点击下方 Save as Example 可以保存响应数据到本地&#xff08;会在左侧接口下新增一个e.g. 文件用来保…

使用_NT_SYMBOL_PATH在启动VS前设置PDB路径

一、背景 由于公司相关项目的开发管理方式&#xff0c;导致公司会存在多个分支的版本正在开发/测试中。 在这样的背景下&#xff0c;我的日常工作中有时会出现存在某个分支的项目软件的某个功能出现了问题需要我去排查解决&#xff0c;而我当前并不在该分支上开发。于是只能安装…

C++泛编程(3)

类模板基础 1.类模板的基本概念2.类模板的分文件编写3.类模板的嵌套 &#xff08;未完待续...&#xff09; 在往节内容中&#xff0c;我们详细介绍了函数模板&#xff0c;这节开始我们就来聊一聊类模板。C中&#xff0c;类的细节远比函数多&#xff0c;所以这个专题也会更复杂。…

Llama2大模型开源,大模型的Android时代来了?

就昨天凌晨,微软和Meta宣布Llama2大模型开源且进一步放开商用,一下朋友圈刷屏。要知道,开源界最强大的模型就是过去Meta开源的Llama,而现在Llama2更强大,又开放商用,更有微软大模型霸主企业撑腰(微软既投资大模型界的IOS——ChatGPT,又联合发布大模型的Android——Llam…

【2月比赛合集】28场可报名的数据挖掘大奖赛,任君挑选!

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 Kaggle&#xff08;2场比赛&#xff09;阿里天池&#xff08;…

数据库学习笔记2024/2/4

随笔 1. 为什么学? 认识数据,熟悉数据,掌握数据。 进企业必备技能。 2. 怎么学? 1、MySQL数据库就是存储和管理数据的一个大型软件,这个软件有一个专门的语言叫SQL,主要学的是SQL语言,但想要达到企业用人标准,就还得学会熟练使用MySQL这个软件。 2、学习分三阶段: 一. …

微信小程序课设(基于云开发)

微信小程序通过Laf云平台接入ChatGPT实现聊天&#xff0c;回答方式采用流式回答。 以下是图片展示其页面 回答次数通过卡密兑换 以下是对话页面的代码 <!--pages/content/content.wxml--><view class"container"><view class"div" hidde…

软件测试学习笔记-使用jmeter进行接口测试

使用jmeter之前首先需要安装jdk&#xff0c;配置其环境变量&#xff0c;然后再安装jmeter 软件测试学习笔记-使用jmeter进行接口测试 1. 断言1. 响应断言2. JSON断言 2. 参数化1. 用户定义的变量2. CSV参数化 3. 接口关联4. 连接数据库 1. 断言 对某个接口其中一些信息进行判断…

DiskGenius v4.30专业版下载

DiskGenius是一款专业级的数据恢复软件&#xff0c;算法精湛、功能强大&#xff0c;用户群体广泛&#xff1b;支持各种情况下的文件恢复和分区恢复&#xff0c;恢复效果好&#xff1b;文件预览、扇区编辑、加密分区恢复、Ext4分区恢复、RAID恢复等高级功能应有尽有&#xff0c;…

Vue3+TS+Vite+Pinia最全学习总结

VUE3介绍 vue2和vue3之间的区别 因为需要遍历data对象上所有属性&#xff0c;所以如果data对象属性结构嵌套很深&#xff0c;就会存在性能问题。因为需要遍历属性&#xff0c;所有需要提前知道对象上有哪些属性&#xff0c;才能将其转化为getter和setter,所以vue2中无法将data新…

一起畅玩!幻兽帕鲁服务器1分钟开服,不服来战!

玩转幻兽帕鲁服务器&#xff0c;阿里云推出新手0基础一键部署幻兽帕鲁服务器教程&#xff0c;傻瓜式一键部署&#xff0c;3分钟即可成功创建一台Palworld专属服务器&#xff0c;成本仅需26元&#xff0c;阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…