工作踩坑之特殊的空格- 

64 阅读4分钟

噩梦始于XSS注入修订

在之前的工作中,公司出于安全合规考虑,需要全局盘点页面进行XSS注入的修订。

这是一套有点年纪并且混合着vue和jQuery的代码,便采用了最常见的转义方式来进行修订。

encodeHtml : function(str) {
    if (!UtilisString(str)) {
        return str;
    }
    var s = "";
    if (str. length == 0) return "";
    s = str. replace(/&/g"&");
    s = s. replace(/</g"&lt;");
    s = s. replace(/>/g"&gt;");
    s = s. replace(/ /g"&nbsp;"); //这里就是万恶的开始
    s = s. replace(/\'/g"&#39;");
    s = s. replace(/\"/g"&quot;");
    s = s. replace(/\n/g"<br>");
    return s;
},
        
uncodeHtml : function(str) {
    if (!UtilisString(str)) {
        return str;
    }
    var s = "";
    if (str. length == 0) return "";
    s = str. replace(/&amp;/g"&");
    s = s. replace(/&lt;/g"<");
    s = s. replace(/&gt;/g">");
    s = s. replace(/&nbsp;/g" ");
    s = s. replace(/'/g"\'");
    s = s. replace(/&quot;/g"\""); 
    return s;
},

但是随着XSS修订完成后没多久,莫名其妙的bug却突然接踵而至:当配置的名称包含空格时,采用这个名称的部分信息界面会出现报错,无法获取该名称的相关信息。

image.png

深入探究

明明使用的是一样的接口啊,怎会出现一个报错,另一个不报错的现象?

通过对比两个接口传递的参数,点击查看网址编码格式的数据:

1702787284320.jpg

1702787286386.jpg

可以很明显地发现,正常的接口,其载荷的名称 是name:33+3 ,而 + 就是空格的意思,所以其传递的名称就是正常的 33 3

反观错误的接口,其载荷的名称是奇怪的 name:33%C2%A03 ,奇怪,%C2%A0是什么?为什么空格会变成这串东西?

通过 UTF-8编码表 比对,我们可以得知 %C2%A0C2=194 A0=160 ,这个在编码表中对应的是:

GF)G~BO3}GBYXNGQ8DMOI.png

啊哈!NO-BREAK SPACE,正是 SPACE 那前面一串的修饰,注定使他成为了特殊的存在,和那些平平无奇的普通空格不是一类!

image.png

特殊的空格-&nbsp;

根据描述,这是一种十分特殊的空格。

众所周知,在页面的元素中,一旦你输入了多个空格,那么页面会自动压缩显示成只有一个空格的样子。

如果有人玩的比较花,就是不想缩在一起,那么&nbsp;就派上用场了~

任何时间,任何地点,&nbsp;(认真办案) 绝不压缩!

所以,之所以接口错误,拿不到该名称的相关信息,就是因为他所拿到的名称里,普通的空格早已变成了特殊的 &nbsp;空格 !

恶心的代码,无奈的码农

那为什么,普普通通的、包含空格的名称,经页面一转手,就变成了特殊的空格呢?

来仔细看看代码探究一下吧:

细细品味前人的代码,让人五味杂陈。

1702786071171.jpg

明明都用vue重构了,为什么还要用jQuery来绑定点击事件?

明明都用vue重构了,为什么还要用$(this).text()来获取该名称?

正是着一串莫名其妙让人懵逼的代码,在经过之前的XSS注入修订转义,原本普普通通老老实实的空格一秒提升逼格,成为了不老实,不压缩的特殊空格—— &nbsp;

着手修订吧!

至于修订方法也十分简单,不要传递这种特殊的空格即可,但是我还是无法忍受这种写法,最终使用@click来直接传递该行数据的信息解决。

1702786073672.jpg

但是,根据旧有的代码分析,我发现了新的BUG,通过url来传递信息(好老的代码啊!),在解析数据时通过 & 符号来分割,如果我配置了包含 & 符号的名称,那不是也得挂掉?(永远都修不完的BUG啊!)🤮🤮

太长了不想看?来看看总结

根据上述一连串的分析,最终可以确定,之前的XSS修订的转义,使得从页面DOM元素直接获取的名称,其名中的普通的空格(UTF8对应32)变成了特殊的空格&nbsp;(UTF8对应194 160,即C2 A0),而这特殊的空格通过接口传递给设备,导致设备不识别该空格而找不到相关的信息,导致接口错误。

1702786076487.jpg