在前端JS的部分编码引起的xss
<div id="a">test</div>
<div id="b">test</div>
<div id="c">test</div>
<a href="javasc
ript:alert(/xss/)">click</a>
<a href="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==">test</a>
<script>
var a="\u003cimg src=1 onerror=alert(/xss/)\u003e";
var b="\74\151\155\147\40\163\162\143\75\170\40\157\156\145\162\162\157\162\75\141\154\145\162\164\50\61\51\76";
var c="\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\u002f\u0078\u0073\u0073\u002f\u0029\u003e";
document.getElementById("a").innerHTML=a;
document.getElementById("b").innerHTML=b;
document.getElementById("c").innerHTML=c;
</script>
php中的XSS攻击和预防
xss攻击的类型
- 反射型:通过url参数直接注入。
- 存储型:通过存储到数据库读取时注入。比反射型危害更大一些。
xss攻击的注入点
1、html节点内容
如果一个节点内容是动态生成的、包含用户输入的信息、那么数据有可能包含xss攻击
例子
<?php $name="<script>alert(2);</script>"; ?>
<div><?PHP echo $name; ?></div>
2、html属性
如果一个节点属性是用户输入生成的或超出属性本身等、那么数据有可能包含xss攻击
例子
<?php $src='1" onerror=alert(1);"'; ?>
<img src="<?php echo $src ?>" />
3、javascript代码
js代码中、存在有后台注入的变量或者包含用户输入的信息、那么可能改变代码的逻辑、可能存在xss攻击
例子
<?php $xss=$_GET['xss'];
echo $xss;
?>
<script>
var xss="<?php echo $xss; ?>";
console.log(xss);
</script>
接着演变
富文本
富文本是包含html结构的,那么可能存在js等代码、xss攻击。富文本的本质是保留html、一般不推荐直接用
textarea里面直接使用html。应该选用富文本编辑器。
补充
关于url执行get传参数执行的<script>
脚本、在现代浏览器会自动屏蔽、浏览器自带防御是参数出现在html内容或属性中、自动触发。
因为浏览器默认开启了XSS保护
php开启或关闭保护代码
header("X-XSS-Protection: 1"); //开启XSS保护
header("X-XSS-Protection: 0"); //禁用XSS保护
禁用保护的结果
关于浏览器的SCP
全称Content Security Policy
内容安全策略,用于指定那些内容可执行,他是http头。等同于提供白名单。
在php中声明有两种方式第一是用header函数、第二种是在meta标签里面声明
1、php
<?php
header("X-XSS-Protection: 0"); //禁用XSS保护
header("Content-Security-Policy: default-src self");
?>
2、meta标签
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
参数介绍
script-src:外部脚本
style-src:样式表
img-src:图像
media-src:媒体文件(音频和视频)
font-src:字体文件
object-src:插件(比如 Flash)
child-src:框架
frame-ancestors:嵌入的外部资源(比如<frame>、<iframe>、<embed>和<applet>)
connect-src:HTTP 连接(通过 XHR、WebSockets、EventSource等)
worker-src:worker脚本
manifest-src:manifest 文件 webapp一些信息
default-src 没有指定内容是 默认内容
代码演示
访问网址
http://localhost/newTest.php?xss=%3Cscript%3Ealert%281%29%3C%2Fscript%3E
代码
<?php
header("X-XSS-Protection: 0"); //禁用XSS保护
//header("Content-Security-Policy: default-src self");
?>
<img id="img" src="//qidian.qpic.cn/qdbimg/349573/1011058239/150" srcset="//qidian.qpic.cn/qdbimg/349573/1011058239/300 2x" class="author-item-img">
<?php $xss=$_GET['xss'];
echo "<br/>";
echo $xss;
?>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
console.log($('#img'));
</script>
<script>
var xss="<?php echo $xss; ?>";
</script>
图片结果
现在我把scp打开
代码
<?php
header("X-XSS-Protection: 0"); //禁用XSS保护
header("Content-Security-Policy: default-src self");
?>
<img id="img" src="//qidian.qpic.cn/qdbimg/349573/1011058239/150" srcset="//qidian.qpic.cn/qdbimg/349573/1011058239/300 2x" class="author-item-img">
<?php $xss=$_GET['xss'];
echo "<br/>";
echo $xss;
?>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
console.log($('#img'));
</script>
<script>
var xss="<?php echo $xss; ?>";
</script>
结果
代码用script-src中nonce属性来加载带令牌的脚本防止xss攻击
url
http://localhost/newTest.php?xss=%3Cscript%3Ealert%281%29%3C%2Fscript%3E
代码
<?php
header("X-XSS-Protection: 0"); //禁用XSS保护
header("Content-Security-Policy: script-src 'self' 'nonce-123456'");
?>
<img id="img" src="//qidian.qpic.cn/qdbimg/349573/1011058239/150" srcset="//qidian.qpic.cn/qdbimg/349573/1011058239/300 2x" class="author-item-img">
<?php $xss=$_GET['xss'];
echo "<br/>";
echo $xss;
?>
<script nonce="123456" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script nonce="123456">
console.log($('#img'));
</script>
<script>
var xss="<?php echo $xss; ?>";
</script>
结果是带令牌的执行了、不带令牌的不执行
另一种方法相对麻烦是计算内容的hash值、通过hash算法计算和值相对比的内容、如果对比成功则加载
列子、
<script>var xss=123; console.log(xss);</script>
用node.js计算脚本的hash值、代码
var content=`var xss=123; console.log(from);`;
var crypto=require('crypto');
var hash=crypto.createHash('sha256');
hash.update(content);
var str=hash.dugest('base64');
console.log(str);
更改页面上的scp把nonce-123456替换sha256-xxxxxxxxxxxx 既可