什么是恶意输入
在一些应用场景下,用户输入的内容会显示到页面中,比如文章的发布,等等,这个时候就会出现一个问题。
比如猪痞恶霸在掘金的文章简介内插入下面的一行代码
<script> alert("猪痞恶霸yyds") </script> 复制代码
这里就不表达出不好的内容了,其实这还不算是严重的问题,如果使用了无限循环alert
那就直接死机,又或者将页面跳转到其他页面去,造成进不去的情况
😶🌫️用户恶意输入的威胁性可想而知,那么又如何去解决这个问题呢,下面将具体介绍一种通过标签模板来解决的方法
标签模板
概念
标签模板是模板字符串的一种使用方式,可以理解为跟在函数名后的模板字符串,也算是函数的另一种使用形式,可以将模板字符串内部的字符串部分和变量替换部分以参数的形式传递到函数中,就如下面的例子。
let str = "猪痞恶霸", _str = "fzf404"; function add(a, ...b) { console.log(a); console.log(b); } add`Hello${str}World${_str}`; // [ 'Hello', 'World', '' ] // [ '猪痞恶霸', 'fzf404' ] 复制代码
其参数的转换是有特定的规则,其第一个参数是一个数组的形式,其数组成员为变量部分的两边字符串,如上[ 'Hello', 'World', '' ]
其数组包含三个成员,为什么会有空字符串,是因为在第二个变量部分_str
即"World"
与空格之间,所以第三个数组成员为空字符串;第二个参数到第n个参数为变量成员,也可以使用扩展运算符使其为数组,如上[ '猪痞恶霸', 'fzf404' ]
。
使用
了解了标签模板的使用,那么我们是如何使用标签模板来解决用户恶意输入的问题呢
首先我们声明了一个str
变量来模拟用户输入
let str = "<script>alert("猪痞恶霸yyds")</script>" 复制代码
声明一个防御函数,防御函数参考 《ES6标准入门》 ,这里我来讲解下我思考的其函数实现过程:
函数的参数包含两种,一种是字符串成员,一种是变量成员也就是用户输入的内容,首先保存第一个字符串成员,通过使用arguments
从第二个参数开始遍历,因为需要在遍历体内进行监测恶意内容替换,所以从变量成员开始遍历,将变量成员通过String()
转换为字符串,通过replace
方法进行恶意内容的替换再与先前保留的头部字符串成员拼接,比如这里将<
与>
替换为不可被认为成<script>
执行但是可以被正常渲染的内容,在结束循环前拼接下一个字符串成员,达到交叉拼接的效果。
function SaferHTML(tempalte) { let s = tempalte[0]; for (let i = 1; i < arguments.length; i++) { let arg = String(arguments[i]); // Escape special characters in the substitution. s += arg.replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); // Don't escape special characters in the template. s += tempalte[i]; } return s; } 复制代码
最后再通过标签模板执行函数即可
let end = SaferHTML`<p>${str}用户输入${str}</p>`; 复制代码
总体上的实现是依托标签模板的参数特性,达到一个字符串的拼接替换操作。
参考文献
ES6标准入门