跨站脚本(XSS,Cross Site)攻击是指攻击者可以让网站执行非法脚本。这种情况很常见。例如,在提交修改用户名的表单时,我们可以在文本框中输入一些特殊字符,如'、"等,来检查用户名是否被正确修改。
XSS是如何发生的
XSS一定是由用户输入引起的。无论是提交表单还是点击链接(参数),只要将用户输入不进行任何转义写入数据库,或者写入html或js,就会非常轻松。可能会出问题。举两个例子。
假设您需要显示新闻标题列表。对于服务端渲染来说,可能是用jade这样来实现的。
h1 娱乐速递
ul
each val in newslist
li= val
只需将其视为格式为 ['News1', 'News2', ...] 的数组。如果直接将内容迭代渲染为HTML,一旦新闻标题有特殊字符,例如标题中恰好包含
标签,则不会显示。
再比如,如果用户正在写博客,我们就不要考虑实时保存。现在我们只需要预览它。那么可能的代码是
var preview = document.getElementById('#preview'),
title = document.getElementById('#blog-title'),
content = document.getElementById('#blog-content');
preview.innerHTML =
'' + title.value + '
' +
'' + content.value + '
';
这里,用户的输入也直接显示在html上。如果恰好输入了用户的输入,则提前结束该标签,然后再次输入,直接执行js代码。
XSS的发生至少需要一个条件,那就是这些非法脚本必须在浏览器中被解析。
从发出请求到浏览器显示内容,有3个地方与XSS相关:URL、HTML。至于后端,它有两个功能。一是向数据库写入数据。这时数据也必须进行转义,但它不属于XSS的范畴。更多的是防止数据破坏SQL语句的结构;另一种是转义数据库读取数据直接生成HTML或者以JSON的形式传给前端。这些数据必须先转义才能显示在浏览器中。
HTML 特殊字符
HTML本身是一个文本文档,但它可以以多种方式出现在浏览器中,因为许多字符对于浏览器来说具有特殊的含义。例如,浏览器会对HTML中的内容做一些动画。那么转义这些特殊字符就意味着让浏览器将它们视为普通字符。例如,文本≶>将在浏览器中正常显示。
当我们在代码中生成HTML时,一定要注意变量是否被转义。像这样
el.innerHTML = title.value;
这是非常危险的。因为输入框的内容来自于用户,而用户的输入是不可靠的。不管是前端还是后端,一定有类似的方法,然后在代码中这样使用
el.innerHTML = escapeHTML(title.value);
这是转义 HTML 的简单方法。
function encodeHTML (a) {
return String(a)
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
};
那么哪些字符需要转义呢?以下是一些常见的。
“-->”
# --> #
$ --> $
& --> &
' --> '
( --> (
) --> )
; -->;
< --> <
> --> >
在方法中,我使用别名方法进行转义,因为这样更容易记住。无论是别名还是十六进制数,它们所代表的含义都是一样的。例如&和&都代表&符号。如果您想查看更具体的列表,可以参考这个网站。
浏览器收到HTML后,首先会解码所有内容。它将所有可识别的编码符号解码为文字值。例如,有
my name is: 名一
经过浏览器解码后变成
my name is: 名一
这里我想说的是,浏览器只会解码两个地方,一是标签的内容(即除了 and 标签),二是标签的属性值。属性名称不会被解码。
网址
此前,服务器不支持在URL中直接传输。例如,服务器无法识别“hello”值,因此必须在传输之前对其进行编码。
所以对于URL,我们只需要对参数的值进行编码即可。例如上面的链接,编码后为%E4%BD%A0%E5%A5%BD。
如果整个 URL 都经过编码,则该链接将不起作用。
编码方法非常简单。浏览器提供了一个全局方法,调用后可以实现转义。
重要的一点是,URL 中具有特殊含义的字符(例如:、/、?、&、=)不会被转义。如果参数恰好包含这些字符,则它们不会被转义。例如
encodeURI('http://jchen.cc/login?name=名一&from=http://other.com');
// -> http://jchen.cc/login?name=%E5%90%8D%E4%B8%80&from=http://other.com
from 参数的值不会被转义。这时候就需要用到另外一个方法了。
var param = encodeURIComponent('http://other.com');
encodeURI('http://jchen.cc/login?name=名一&from=') + param;
// -> http://jchen.cc/login?name=%E5%90%8D%E4%B8%80&from=http%3A%2F%2Fother.com
所以结论是,如果你想转义整个URL,就使用,如果你想转义参数的值,就使用。
当动态生成的链接地址需要分配给href或src属性时,需要对这些地址进行URL转义。当然,如果服务器支持URL中的UTF-8字符,那么不转义它们也没有问题。这就是为什么我们通常不太关注转义表单和URL参数,因为服务器性能良好。
特殊字符
JS中的转义都是通过反斜杠来完成的。分为三种,以 ' 和 " 为例。
一般情况下,可以直接通过反斜杠转义,但是有一些字符我们不知道怎么输入。很常见,比如Web Font。你可以在 CSS 中看到这样的代码。
.glyphicon-home::before {
content: "";
}
其中的值可以用十六进制或替换。
JS转义一般用在显示用户输入的时候。例如用户输入反斜杠,需要显示,alert('\\');必须使用。
解码顺序
浏览器绘制时,首先解码HTML,然后解码URL,最后执行时解码JS。
现在考虑这三种编码同时存在的情况
click
首先是HTML解码,结果是
click
然后对URL进行解码,结果为
click
最后进行JS解码,结果为
click
单击链接后,应出现一个弹出窗口,其中显示内容。
这篇文章更多的是关于如何防止XSS的发生,而不是它的危害。核心是使用适当的方法来转义HTML和JS。
扫一扫在手机端查看
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。