文档章节

PHP htmlspecialchars不能防御前端innerHTML产生的XSS注入

eechen
 eechen
发布于 2016/02/28 11:31
字数 744
阅读 1426
收藏 9
不要在JS里直接用innerHTML输出未经JS过滤的用户内容,
即使这些内容已经经过服务器端PHP的htmlspecialchars或者HTMLPurifier过滤.
比如下面的代码,页面将alert弹出字符串/xss/,因为JS会把变量中的Unicode字符\u003c和\u003e转换成<和>输出.

<?php
//<img src=1 onerror=alert(/xss/)>
$xss = '\u003cimg src=1 onerror=alert(/xss/)\u003e';
//<a href=javascript:alert(String.fromCharCode(88,83,83))>XSS</a>
$xss = '\u003ca href=javascript:alert(String.fromCharCode(88,83,83))\u003eXSS\u003c/a\u003e';
header('Content-Type: text/html;charset=utf-8');
?>
<div id="xss"></div>
<script src="jquery.js"></script>
<script>
// PHP的htmlspecialchars不能过滤\u003c和\u003e,经过JS赋值后,Unicode字符\u003c和\u003e被转换成<和>.
var xss = '<?php echo htmlspecialchars($xss, ENT_QUOTES, 'UTF-8'); ?>';
console.log(xss);
//$("#xss").html(xss); //能够执行alert(/xss/) document.getElementById("xss").innerHTML = xss;
//$("#xss").html(xss.replace(/</g, "&lt;").replace(/>/g, "&gt;")); //不能执行alert(/xss/)
//$("#xss").text(xss); //不能执行alert(/xss/) document.getElementById("xss").innerText = xss;
</script>
$(#xss).append(xss)跟$("#xss").html(xss)输出的都是HTML.

解决方法:
http://segmentfault.com/q/1010000004067521
毕竟很多时候要把AJAX加载的数据用innerHTML添加到页面.
值得注意的是,innerHTML本质也是输出HTML,
所以我们可以在输出前用JS像PHP的htmlspecialchars那样
把特殊字符(&,",',<,>)替换为HTML实体(&amp;&quot;&#039;&lt;&gt;).
或者干脆直接用innerText(IE)和textContent(Firefox),也就是jQuery的text()来输出文本内容.
Firefox不支持IE的innerText,但支持textContent.
StackOverflow上找到的两个实现:
function htmlspecialchars(str) {
    return str
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;");
}
function htmlspecialchars(str) {
    var map = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return str.replace(/[&<>"']/g, function(k) { return map[k]; });
}
其中g表示全局(global)替换的意思,也就是把字符串中的所有匹配的内容都进行替换.

不过JS模仿PHP的htmlspecialchars是一刀切的方法,数据将丧失HTML特性.
请教下,对于前端AJAX(PJAX)过来后的HTML数据大家是怎么过滤XSS输出的呢?
经过PJAX测试后发现,AJAX返回的数据用jQuery的html()函数插入并不会因为Unicode字符\u003c和\u003e而发生XSS.
index.php:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index</title>
<script src="jquery.js"></script>
</head>
<body>
<div id="main">
    <a href="data.php">data.php</a>
    <script>
    $(document).ready(function() {
        $('#main').on('click','a',function(e) {
            if(window.history.pushState) {
                e.preventDefault(); //不跟随原链接跳转
                url = $(this).attr('href');
                $.ajax({
                    async: true,
                    type: 'GET',
                    url: 'data.php',
                    data: 'pjax=1',
                    success: function(data) {
                        window.history.pushState(null, null, url); //改变URL和添加返回历史
                        document.title = data.title; //设置标题
                        $('#main').html(data.main); //这里并不会因为Unicode字符\u003c和\u003e而发生XSS
                        //$('#main').html('\u003cimg src=1 onerror=alert(/xss/)\u003e'); //直接赋值字符串则会发生XSS
                    }
                });
            } else {
                return; //低版本IE8等不支持HTML5 pushState,直接返回进行链接跳转
            }
        });
    });
    </script>
</div>
</body>
</html>

data.php:
<?php
if(isset($_GET['pjax'])) {
    //PJAX请求返回JSON
    $arr['title'] = 'Data';
    $arr['main'] = '\u003cimg src=1 onerror=alert(/xss/)\u003e';
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($arr);
} else {
    //常规请求返回HTML
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Data</title>
<script src="jquery.js"></script>
</head>
<body>
<div id="main">\u003cimg src=1 onerror=alert(/xss/)\u003e</div>
</body>
</html>
<?php } ?>

© 著作权归作者所有

eechen

eechen

粉丝 1021
博文 107
码字总数 55962
作品 1
深圳
私信 提问
加载中

评论(3)

eechen
eechen 博主

引用来自“菜蚜”的评论

可以针对不同的请求做不同程度的XSS过滤。
文末补充了测试,经过测试后发现,AJAX返回的数据用jQuery的html()函数插入并不会因为Unicode字符\u003c和\u003e而发生XSS.
菜蚜
菜蚜
可以针对不同的请求做不同程度的XSS过滤。
PHP安全编码

一、开始前的一些建议 1.不要相信任何用户输入或第三方数据来源,包括$GET、$POST($FILES)、$COOKIE、$SERVER的部分参数等。 2.HTML、PHP、MYSQL等使用统一的UTF-8编码。 3.数据库SQL构造时...

ZoaChou
2015/09/18
587
2
XSS,CSRF防范 也是慢慢更

xss攻击两种 reflected 和stored 如xss可以获取用户的cookie <script>alert(document.cookie)</script> csrf可以跨站请求修改删除用户信息 防御措施: 1.一般的XSS脚本 2.安全函数 如php的 ...

just_wkj
2015/12/30
113
0
WEB安全 - 认识与防御XSS攻击

目录 什么是xss攻击? XSS的危害 XSS攻击分类 xss攻击示例 反射型攻击 - 前端URL参数解析 反射型攻击 - 后端URL参数解析 注入型攻击 - 留言评论 如何规避xss攻击? 总结 什么是xss攻击? XS...

卷柏的花期
2018/08/13
0
0
Web-安全-学习资料(很全)​

看原文 看原文 看原文 Web-安全-学习资料(很全) Web-Security-Learning 在学习web安全的过程中整合的一些资料。 该repo会不断更新,最近更新日期为:2017/9/19。 9月19日更新: 新收录文章...

Ho0oH
2017/09/26
0
0
web安全:什么是 XSS 和 CSRF

在 Web 安全领域中,XSS 和 CSRF 是最常见的攻击方式。本文将会简单介绍 XSS 和 CSRF 的攻防问题。 XSS (Cross Site Script) 跨站脚本攻击 XSS 攻击是指攻击者在网站上注入恶意的客户端代码,...

Shellming
05/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Jenkins World 贡献者峰会及专家答疑展位

本文首发于:Jenkins 中文社区 原文链接 作者:Marky Jackson 译者:shunw Jenkins World 贡献者峰会及专家答疑展位 本文为 Jenkins World 贡献者峰会活动期间的记录 Jenkins 15周岁啦!Jen...

Jenkins中文社区
32分钟前
8
0
杂谈:面向微服务的体系结构评审中需要问的三个问题

面向微服务的体系结构如今风靡全球。这是因为更快的部署节奏和更低的成本是面向微服务的体系结构的基本承诺。 然而,对于大多数试水的公司来说,开发活动更多的是将现有的单块应用程序转换为...

liululee
47分钟前
7
0
OSChina 周二乱弹 —— 我等饭呢,你是不是来错食堂了?

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @ 自行车丢了:给主编推荐首歌 《クリスマスの夜》- 岡村孝子 手机党少年们想听歌,请使劲儿戳(这里) @烽火燎原 :国庆快来,我需要长假! ...

小小编辑
今天
474
9
玩转 Springboot 2 之热部署(DevTools)

Devtools 介绍 SpringBoot 提供了热部署的功能,那啥是热部署累?SpringBoot官方是这样说的:只要类路径上的文件发生更改,就会自动重新启动应用程序。在IDE中工作时,这可能是一个有用的功能...

桌前明月
今天
6
0
CSS--列表

一、列表标识项 list-style-type none:去掉标识项 disc:默认实心圆 circle:空心圆 squire:矩形 二、列表项图片 list-style-img: 取值:url(路径) 三、列表项位置 list-style-position:...

wytao1995
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部