昆明前端开发中的字符编码

前端开发过程中会接触各种各样的编码,比较常见的主要是UTF-8和HTML实体编码,但是web前端的世界却不止这两种编码,而且编码的选择也会造成一定的问题,如前后端开发过程中不同编码的兼容、多字节编码可能会造成的XSS漏洞等。因此,本文旨在更好的全面了解涉及前端开发领域的字符编码,避免可能出现的交互和开发中的忽视的漏洞。

URL编码

我曾经在URL编码解码和base64一文中讲述了URL编码中的三组函数,并对比了这三组函数与base64编码的关系,在此简要说明一下。

escape/unescape函数针对宽字符做unicode编码,并针对码值做十六进制编码,所以使用escape针对汉字编码会得到形如uxxxx的结果;encodeURI/decodeURI,encodeURIComponent/decodeURIComponent函数针对宽字节编码却不同于escape,首先针对宽字节字符进行UTF-8编码,然后针对编码后的结果进行%替换,得到结果。以上所述都是针对宽字节字符而言,对于编码靠前的ASCII字符而言,上述三组函数的安全字符的范围也有所不同,具体可在上文中了解。

base64编码

base64编码在前端通常用于图片和icon的编码,它将每3个8位字节为一组,分成4组6位字节,并且每个字节的高位补零,形成4个8位的字节,由此可看出base64编码是可逆推的。在大多数浏览器中,提供了ASCII字符的base64编码函数,即window.btoa()。该函数无法针对宽字节进行base64编码,若针对中文编码,则需现转换位UTF-8编码,然后进行base64编码。

function unicodeToBase64(s){ return window.btoa(unescape(encodeURIComponent(s))) }

通过encodeURIComponent对宽字节字符编码,是%xx形式的编码,与UTF8编码的区别仅在于前缀(这是由规范RFC3986决定的,将非ASC字符进行某种形式编码,并转换为16进制,并在字节前加上%)。因此通过unescape(encodeURIComponent(s))可以转化为UTF8字节。当然,也可自己写一个转换函数,按照一定规则便行为UTF-8编码的字节,如下例:

unescape(encodeURIComponent("中国")) //结果:"中国"

encodeURIComponent("中国") //结果:"%E4%B8%AD%E5%9B%BD"

console.log("u00E4u00B8u00ADu00E5u009Bu00BD") // 结果: "中国"

通过简单的replace函数,就可以完成URL编码到UTF8编码的转换,进而完成宽字节字符到base64编码的转换。有了这个函数,我们手动生成一些data URI形式的内容,只需制定MIME类型和编码方式,就可以实现文本的转换,如以下代码:

<a href="data:text/html;charset=utf-8;base64,PHNjcmlwdD5hbGVydCgxMik8L3NjcmlwdD4=" >abc</a>

// 未编码前:<a href="javascript: alert(1)">test</a>

前端UTF8编码与后端GBK编码的兼容

目前前端大都采用UTF8进行编码,不管是html、js抑或是css,而后端则由于历史原因大都采用GBK或GB2312进行解码,因此前端通过parameter传递的URL编码的字符串就不可能直接在后台进行解码,为了更好的兼容性,前端可进行两次URL编码,即encodeURIComponent(encodeURIComponent(中国)),这样后端接收到参数后,先使用GBK或GB2312解码,得到了UTF8编码后再使用UTF8解码即可。两次编码主要是利用ASC字符使用GBK或GB2312编码不变的特点完成,富有技巧。

HTML实体编码与进制编码

实体编码针对HTML的预留字符而言,如等。实体编码有两种形式&实体名;或&entity_number;,由于浏览器对&实体名;的兼容性有差别,因此最好采用实体号的形式编码。

进制编码,顾名思义将ASC字符对应的码值按照十六进制或十进制编码,并转化为(16进制)或D;(10进制)形式。

单单针对实体编码而言并没有什么特殊强调的点,之所以把它单独列为一个章节,意在强调这两种编码与js代码的作用域的关系。

<div onclick="document.write('<img src=1 onerror=alert(23)>')">cccc</div>

 <div onclick="document.write('&lt;img src=1 onerror=alert(23)&gt;')">cccc</div>

 <img src=1 onerror=alert(23)>

 <img src=1 onerror=alert(23)>

<script>

document.write('&lt;img src=1 onerror=alert(23)&gt;');

document.write('<img src=1 onerror=alert(3)>')

 document.write('<img src=1 onerror=alert(23)>')

document.write('\u003c\u0069\u006d\u0067\u0020\u0073\u0072\u0063\u003d\u0031\u0020\u006f\u006e\u0065\u0072\u0072\u006f\u0072\u003d\u0061\u006c\u0065\u0072\u0074\u0028\u0032\u0033\u0029\u003e')

 </script>

代码中列举了8个例子,第一个在事件处理函数onclick中输出HTML片段;第二个则输出经实体编码后的HTML片段;第三个则是直接针对<img src=1 onerror=alert(23)>做16进制编码;第四个则是针对onerror事件处理函数做16进制编码;第五个则是在脚本中输出实体编码的字符;第六个针对事件处理函数做16进制编码;第七个则针对所有的字符做16进制编码;第八个则是在script中直接输出<img src=1 onerror=alert(23)>的unicode编码。

对比结果,前两个例子在点击后都会弹出alert;第三个例子则在页面中显示文本<img src=1 onerror=alert(23)>;第四个例子则会在页面加载初期弹出alert;第五、七会输出字符串;第六、八则会在第四个例子中的alert之后也弹出alert。现在分析这些结果,通过第一二个例子可知道,HTML标签中(除script标签)的内联js代码可以进行HTML实体编码,这是非常重要的一点,我们可以更为明确的进行验证:

<div onclick="alert('&lt;img src=1 onerror=alert(23)&gt;')">cccc</div>

输出的结果自然是<img src=1 onerror=alert(23)>,这的确论证了我们上文提到的这一点;第三个例子说明了HTML解析器在进行词法分析前,首先进行解码,十六进制和十进制皆可,因此,结果自然输出形如<img src=1 onerror=alert(23)>的字符串;第四个例子则紧接着论证了内联在HTML的并采用十六进制编码的js代码同样会被正确解析并执行,这说明了进制编码同样可被HTML解析器解析;第五、七个例子说明在js中同样可以使用实体编码和进制编码,解析的结果会渲染在页面上;第六个例子则论证了上一观点,只针对事件处理函数做进制编码,执行后页面弹出alert;第八个例子则是在js中执行unicode编码的字符串,正常alert。

由此可见,js代码内联在HTML的非script标签内,则会遵守HTML编码规范:进制编码和实体编码;而在js代码(script标签内以及js文件内)中,则遵从js编码:1,unicode形式编码(\uxxxx)2,普通的16进制编码(\xH),这可通过第八个例子得到证明。之所以在本节提到这么多编码特点,主要提醒大家在预防XSS时需要注意的几点:

检测用户输入时,不仅仅需要防范类似<>这样的字符,通过unicode编码或进制编码仍有可能注入代码

需要针对特定的关键字做过滤,如eval、write、prototype

尽可能禁止内联事件处理函数的使用

js过滤src/href/action属性,如javascript:,data:

JS编码

其实在上节中已提到了js编码,即js可执行unicode编码和十六(八)进制编码后的字符串,但是不支持十进制编码的字串。具体操作可通过常用的几个函数来实现,如eval,write,setTimeout,Function执行编码后的字符串;同样,对于十进制编码的字串,通过结合String.fromCharCode和eval同样可以执行。

在此附上笔者实现的字符转换,更为灵活的实现各种自定义形式的字串编码:

var Code = {};   

   /**

         *

         * @param str 待编码字串

         * @param jinzhi 进制编码

         * @param prefix 前缀

         * @param postfix 后缀

         * @param count 总共编码的位数,默认为4

         * @returns {string}

         */

        Code.encode = function({str = '',jinzhi = '16',prefix = '\\u',postfix = ';',count = '4'} = {}){

            var ret = '';

            var addZero,tmp;

            for(let i=0;i<str.length;i++){

                tmp = str.charCodeAt(i).toString(jinzhi);

                addZero = count - tmp.length + 1;

                ret += prefix + new Array(addZero).join('0') + tmp + postfix;

            }

            return ret;

        };

        Code.decode = function({str = '',jinzhi = '16',prefix = '\\u',postfix = ';'} = {}){

            var ret = '';

            var splits = str.split(';');

            for(let i=0;i<splits.length;i++){

                let tmp = splits[i].replace(prefix,'');

                ret += String.fromCharCode(parseInt(tmp,jinzhi));

            }

            return ret;

        };

        console.log(Code.encode({str: '<img src=@ onerror=alert(123) />'}));

        console.log(Code.decode({str: Code.encode({str: '<img src=@ onerror=alert(123) />'})}))

另外,对于js输出点的过滤其实并不仅限于上文提到的如eval、setTimeout、Function等几个,由于JS语法比较灵活相对漏洞较多,可使用的线索也越丰富,如前段时间在Stackoverflow上发现的一个问题,即

(0)['constructor']['constructor']('return "abc;"')()

同样可以执行JS代码,确实挺有特点的,具体为什么上述形式可以执行代码,请读者自己仔细品味。

以上就是昆明前端开发中的字符编码的所有内容,希望对大家有所帮助。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

热门产品

短视频/直播电商部门岗位职责及绩效考核指标管理实施办法|短视频运营岗位职责,直播电商部门管理,直播电商部门绩效考核,短视,频/,直播,电商,部门,岗位职责,绩效,考核,指标,管理,实施办法
短视频/直播电商部门岗位职责及绩效考核指标管理实施办法
在线药店设计书(范文)|在线药店设计书,在线药店设计,在线药店,在线,药店,设计书,范文
在线药店设计书(范文)
x升电子有限公司商务网站项目设计书|商务网站项目设计书,商务网站项目,商务网站,瑞升电子有限公司,x升,电子,有限公司,项目,设计书
x升电子有限公司商务网站项目设计书
必通网上考试书店项目设计书(范文)|必通网上考试书店项目设计书,网上考试书店项目设计书,网上考试书店项目设计,网上考试书店项目,必通,网上,考试,书店,项目,设计书,范文
必通网上考试书店项目设计书(范文)
(有详细评估的范文)E-WORK网络实习平台及线下实习教育|网络实习平台,线下实习教育,E-WORK网络实习平台,详细,评估,范文,work,网络,实习,平台,线下,教育
(有详细评估的范文)E-WORK网络实习平台及线下实习教育
(范文)网上内衣店项目设计书|内衣店项目设计书,网上内衣店项目设计书,内衣店项目设计,范文,网上,内衣,项目,设计书
(范文)网上内衣店项目设计书
**鞋业公司  开拓电子商务和校园市场  营销策划方案|鞋业营销策划,鞋业营销策划方案,**,鞋业,公司,开拓,电子商务,校园,市场,营销策划,方案
**鞋业公司 开拓电子商务和校园市场 营销策划方案
视频伪原创处理:短视频搬运处理方法步骤及图文视频深度创作处理|视频搬运方法,视频搬运技巧,视频伪原创,图文视频技巧,搬运,视频,处理,步骤,图文,原创,短视频搬运,短视,方法,深度,创作
视频伪原创处理:短视频搬运处理方法步骤及图文视频深度创作处理

历史上的今天:04月19日

美业发朋友圈的小套路-讲稿

美丽誓颜的小伙伴们,大家早上好!一日之计在于晨,利用宝贵的晨间时间, Nicole 老师想跟大家分享一个发朋友圈的套路。我们做微商一路走过来,会遇到不同的人,也会招到不同的代理,有些代理能力很强,朋友圈发的内容都是原创,很有新意。对他们来说,遇到了美丽誓颜这个机遇,仿佛打开了新世界的大门,把自己很多灵感都转化成了充满创意的朋友圈; 也有一些代理,有很多好的 idea 却不知道怎么转化成适合发圈的文

热门专题

安徽中源管业|安徽中源管业,安徽中源管业mpp电力管,安徽中源管业cpvc电力管,安徽中源管业pe穿线管,安徽中源管业电力管,安徽中源管业排水管,安徽中源管业通信管,安徽中源管业管材
安徽中源管业
自考本科|自考本科有用吗,自考文凭,自考本科文凭,自考文凭有用吗,自考本科文凭有用吗,自考文凭承认吗
自考本科
弥勒综合高中|弥勒综合高中
弥勒综合高中
云南网站建设|云南网站制作,网站建设,云南网站开发,云南网站设计,云南网页设计,云南网站建设公司,云南网站建设
云南网站建设
外贸网站建设|外贸网站建设,英文网站制作,英文网站设计,美国主机空间,外贸建站平台,多语言网站制作
外贸网站建设
大理科技管理学校|大理科技管理中等职业技术学校,大理市科技管理中等职业技术学校
大理科技管理学校
易捷尔单招|易捷尔单招,易捷尔单招培训,易捷尔单招报名,易捷尔单招考试,易捷尔单招培训学校,易捷尔单招分数
易捷尔单招
易捷尔高职单招|易捷尔高职单招,易捷尔高职单招培训,单招分数线,单招录取分数线,高职单招学校分数线
易捷尔高职单招

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部