xss
为什么不能阻止用户输入不安全数据
比如用户想发一篇标题的文章 1+1>2吗?
为什么不在数据库存的时候就处理好或者接口里处理好
1<2
会被转义为 1<2
,放到html中确实可以正常显示为 1<2
,但如果要把它alert出来就还是1<2
什么是xss
-
xss
是一种注入
- 用户将自己的
html
代码注入到我们的html
中 - 类似SQL注入
- 用户将自己的
这是一种
html
的注入,所以与python
,数据库无关
比如说:
数据:
value = "<script>alert(1);</script>"
模板:
<p><?=value?></p>
前两者生成的html:
<p><script>alert(1);</script></p>
这样就被注入了一段代码,然后浏览器诚实的解析执行
了它
解决办法
- 将用户数据转义为
纯文本
- 浏览器当做
纯文本
显示而不是解析
它
将上例模板改成:
<p><?-value?></p>
- 上例中用的是
<?=
代表直接输出 - 本例使用的是
<?-
代表转义后输出
(不同模板引擎在实现的时候会略有不同,但都大同小异)
生成的html:
<p><script>alert(1);</script></p>
在浏览器上的表现:
<script>alert(1);</script>
html转义
为什么要转义
- 为了能让
html解释器
可以解析出正确的页面 - 就像在字符串中不可以直接输入
"
而得输入\"
(不然字符串就断开了),在html中也得转义部分字符:-
\
/
-
'
'
-
"
"
-
<
<
-
>
>
-
&
&
-
假设我们要输出一个</p>
字符串到页面,那html就会是:
-
<p></p></p>
显然是不行的 -
<p></p></p>
这样才是正确的
什么应该不转义
- 需要展示为富文本
- 并且绝对没有可执行代码(需要后端事先做好过滤)
什么应该转移(剩下的全部情况)
<img src="<%-src%>">
<div>
<%-text%>
</div>
script标签内
在script标签中,都是js代码,浏览器不会把他们当做html代码解析,所以不需要html转义
但script标签有个特性:从<script>
标签开始,一直到</script>
标签截止,所以需要注意:
<script>
var a='</script><script>alert(1)</script>'; // 到第一个</script>就截止了!!!
</script>
<script>
···
var a='<\/script><script>alert(1)<\/script>'; //这样就正确
···
</script>
如何把数据打到script里:
在script里也需要转义,但不是html转移,需要转移4个字符:'
"
/
\
,转移的方法就是在他们前边添加一个\
,是不是有些熟悉,他比字符串转义只多一个/
,剩下的全部一样
用到的工具就是jsonify,把后端变量变成js变量
<script>
···
var a=<?=JSON.stringify(a).replace(/\//g,'\\/')?>;
// 将会变成以下
var a="<\/script>";
var a=null;
var a={a:1};
···
</script>
jsonify规则:
- None null
- "str" "str"
- True true
- 1 1
- map JSON
一下演示一些错误的使用方法:
<script>
···
var a="<?-a?>";
// 将会变成以下
var a="h&m" //原来的数据是 h&m
var a="<?=a?>";
// 将会变成以下
var a="</script><script>alert(1);</script>"
var a="</script>";alert(1); //被注入
···
</script>
js
写入:
只有涉及到操作html
的时候才会有xss的问题:
- html(html)
- append(html)
- ...
这些情况需要转义或者使用.text(text)
方法替代。
.text('<>')
是不需要转义的,因为不是设置html
所以不需要html解析器
解析,修改属性(.prop('src',src)
)也一样
读取:
<div id="d" data-text="&"><</div>
$('#d').text(); // "<"
$('#d').html(); // "<"
$('#d').data('text'); // "&"