原型污染(Prototype Pollution):如何通过 `__proto__` 篡改全局对象并防御?

技术讲座:原型污染(Prototype Pollution)的原理与防御

引言

原型污染(Prototype Pollution)是一种常见的Web安全漏洞,它允许攻击者通过篡改JavaScript对象的原型来影响全局对象,进而可能导致信息泄露或执行恶意代码。本文将深入探讨原型污染的原理、攻击方法、防御策略,并提供相应的工程级代码示例。

原型污染原理

JavaScript中的每个对象都有一个原型(prototype),它是一个对象,用于实现继承。当访问对象不存在的属性或方法时,JavaScript引擎会沿着原型链向上查找,直到找到对应的属性或方法。

原型污染攻击利用了这一点,通过篡改对象的原型,将恶意代码注入到全局对象中。以下是一个简单的例子:

// 假设全局对象为window
window.__proto__ = {
  _secret: 'my_secret',
  getSecret: function() {
    return this._secret;
  }
};

// 攻击者访问getSecret方法
console.log(window.getSecret()); // 输出:my_secret

在这个例子中,攻击者通过修改window.__proto__,将一个包含恶意代码的原型赋值给全局对象。当攻击者调用getSecret方法时,实际上是在调用全局对象的getSecret方法,从而实现了攻击目的。

攻击方法

原型污染攻击有多种方法,以下是一些常见的攻击手段:

  1. 修改全局对象的原型:如上例所示,通过修改window.__proto__,将恶意代码注入全局对象。
  2. 利用构造函数的原型:通过修改构造函数的原型,可以影响由该构造函数创建的对象的原型。
  3. 利用函数的原型:通过修改函数的原型,可以影响由该函数创建的对象的原型。

以下是一些具体的攻击示例:

1. 修改全局对象的原型

// 修改全局对象的原型
Object.prototype.constructor = {
  _secret: 'my_secret',
  getSecret: function() {
    return this._secret;
  }
};

// 攻击者访问getSecret方法
console.log(Object.getSecret()); // 输出:my_secret

2. 利用构造函数的原型

// 创建一个构造函数
function MyClass() {}

// 修改构造函数的原型
MyClass.prototype.constructor = {
  _secret: 'my_secret',
  getSecret: function() {
    return this._secret;
  }
};

// 创建对象并访问getSecret方法
var obj = new MyClass();
console.log(obj.getSecret()); // 输出:my_secret

3. 利用函数的原型

// 创建一个函数
function myFunction() {}

// 修改函数的原型
myFunction.prototype.constructor = {
  _secret: 'my_secret',
  getSecret: function() {
    return this._secret;
  }
};

// 调用函数并访问getSecret方法
console.log(myFunction().getSecret()); // 输出:my_secret

防御策略

为了防止原型污染攻击,可以采取以下防御策略:

  1. 限制全局对象的原型修改:在代码中,尽量避免修改全局对象的原型。
  2. 使用严格模式:在JavaScript代码中启用严格模式,可以限制对全局对象的原型修改。
  3. 使用Content Security Policy(CSP):CSP可以限制脚本来源,防止恶意脚本注入。
  4. 使用库或框架:使用成熟的库或框架,它们通常已经对原型污染进行了防御。

以下是一些具体的防御示例:

1. 限制全局对象的原型修改

// 禁止修改全局对象的原型
Object.defineProperty(window, '__proto__', {
  configurable: false,
  writable: false,
  value: Object.getPrototypeOf(window)
});

2. 使用严格模式

// 在代码开头启用严格模式
'use strict';

// 尝试修改全局对象的原型将抛出错误
Object.prototype.constructor = {
  _secret: 'my_secret',
  getSecret: function() {
    return this._secret;
  }
};

3. 使用CSP

<!-- 在HTML中设置CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">

4. 使用库或框架

// 使用成熟的库或框架
var express = require('express');
var app = express();

// 使用express框架,它已经对原型污染进行了防御
app.get('/', function(req, res) {
  res.send('Hello, world!');
});

总结

原型污染是一种常见的Web安全漏洞,攻击者可以通过篡改对象的原型来影响全局对象,从而实现恶意目的。本文介绍了原型污染的原理、攻击方法和防御策略,并提供了一些工程级代码示例。在实际开发中,我们应该注意防范原型污染攻击,确保应用程序的安全性。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注