设计思路
- 模块封装:使用 ES6 模块系统,每个模块都有自己独立的作用域,避免全局变量污染。这样不同模块的类和原型不会在全局作用域下相互干扰。
- 冻结对象:对于不希望被修改的类和原型,使用
Object.freeze
方法。冻结后的对象不能添加新属性,不能修改现有属性,也不能删除属性,从而防止恶意代码对其进行修改导致原型污染。
- 严格模式:在模块中使用严格模式(
'use strict';
),严格模式会对一些潜在不安全或不符合规范的操作抛出错误,例如给不可写属性赋值、使用未声明变量等,有助于发现潜在的恶意代码行为。
- 验证输入:在涉及到使用外部输入来操作类和原型时,对输入进行严格的验证。确保输入的数据类型和内容符合预期,防止恶意数据导致原型污染或其他安全漏洞。
- 不可枚举属性:将一些关键属性设置为不可枚举(
Object.defineProperty
时设置 enumerable: false
),这样恶意代码通过 for...in
等枚举操作无法访问到这些属性,降低被攻击的风险。
关键实现代码
- 模块封装示例:
// module1.js
export class MyClass1 {
constructor() {
this.property1 = 'value1';
}
}
// module2.js
export class MyClass2 {
constructor() {
this.property2 = 'value2';
}
}
- 冻结对象示例:
class MySecureClass {
constructor() {
this.someProperty = 'initial value';
}
}
Object.freeze(MySecureClass.prototype);
const instance = new MySecureClass();
// 以下操作在严格模式下会报错
// instance.__proto__.newProperty = 'attempted malicious addition';
- 严格模式使用:
// 整个模块使用严格模式
'use strict';
class MyClass {
constructor() {
// 这里的代码遵循严格模式规则
}
}
- 验证输入示例:
class User {
constructor(name) {
if (typeof name!=='string' || name.length === 0) {
throw new Error('Invalid name input');
}
this.name = name;
}
}
- 设置不可枚举属性示例:
class SomeClass {
constructor() {
this.publicProperty = 'visible';
}
}
Object.defineProperty(SomeClass.prototype, 'privateProperty', {
value: 'not enumerable',
enumerable: false
});
const obj = new SomeClass();
for (let key in obj) {
console.log(key); // 不会输出 'privateProperty'
}