系统设计-文本内容保存之XSS过滤
创始人
2024-02-16 12:37:57

点击上方名片关注我,为你带来更多踩坑案例

afda49b670c8d62491b0c0094eb499d5.png

- 引言 -

    如果你是一个摸爬滚打几年的开发者,那么这个阶段,对系统设计的合理性绝对是衡量一个人水平的重要标准。

    一个好的设计不光能让你工作中避免很多麻烦,还能为你面试的时候增加很多谈资

    而且,不同设计之间理念都是有借鉴性参考性的,你见过的设计多了,思考的多了,再次面临一个问题的时候,就会有很多点子不由自主的冒出来。

    希望这个系列的文章,能够和大家互相借鉴参考,共同进步。

- XSS攻击 -

    XSS跨站脚本攻击(Cross Site Scripting)攻击就是指在网页中通过一些巧妙的方式,注入一些恶意的可执行代码片段等,来非法攻击网站

    XSS攻击的方式有很多很多,需要我们在开发环节中的每一个步骤都注意

    本文主要介绍一种防止XSS攻击的方法,也是普适性比较高,大家比较容易忽略的一点---服务端保存前端传来的参数,特别是字符串类型的参数,要秉持着不信任的原则,防止把跨站脚本持久化到数据库中

- XSS过滤 -

    方法就是在接收参数前,对参数中的String类型的字段做一个筛查,大致思路分为三步:

    1.拦截到参数--使用过滤器

    2.将参数中的Srting字段拆出来---通过类型判断和遍历,因为有些参数的格式可能会略复杂

    3.将String类型的字段做统一替换---可以使用一些现成的正则替换工具

    好了,思路就是上面的三步,下面直接贴代码

    首先定义我们的过滤器

public class XssFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;XssHttpRequestWrapper requestWrapper = new XssHttpRequestWrapper(request);filterChain.doFilter(requestWrapper, servletResponse);}@Overridepublic void destroy() {}
}

    然后注册我们的过滤器

@Configuration
public class XSSFilterRegister {@Beanpublic FilterRegistrationBean registerXss() {//通过FilterRegistrationBean实例设置优先级可以生效FilterRegistrationBean bean = new FilterRegistrationBean<>();//注册自定义过滤器bean.setFilter(new XssFilter());//过滤器名称bean.setName("xssFilter");//过滤所有路径bean.addUrlPatterns("/*");return bean;}
}

    最后写过滤器具体要做的事

public class XssHttpRequestWrapper extends HttpServletRequestWrapper {public XssHttpRequestWrapper(HttpServletRequest request) {super(request);}@Overridepublic String getParameter(String name) {String value = super.getParameter(name);if (!StringUtils.isEmpty(value)) {value = HtmlUtil.filter(value);}return value;}@Overridepublic String[] getParameterValues(String name) {String[] values = super.getParameterValues(name);if (values != null) {for (int i = 0; i < values.length; i++) {String value = values[i];if (!StringUtils.isEmpty(value)) {value = HtmlUtil.filter(value);}values[i] = value;}}return values;}@Overridepublic Map getParameterMap() {Map parameters = super.getParameterMap();Map map = new LinkedHashMap<>();if (parameters != null) {for (String key : parameters.keySet()) {String[] values = parameters.get(key);for (int i = 0; i < values.length; i++) {String value = values[i];if (!StringUtils.isEmpty(value)) {value = HtmlUtil.filter(value);}values[i] = value;}map.put(key, values);}}return map;}@Overridepublic String getHeader(String name) {String value = super.getHeader(name);if (!StringUtils.isEmpty(value)) {value = HtmlUtil.filter(value);}return value;}@Overridepublic ServletInputStream getInputStream() throws IOException {InputStream in = super.getInputStream();InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8);BufferedReader buffer = new BufferedReader(reader);StringBuilder body = new StringBuilder();String line = buffer.readLine();while (line != null) {body.append(line);line = buffer.readLine();}buffer.close();reader.close();in.close();Map map = new HashMap<>();String json = "";try {if (body.toString().startsWith("[")) {JSONArray jsonArray = JSONUtil.parseArray(body.toString());JSONArray newArray = new JSONArray();for (Object object : jsonArray) {if (object instanceof Integer) {json = jsonArray.toString();break;} else if (object instanceof Long) {json = jsonArray.toString();break;} else {map = (JSONObject) object;Map result = new LinkedHashMap<>();for (String key : map.keySet()) {filter(result, key, map.get(key));}newArray.add(result);}}if (newArray.size() != 0) {json = newArray.toString();}} else if (body.toString().startsWith("{")) {map = JSONUtil.parseObj(body.toString());if (!map.isEmpty()) {Map result = new LinkedHashMap<>();for (String key : map.keySet()) {filter(result, key, map.get(key));}json = JSONUtil.toJsonStr(result);}}} catch (Exception e1) {throw new ParamException(e1);}ByteArrayInputStream bain = new ByteArrayInputStream(json.getBytes());return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {}@Overridepublic int read() {return bain.read();}};}private static void filter(Map result, String key, Object val) {if (val instanceof String) {// 字符串直接替换result.put(key, HtmlUtil.filter(val.toString()));} else if (val instanceof JSONObject) {// JSONObject遍历JSONObject valObj = new JSONObject(val);JSONObject newObj = new JSONObject();for (String keyObj : valObj.keySet()) {if (valObj.get(keyObj) instanceof String && !StringUtils.isEmpty(valObj.get(keyObj).toString())) {newObj.set(keyObj, HtmlUtil.filter(valObj.get(keyObj).toString()));} else {newObj.set(keyObj, valObj.get(keyObj));}}result.put(key, newObj);} else if (val instanceof JSONArray) {// JSONArray遍历JSONArray valArray = new JSONArray(val);JSONArray newArray = new JSONArray();for (Object o : valArray) {if (o instanceof JSONObject) {JSONObject valObj = (JSONObject) o;JSONObject newObj = new JSONObject();for (String keyObj : valObj.keySet()) {if (valObj.get(keyObj) instanceof String && !StringUtils.isEmpty(valObj.get(keyObj).toString())) {newObj.set(keyObj, HtmlUtil.filter(valObj.get(keyObj).toString()));} else {newObj.set(keyObj, valObj.get(keyObj));}}newArray.put(newObj);} else {newArray.put(o);}}result.put(key, newArray);} else {// 其他类型字段不做替换result.put(key, val);}}
}

    其中的一些类大家可以做自行替换,比如正则过滤的工具类我使用的是hutool的工具包HtmlUtil,大家也可以根据业务场景的不同用别的或者自定义。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...