一、背景
xss攻击是前端的日常会遇到的安全问题,本文概述react框架是如何预防xss攻击的,学习框架如何处理安全问题。
二、xss介绍
全称Cross Site Script,跨站脚本攻击。
XSS的定义:XSS是一种注入式攻击,通过向用户页面注入恶意脚本,用户浏览页面时运行脚本进攻攻击,如获取一些隐私信息, 例如cookie。
主要是利用:
1.利用了浏览器可以运行javascript的特点
2.html文档中可以包含可执行的脚本,html的部分内容可以在浏览器或服务器上动态生成
3.恶意代码常见的载体例如script标签,标签中的onclick, onerror这些可以直接填写代码的位置。
2.1 xss类型
反射型
恶意代码放在请求中,服务端读取后返回包含恶意代码的html
例如下面这请求中的query是一一段运行的js脚本
https://www.test.com?query=<script>alert(123)</script>
服务端获取query后直接原样拼接在html中返回<p>{{ 这里原样输出query的内容 }}<p>
这样上面恶意请求返回的html中就包含了<p><script>alert(123)</script></p>这样一段可执行的js, 可以利用起进行攻击,获取用户隐私信息等。
存储型
1.恶意代码放在请求中,服务端保存恶恶意代码至数据库
2.用户请求时,服务端从数据库里取出带恶意代码的字段,拼接在html中
例如下面这请求中的query是一一段运行的js脚本
https://www.test.com/save?query=<script>alert(123)</script>
服务端接受请求后将query保存至数据库
用户请求页面https://www.test.com/page
服务端读取数据库字段query后直接原样拼接在html中返回<p>{{ 这里原样输出query的内容 }}<p>
用户访问到的html中就包含了<p><script>alert(123)</script></p>这样一段可执行的js, 可以利用起进行攻击,获取用户隐私信息等。
DOM型
恶意代码放在请求中,客户端通过js动态插入到html中,比如使用eval()、innerHTML、document.write()等不安全的API。
例如下面这请求中的query是一一段运行的js脚本
https://www.test.com/save?query=<script>alert(123)</script>
使用`eval()`、`innerHTML`、`document.write()`等不安全的API
const div = document.createElement('div');
div.innerHTML = decodeURIComponent(query)
document.body.appendChild(div);
2.2 xss分类
也可以通过危险代码是在客户端还是服务端生成的分为client型和server型
client型:DOM型
server型:反射型和存储型
三、react框架防御xss
react-client
1.进行DOM操作的时候避免直接拼接并插入DOM, 如.innerHTML、.outerHTML、document.write() ,而是使用.textContent改变文本内容、.setAttribute()改变标签属性。
2.danngerousSetInnerHtml可以直接原样插入html,慎用
react-server
对输出的html进行转义
function escapeHtml(string) {
if (__DEV__) {
checkHtmlStringCoercion(string);
}
const str = '' + string;
const match = matchHtmlRegExp.exec(str);
if (!match) {
return str;
}
let escape;
let html = '';
let index;
let lastIndex = 0;
for (index = match.index; index < str.length; index++) {
switch (str.charCodeAt(index)) {
case 34: // "
escape = '"';
break;
case 38: // &
escape = '&';
break;
case 39: // '
escape = '''; // modified from escape-html; used to be '''
break;
case 60: // <
escape = '<';
break;
case 62: // >
escape = '>';
break;
default:
continue;
}
if (lastIndex !== index) {
html += str.substring(lastIndex, index);
}
lastIndex = index + 1;
html += escape;
}
return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
}