1 背景
在进行数据抓取时,找javascript生成的cookie通常是一件很烦人的事情。如果能一步定位到cookie是哪个javascript文件生成,那么会极大减轻工作量。
2 原理
我们设置cookie会通过document.cookie来设置。当设置cookie时,能触发我们增加的拦截功能即可。
如果一个对象具有一个属性,我们可以获取该对象的属性描述符,并覆盖属性描述符对象的set方法来完成拦截功能。
属性描述符是ES5中新增的概念,其作用是给对象的属性增加更多的控制。当通过document.cookie设置修改属性时,属性描述符的set方法会被调用。
而我们只需要重写这个方法,当document.cookie发生时,先调我们设置的拦截操作,最终再调document.cookie即可实现。具体实现涉及到了属性拦截涉及了属性描述符、原型对象、及闭包概念。可查看参考资料[1]学习。
为了给浏览器增加这个功能,我们将能够拦截cookie设置的js脚本通过编写chrome插件,在页面文档加载前注入页面中。随后页面有cookie设置动作发生时,拦截会被触发。
3 实现分析
chrome插件体系结构概述中介绍的content script就是我们要这里编写的拦截脚本。拦截脚本实现如下。代码取自[2]。
function breakOn(obj, propertyName, mode, func) {
function getPropertyDescriptor(obj, name) {
var property = Object.getOwnPropertyDescriptor(obj, name);
var proto = Object.getPrototypeOf(obj);
while (property === undefined && proto !== null) {
property = Object.getOwnPropertyDescriptor(proto, name);
proto = Object.getPrototypeOf(proto);
}
return property;
}
function verifyNotWritable() {
if (mode !== 'read')
throw "This property is not writable, so only possible mode is 'read'.";
}
var enabled = true;
var originalProperty = getPropertyDescriptor(obj, propertyName);
var newProperty = { enumerable: originalProperty.enumerable };
// write
if (originalProperty.set) {// accessor property
newProperty.set = function(val) {
if(enabled && (!func || func && func(val)))
debugger;
originalProperty.set.call(this, val);
}
} else if (originalProperty.writable) {// value property
newProperty.set = function(val) {
if(enabled && (!func || func && func(val)))
debugger;
originalProperty.value = val;
}
} else {
verifyNotWritable();
}
// read
newProperty.get = function(val) {
if(enabled && mode === 'read' && (!func || func && func(val)))
debugger;
return originalProperty.get ? originalProperty.get.call(this, val) : originalProperty.value;
}
Object.defineProperty(obj, propertyName, newProperty);
return {
disable: function() {
enabled = false;
},
enable: function() {
enabled = true;
}
};
};
4 参考
[1]javascript基础知识,https://wangdoc.com/javascript/oop/prototype.html
[2]属性拦截,https://github.com/paulirish/break-on-access/blob/master/break-on-access.js