一、为什么要做一款这样的小插件
数据,始终在思考如何让数据更平安的流转和服务于客户,围绕这样的想法,咱们做过许多方面的扩大。咱们落地了服务端的数据切片反对场景化的设计,实现了基于 JDBC 协定对 SQL 的拦挡与切片,实现了在应用层的全链路数据库审计计划和实现,实现了 WEB 端明暗水印和文档水印等等,但这些都是在应用服务端的革新;那么围绕以上服务端的思维产生了在端上做一些事件,剖析了团体外部服务,多以 WEB 服务端对客户和用户提供便当的性能和数据应用场景。WEB 服务多以依赖浏览器的存在进行拜访,所以就试图把数据安全防护的计划前置到浏览器上,在浏览器上做辅助性的数据探测,能够在研发阶段和测试阶段发现数据应用的平安问题,比方某个接口的返回了明文手机号,某个页面未应用身份信息然而调用的接口返回了等等场景 …
所以咱们要做一个浏览插件把数据安全防护能力前置到端上实现,它不会影响开发者和测试人员 …
二、解决的思路和想法
第一步阐明了咱们为什么要做一款这样的小工具,这个章节就是如何去解决下面的问题和想法。
1、浏览器占比剖析
市场上的浏览器 chrome/firefox/safri…. 从市场上数据分析目前 chrome 浏览器占比份额为 66.93%,根本主导了浏览器市场,排名第二的是 MicrosoftEdge 浏览器。依据这样的一个后果咱们优先从 chrome 插件去着手。
2、知识面的延长
咱们团队侧重于后端的方向研发,在前端侧的能力相对来说比拟弱势特地是在浏览器插件又波及到一些底层的运行机制等;首先官网文档去理解 chrome 插件开发,明确了目前 chrome 反对的插件版本为 v2 和 v3,其中不好的音讯就是 v2 在 2023 年的时候会被后续的版本放弃,意味着 v2 和 v3 要同时进行,所以又去理解了一下版本的差别,两个版本在网络拦挡方面有了比拟大的改变,后者变成了规定的模式,对拦挡方面不是太敌对。
3、想法和功能设计
要把数据安全局部防护能力前置到浏览器端,意味着要对以后的性能做剖析和实现,首先插件能力不能对研发和测试人员产生影响,其次应用要不便。就有了以下的四个点的想法:
第一是 WEB 水印能力
通过对插件机制的理解,能够在装置插件之后,对失效的站点批改 dom 的构造,把水印主动的减少到页面中。
第二个想到的是敏感的数据
利用的敏感数据起源分为三个局部:页面渲染的资源,接口申请的数据,接口返回的数据,围绕这一层的构思,最终定义要实现对页面和申请的拦挡。
第三想法是对页面的操作的事件监听
这个的来源于某些站点会提供大量的数据,用户在应用的时候能够间接应用把数据复制到其它数据,这样的操作属于用户个人行为也不是文件的模式,用户在复制的过程中无奈第一工夫感知是否为敏感,没有方法做到第一工夫的追踪和防护。
第四个.. 其实是额定的延长
咱们目前同时也做数据流动链相干的我的项目,在我的项目进行的过程中发现会在前端路由与后端路由的链条缺失,想到浏览器插件的运行机制是能够通过 dom 的对象拿到前端页面的路由,这样的思路就能够填补了这块数据链关系的缺失。
三、落地的路上很多坑
1、繁难逻辑图
2、devtool 的坑
在 chrome 插件的生命周期中,在 background 能监听申请收回、返回等事件,个别能获取的事件如下:
// web 申请监听,最初一个参数示意阻塞式,需独自申明权限:webRequestBlocking
chrome.webRequest.onBeforeRequest.addListener(details => {
// cancel 示意勾销本次申请
if(details.type == 'image' || details.type === 'medis') return {cancel: false};
}, {urls: ["<all_urls>"]});
//ajax 生命周期开始
chrome.webRequest.onBeforeRequest.addListener(details => {console.log('onBeforeRequest', details);
}, {urls: ["*://*.jd.com/**"] });
chrome.webRequest.onBeforeSendHeaders.addListener(details => {console.log('onBeforeSendHeaders', details)
},
{urls: ["*://*.jd.com/**"] },
['blocking', 'requestHeaders', 'extraHeaders']
);
// 能够拦挡 ajax
chrome.webRequest.onResponseStarted.addListener(details => {console.log('onResponseStarted', details);
}, {urls: ["*://*.jd.com/**"]});
// 申请实现,然而取不到 response 后果
chrome.webRequest.onCompleted.addListener(details => {console.log('onCompleted', details);
}, {urls: ["*://*.jd.com/**"]
该形式无奈拿到 response 内容,从网上常见的解决方案,是给浏览器插件增加 devtools_page 模块,而后在 devtools 的页面增加 request 完结事件,如下:
chrome.devtools.network.onRequestFinished.addListener(function(request) {
//request 蕴含申请响应数据,如:url, 响应内容等
//request.request.url 接口 的 url
//request.getContent 接口返回的内容
}
);
然而该形式有个问题,就是想要触发 devtools 的页面内容,须要在页面按 F12 呼出浏览器的控制台,这个体验就很个别,所以 devtools 这种模式更像是为开发人员提供 debug 工具时引入的。
3、xhr/fetch
因为上文应用两种形式的局限性,所以思考重写 xhr,而后在页面加载时进行注入替换,重写 xhr 的办法如下:
(function () {
var open = XMLHttpRequest.prototype.open;
var send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function (body) {this["hookQuery"] = body;
send.apply(this, arguments);
};
XMLHttpRequest.prototype.open = function () {this.addEventListener("load", function () {if (this.responseType === ""|| this.responseType ==="text") {
window.dispatchEvent(
new CustomEvent("pageScript", {...})
);
}
});
open.apply(this, arguments);
};
})()
次要改写了原有 send 办法和 open 办法,在 send 时,将申请的参数记录到 xhr 实体的一个属性里,而后在申请触发并返回(load 事件)后,将申请的参数、响应的返回内容,通过事件发送进来,事件会在 content\_scripts 进行监听和解决,content\_scripts 局部代码如下:
// 加载重写的 xhr 所在 js 文件,而后注入到以后页面的 document 中,这样业务的页面会加载这段 js
var hook = document.createElement("script");
hook.src = chrome.runtime.getURL("script/hook.js");
hook.onload = function () {this.remove();
};
(document.head || document.documentElement).appendChild(hook);
// 监听 xhr 发送过去的音讯
window.addEventListener(
"pageScript",
function (event) {// 解决逻辑},
false
);
五、成果演示
六、未完待续
第一版的性能以敏感数据防护为主导线,后续会减少数据安全其它的防护和感知能力,从端上帮助业务解决数据安全的危险
作者:CCO 体系 郝帅卫
起源:京东云开发者社区