最近查看browserify源碼在扰,發(fā)現(xiàn)其沒有用eval和new Function痢虹,原因如下:
確保browserify的安裝使用了語(yǔ)法-error@1.1.1或 后來(lái)存在一個(gè)安全漏洞,惡意文件可能會(huì) 瀏覽時(shí)執(zhí)行代碼悬钳。 該漏洞涉及破壞用于 檢查語(yǔ)法以了解更多信息性錯(cuò)誤昨登。在節(jié)點(diǎn)0.10中,
Function()以“eval()”的形式實(shí)現(xiàn)障般,這樣惡意代碼甚至可以執(zhí)行 如果從未調(diào)用“function()”返回的函數(shù)调鲸。節(jié)點(diǎn)0.11確實(shí)如此 似乎不易受攻擊。 多虧了Cal Leeming[cal@iops.io] 感謝你發(fā)現(xiàn)并揭露這個(gè)錯(cuò)誤挽荡!
經(jīng)過(guò)一番思考藐石,發(fā)現(xiàn)之前 重寫的browserify也可以改進(jìn)為不使用eval和new Function
改進(jìn)代碼如下:
browserify.js
const fs = require("fs");
const { resolve } = require("path");
const moduleFuncCache = [];
let curIndex = 0;
//記錄path和數(shù)組對(duì)應(yīng)資源數(shù)組位置
const pathIndexMap = {};
const codeSplicing = (path) => {
// 獲取絕對(duì)路徑
const wholePath = resolve(path);
if (pathIndexMap[wholePath] !== undefined) return;
const text = fs
.readFileSync(wholePath, "utf-8")
.trim()
.replace(/require/g, "_require")
.replace(/_require\(['\"](.*)['\"]\)/g, function (matched, $1) {
codeSplicing($1);
return `_require(${pathIndexMap[resolve($1)]})`;
})
.replace(/;$/, "");
moduleFuncCache.push(`
function(){
const module = {exports:{}};
let {exports} = module;
${text}
return module.exports
}
`);
pathIndexMap[wholePath] = curIndex++;
};
const getCode = () => {
// eval方式轉(zhuǎn)函數(shù)
return `
// 自執(zhí)行函數(shù),避免全局污染
(function(){
const moduleCache = []
const _require = function(index){
// 第一次引用該模塊則執(zhí)行定拟,后續(xù)從緩存中取
if(!moduleCache[index]) moduleCache[index] = formatModuleFuncCache[index]()
return moduleCache[index]
}
//數(shù)組收集于微,省去了json序列化的過(guò)程,從而省去轉(zhuǎn)碼的過(guò)程
const formatModuleFuncCache = [${moduleFuncCache}]
//執(zhí)行入口文件代碼
formatModuleFuncCache[${moduleFuncCache.length - 1}]()
})()
`;
};
//主函數(shù),傳入文件路徑青自,返回最終打包完成的代碼塊
const browserify = (path) => {
// 為每個(gè)require的模塊拼接代碼株依,為其提供module實(shí)例,并返回module.exports
codeSplicing(path);
// 阻止代碼延窜,使其能解析代碼cache對(duì)象恋腕,并依照引入順序來(lái)執(zhí)行代碼塊
return getCode();
};
// 執(zhí)行命令行傳入打包源文件 node ./browserify.js index.js,此時(shí)path即index.js
const [path] = process.argv.splice(2);
// 寫目標(biāo)文件;
fs.writeFileSync("./chunk.js", browserify(path));
能夠改進(jìn)的核心原因是:
- 對(duì)象不方便轉(zhuǎn)字符串逆瑞,需要借助json
- json對(duì)中文解析能力弱荠藤,需要轉(zhuǎn)碼,而函數(shù)代碼轉(zhuǎn)碼就需要在chunk中轉(zhuǎn)回來(lái)呆万,則被動(dòng)地必須使用eval或者new Function
- 數(shù)組很方便轉(zhuǎn)化成代碼字符串商源,不需要經(jīng)過(guò)上述流程