【每日一题NO.77】浏览页面突然出现广告的原因是什么?
问题:在我们访问一个页面时,有时候会突然出现一段广告,这可能是什么原因,怎么解决?
答:可能有两种情况:
XSS跨站脚本攻击 HTTP劫持
什么是 XSS 攻击?
XSS
攻击 一般指攻击者通过在网页注入恶意脚本,当用户浏览网页时,恶意脚本执行,控制用户浏览器行为的一种攻击方式。
他的全称:Cross Site Scripting
他的简称:XSS
(因为已经有CSS的称呼,所以改称XSS)
XSS 攻击分类
反射型 XSS 攻击
通过 URL 链接点击触发,是一次性行为, 本质上是服务器端没有对用户恶意输入做安全处理,直接反射输入内容。
如:输入“baidu.com/?id=”,弹出弹窗内容为 1。
谷歌这类安全性高的浏览器基本可以自动处理这类攻击。
存储型 XSS 攻击
顾名思义,一般涉及后端数据存储。
常见场景意见反馈模块,这种模块通常用富文本输入,用户可以随意输入内容。
不法分子在前端输入恶意脚本,并通过接口传给后端。
当后台管理系统再次展示反馈意见时,就会读取数据库中这些恶意脚本数据,此时这些数据中含有的攻击脚本就会在浏览者的前端执行,这就是存储型 XSS 攻击。
而且,这种攻击是持久性的。
所以,当我们在项目中使用富文本编辑器、内容编辑器、作用域、文本框等需要用户输入内容的表单时,一定要注意是否有输入内容存在恶意脚本被执行的情况。
这就需要我们在存储给后端时对数据进行转译(将脚本标签转为html的转义字符进行展示)、在读取并展示内容时尽量不要用innerHTML
这类用于内容渲染的API。
DOM 型 XSS 攻击
又称作 “DOM反射型XSS”。与第一种“反射性 XSS攻击”的区别是,需要恶意脚本通过操作DOM(比如给DOM元素的innerHTML属性赋值)来进行攻击。
防御
浏览器自带的防御 X-XSS-Protection
目前支持 IE、Chrome、Safari 浏览器,可检测到 XSS 攻击时,阻止页面加载。
使用方式是在HTTP响应头中设置X-XSS-Protection
字段:
X-XSS-Protection: 0
X-XSS-Protection 为 0
表示禁止使用 XSS 过滤(不用浏览器自带的安全防护)
X-XSS-Protection: 1
为 1
表示允许使用 XSS 过滤。
X-XSS-Protection: 1; mode=block
mode=block
:若检测到 XSS 攻击,阻止页面加载。
X-XSS-Protection: 1; report=
report=\
(仅限 Chromium):若检测到跨站点脚本攻击,浏览器将清理页面并报告违规行为。使用 CSP
report-uri 指令发送报告。
HTML 标签
将标签符号<、>等全局转义
const escapeHtml = (str) => {
str = str
.replace(/&/g, "&")
.replace(/, "<")
.replace(/>/g, ">")
.replace(/"/g, "&quto;")
.replace(/'/g, "'")
.replace(/ /g, " ");
return str;
};
白名单过滤
大体思路将 HTML 字符串解析成实体对象。
若白名单里属性存在在该实体对象中则做相应的处理。
这里使用 cheerio 将 HTML 解析成实体。
const whiteList = {
img: ["src"],
};
const xssFilter = (html) => {
if (!html) return "";
const $ = cheerio.load(html, {
normalizeWhitespace: true,
xmlMode: true,
});
$("*").each((index, elem) => {
if (!whiteList[elem.name]) {
$(elem).remove();
return;
}
for (var attr in elem.attributes) {
if (whiteList[elem.name].indexOf(attr) === -1) {
$(elem).attr(attr, null);
}
}
});
return $.html();
};
CSP
CSP
(Content Security Policy) 实质就是白名单制度,开发者明确告诉客户端哪些外部资源可以加载和执行。
设置如下:
<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 'self';
脚本:只信任当前域名object-src 'none';
style-src cdn.example.org third-party.org;
样式表:只信任 cdn.example.org 和 third-party.orgchild-src https:
框架(frame):必须使用HTTPS
协议加载其他资源:没有限制
HTTP 挟持
什么是 HTTP 挟持?
在运营商的路由器节点上,设置协议检测,一旦发现是 HTTP
请求且是 HTML
类型请求,则拦截处理。常见有两种:
返回 302 让用户浏览器跳转到另外的地址
在服务器返回的 HTML 中插入 JS 或 DOM 节点
HTTP 劫持防御
向运营商投诉
在 HTML 上加上如下代码禁止转码
<meta http-equiv="Cache-Control" content="no-siteapp">
<meta http-equiv="Cache-Control" content="no-transform"/>
使用 HTTPS,HTTPS 增加了 SSL 协议,会对数据进行加密。
白名单过滤。大体思路是检查所有外链是否属于白名单。
监听 DOM 节点插入及 DOM 节点移除事件
el.addEventListener("DOMNodeInserted", function (e) {
console.log(e.srcElement);
});
el.addEventListener("DOMNodeRemoved", function (e) {
console.log(e.srcElement);
});
所有《每日一题》的 知识大纲索引脑图 整理在此:https://www.yuque.com/dfe_evernote/interview/everyday
你也可以点击文末的 “阅读原文” 快速跳转