簡體   English   中英

如何防止 JavaScript 中的原型污染

[英]How to prevent prototype pollution in JavaScript

最近我偶然發現了doT.js 中的一個漏洞 該漏洞的存在是因為攻擊者可以使用原型污染來修改傳遞給 doT 的選項的值。

例子:

var doT = require("dot");
var tempFn = doT.template("<h1>Here is a sample template " +
    "{{=console.log(23)}}</h1>");
tempFn({})
var doT = require("dot"); // prototype pollution attack vector
Object.prototype.templateSettings = {varname:"a,b,c,d,x=console.log(25)"};
// benign looking template compilation + application
var dots = require("dot").process({path: "./resources"});
dots.mytemplate();

然后我開始思考:這是否意味着幾乎所有JavaScript 庫的 API 選項都可能因原型污染而受到損害?

例如,這里的express.static與選項一起使用。

var options = {
  dotfiles: 'ignore',
  etag: false,
  extensions: ['htm', 'html'],
  index: false,
  maxAge: '1d',
  redirect: false,
  setHeaders: function (res, path, stat) {
    res.set('x-timestamp', Date.now())
  }
}

app.use(express.static('public', options))

攻擊者不能設置Object.prototype.redirect = true ,如果用戶未指定,會發生重定向嗎? 肯定還有更多惡意用例。

作為庫作者,可以做些什么來允許傳遞選項但防止原型污染?

編輯:我特別關注與 NPM 一起分發的包。 例如,doT.js 的作者可以做些什么來解決這個漏洞?

Olivier Arteau發布了一份完整的白皮書 PDF,稱為NodeJS 應用程序中的Prototype 污染攻擊,涵蓋了攻擊的識別和緩解。


攻擊的一般概念

原型污染背后的一般思想始於這樣一個事實:攻擊者至少可以控制以下形式的任何表達式的參數avalue

obj[a][b] = value;

攻擊者可以將a設置為__proto__並且b定義的名稱的屬性將定義在應用程序的所有現有對象(屬於obj的類)上,值為value

當攻擊者至少控制abvalue時,同樣的事情可以附加以下形式。

obj[a][b][c] = value;

攻擊者可以將a設置為constructorbprototypec定義的名稱的屬性將定義在應用程序的所有現有對象上,值為value

然而,因為這需要更復雜的對象分配,所以第一種形式更容易使用。

雖然您很少會偶然發現在文本上看起來像提供的示例的代碼,但一些操作可以為攻擊者提供類似的控制。

減輕

使用 Map 而不是 Object

它本質上用作 HashMap,但沒有Object具有的所有安全警告。 當需要鍵/值結構時, Map應該優先於Object

Object.create(null)

可以在 JavaScript 中創建沒有任何原型的對象。 它需要使用Object.create函數。 通過此 API 創建的對象將不具有__proto__constructor屬性。 以這種方式創建對象有助於減輕原型污染攻擊。

let obj = Object.create(null);
obj.__proto__ // undefined
obj.constructor // undefined

JSON 輸入的模式驗證

npm 上的多個庫(例如: ajv )為 JSON 數據提供模式驗證。 架構驗證確保 JSON 數據包含具有適當類型的所有預期屬性。 當使用這種方法來減輕“原型污染”攻擊時,重要的是拒絕不需要的屬性。 ajv ,這可以通過設置來完成additionalPropertiesfalse的架構。

凍結原型

使用Object.freeze將減輕幾乎所有可利用的情況。

請注意,雖然向基礎對象的原型添加函數在實踐中是令人不悅的,但它仍可能在您的 Node.js 應用程序或其依賴項中使用。 強烈建議在沿着這條路線前進之前檢查您的 Node.js 應用程序及其對此類使用的依賴。 由於凍結對象的行為是在屬性分配時靜默失敗,因此可能會引入難以識別的錯誤。

Object.freeze(Object.prototype);
Object.freeze(Object);
({}).__proto__.test = 123;
({}).test // this will be undefined

作為庫作者,可以做些什么來允許傳遞選項但防止原型污染?

您可以使用.hasOwnProperty()檢測屬性是在您的實際對象上還是通過原型繼承。 但是, .hasOwnProperty() ,攻擊者也可以覆蓋.hasOwnProperty()並改變其行為。

正如我在評論中所說,有人在他們的 Javascript 程序中使用您的庫,可以完全訪問您的代碼。 因此,他們甚至不必使用原型污染來修改內容——他們可以隨意修改您的代碼。

為了完全保護您的代碼,您必須僅分發在不同進程中運行並具有進程間 API(例如 http 服務器)的已編譯可執行文件,或者您必須將代碼放入服務中並僅提供以這種方式訪問​​。 如果您要分發 Javascript 庫,就其本質而言,您必須分發源代碼,以便使用您的庫的程序員可以真正對它做任何他們想做的事情。 他們甚至不必訴諸原型技巧。

我也有這個問題,並將我的package.json依賴項升級到最新版本包可能已過時。 有時它可能與升級或降級一樣小。

npm install -g npm-check-updates

運行命令npm audit將為您提供依賴漏洞和建議補丁的報告。

 npm audit

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM