摘要:可能有信息敏感的同學已經了解到庫爆出嚴重安全漏洞,波及萬項目。以此為例,可見這次漏洞算是比較嚴重了。此外,凍結一個對象后該對象的原型也不能被修改。
摘要: 詳解原型污染。
原文:Lodash 嚴重安全漏洞背后 你不得不知道的 JavaScript 知識
作者:Lucas HC
Fundebug經授權轉載,版權歸原作者所有。
可能有信息敏感的同學已經了解到:Lodash 庫爆出嚴重安全漏洞,波及 400萬+ 項目。這個漏洞使得 lodash “連夜”發版以解決潛在問題,并強烈建議開發者升級版本。
我們在忙著“看熱鬧”或者“”升級版本”的同時,靜下心來想:真的有理解這個漏洞產生的原因,明白漏洞修復背后的原理了嗎?
這篇短文將從原理層面分析這一事件,相信“小白”讀者會有所收獲。
漏洞原因其實漏洞很簡單,舉一個例子:lodash 中 defaultsDeep 方法,
_.defaultsDeep({ "a": { "b": 2 } }, { "a": { "b": 1, "c": 3 } })
輸出:
{ "a": { "b": 2, "c": 3 } }
如上例,該方法:
分配來源對象(該方法的第二個參數)的可枚舉屬性到目標對象(該方法的第一個參數)所有解析為 undefined 的屬性上
這樣的操作存在的隱患:
const payload = "{"constructor": {"prototype": {"toString": true}}}" _.defaultsDeep({}, JSON.parse(payload))
如此一來,就觸發了原型污染。原型污染是指:
攻擊者通過某種手段修改 JavaScript 對象的原型(prototype)
對應上例,Object.prototype.toString 就會非常不安全了。
詳解原型污染理解原型污染,需要讀者理解 JavaScript 當中的原型、原型鏈的知識。我們先來看一個例子:
// person 是一個簡單的 JavaScript 對象 let person = {name: "lucas"} // 輸出 lucas console.log(person.name) // 修改 person 的原型 person.__proto__.name = "messi" // 由于原型鏈順序查找的原因,person.name 仍然是 lucas console.log(person.name) // 再創建一個空的 person2 對象 let person2 = {} // 查看 person2.name,輸出 messi console.log(person2.name)
把危害擴大化:
let person = {name: "lucas"} console.log(person.name) person.__proto__.toString = () => {alert("evil")} console.log(person.name) let person2 = {} console.log(person2.toString())
這段代碼執行將會 alert 出 evil 文字。同時 Object.prototype.toString 這個方法會在隱式轉換以及類型判斷中經常被用到:
Object.prototype.toString 方法返回一個表示該對象的字符串
每個對象都有一個 toString() 方法,當該對象被表示為一個文本值時,或者一個對象以預期的字符串方式引用時自動調用。默認情況下,toString() 方法被每個 Object 對象繼承。如果此方法在自定義對象中未被覆蓋,toString() 返回 [object type],其中 type 是對象的類型。
如果 Object 原型上的 toString 被污染,后果可想而知。以此為例,可見 lodash 這次漏洞算是比較嚴重了。
再談原型污染(NodeJS 漏洞案例)由上分析,我們知道原型污染并不是什么新鮮的漏洞,它“隨時可見”,“隨處可見”。在 Nullcon HackIM 比賽中就有一個類似的 hack 題目:
"use strict"; const express = require("express"); const bodyParser = require("body-parser") const cookieParser = require("cookie-parser"); const path = require("path"); const isObject = obj => obj && obj.constructor && obj.constructor === Object; function merge(a, b) { for (var attr in b) { if (isObject(a[attr]) && isObject(b[attr])) { merge(a[attr], b[attr]); } else { a[attr] = b[attr]; } } return a } function clone(a) { return merge({}, a); } // Constants const PORT = 8080; const HOST = "0.0.0.0"; const admin = {}; // App const app = express(); app.use(bodyParser.json()) app.use(cookieParser()); app.use("/", express.static(path.join(__dirname, "views"))); app.post("/signup", (req, res) => { var body = JSON.parse(JSON.stringify(req.body)); var copybody = clone(body) if (copybody.name) { res.cookie("name", copybody.name).json({ "done": "cookie set" }); } else { res.json({ "error": "cookie not set" }) } }); app.get("/getFlag", (req, res) => { var аdmin = JSON.parse(JSON.stringify(req.cookies)) if (admin.аdmin == 1) { res.send("hackim19{}"); } else { res.send("You are not authorized"); } }); app.listen(PORT, HOST); console.log(`Running on http://${HOST}:${PORT}`);
這段代碼的漏洞就在于 merge 函數上,我們可以這樣攻擊:
curl -vv --header "Content-type: application/json" -d "{"__proto__": {"admin": 1}}" "http://0.0.0.0:4000/signup"; curl -vv "http://0.0.0.0:4000/getFlag"
首先請求 /signup 接口,在 NodeJS 服務中,我們調用了有漏洞的 merge 方法,并通過 __proto__ 為 Object.prototype(因為 {}.__proto__ === Object.prototype) 添加上一個新的屬性 admin,且值為 1。
再次請求 getFlag 接口,條件語句 admin.аdmin == 1 為 true,服務被攻擊。
攻擊案例出自:Prototype pollution attacks in NodeJS applications
這樣的漏洞在 jQuery $.extend 中也經常見到:
jQuery 修復原型污染 PR
jQuery prototype pollution vulnerability
對于 jQuery:如果擔心安全問題,建議升級至最新版本 jQuery 3.4.0,如果還在使用 jQuery 的 1.x 和 2.x 版本,那么你的應用程序和網站仍有可能遭受攻擊。
防范原型污染了解了漏洞潛在問題以及攻擊手段,那么如何防范呢?
在 lodash “連夜”發版的修復中:
我們可以清晰的看到,在遍歷 merge 時,當遇見 constructor 以及 __proto__ 敏感屬性,則退出程序。
那么作為業務開發者,我們需要注意些什么,防止攻擊出現呢?總結一下有:
凍結 Object.prototype,使原型不能擴充屬性
我們可以采用 Object.freeze 達到目的:
Object.freeze() 方法可以凍結一個對象。一個被凍結的對象再也不能被修改;凍結了一個對象則不能向這個對象添加新的屬性,不能刪除已有屬性,不能修改該對象已有屬性的可枚舉性、可配置性、可寫性,以及不能修改已有屬性的值。此外,凍結一個對象后該對象的原型也不能被修改。freeze() 返回和傳入的參數相同的對象。
看代碼:
Object.freeze(Object.prototype); Object.prototype.toString = "evil" consoel.log(Object.prototype.toString) ? toString() { [native code] }
對比:
Object.prototype.toString = "evil" console.log(Object.prototype.toString) "evil"
建立 JSON schema
在解析用戶輸入內容是,通過 JSON schema 過濾敏感鍵名。
規避不安全的遞歸性合并
這一點類似 lodash 修復手段,完善了合并操作的安全性,對敏感鍵名跳過處理
使用無原型對象
在創建對象時,不采用字面量方式,而是使用 Object.create(null):
Object.create()方法創建一個新對象,使用現有的對象來提供新創建的對象的__proto__
Object.create(null) 的返回值不會鏈接到 Object.prototype:
let foo = Object.create(null) console.log(foo.__proto__) // undefined
這樣一來,無論如何擴充對象,都不會干擾到原型了。
采用新的 Map 數據類型,代替 Object 類型
Map 對象保存鍵/值對,是鍵/值對的集合。任何值(對象或者原始值)都可以作為一個鍵或一個值。使用 Map 數據結構,不會存在 Object 原型污染狀況。
這里總結一下 Map 和 Object 不同點::
Object 的鍵只支持 String 或者 Symbols 兩種類型,Map 的鍵可以是任意值,包括函數、對象、基本類型
Map 中的鍵值是有序的,而 Object 中的鍵則不是
具體 API 上的差異:比如,通過 size 屬性直接獲取一個 Map 的鍵值對個數,而 Object 的鍵值無法獲取;再比如迭代一個 Map 和 Object 差異也比較明顯
Map 在頻繁增刪鍵值對的場景下會有些性能優勢
補充:V8,chromium 的小機靈同樣存在風險的是我們常用的 JSON.parse 方法,但是如果你運行:
JSON.parse("{ "a":1, "__proto__": { "b": 2 }}")
你會發現返回的結果如圖:
復寫 Object.prototype 失敗了,__proto__ 屬性還是我們熟悉的那個有安全感的 __proto__ 。這是因為:
V8 ignores keys named proto in JSON.parse
這個相關討論 Doug Crockford,Brendan Eich,反正 chromium 和 JS 發明人討論過很多次。相關 issue 和 PR:
chromium 討論
chromium 討論
相關 ES 語言設計的討論:ES 語言設計的討論:proto-and-json
在上面鏈接中,你能發現 JavaScript 發明人等一眾大佬哦~
總之你可以記住,V8 默認使用 JSON.parse 時候會忽略 __proto__,原因當然是之前分析的安全性了。
總結通過分析 lodash 的漏洞,以及解決方案,我們了解了原型污染的方方面面。涉及到的知識點包括但不限于:
Object 原型
原型、原型鏈
NodeJS 相關問題
Object.create 方法
Object.freeze 方法
Map 數據結構
深拷貝
以及其他問題
這么來看,全是基礎知識。也正是基礎,構成了前端知識體系的方方面面。
關于FundebugFundebug專注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有陽光保險、核桃編程、荔枝FM、掌門1對1、微脈、青團社等眾多品牌企業。歡迎大家免費試用!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/105848.html
摘要:可能有信息敏感的同學已經了解到庫爆出嚴重安全漏洞,波及萬項目。以此為例,可見這次漏洞算是比較嚴重了。此外,凍結一個對象后該對象的原型也不能被修改。使用數據結構,不會存在原型污染狀況。 可能有信息敏感的同學已經了解到:Lodash 庫爆出嚴重安全漏洞,波及 400萬+ 項目。這個漏洞使得 lodash 連夜發版以解決潛在問題,并強烈建議開發者升級版本。 我們在忙著看熱鬧或者升級版本的同時...
摘要:基本數據類型在中,基本數據類型有種,即數值字符串布爾值。兩個布爾值轉為數值進行比較。對于對象和布爾值,調用它們的方法得到對應的字符串值,然后進行字符串相加。減法對于字符串布爾值或者,自動調用,轉換結果若為,那么最終結果為。 這篇文章,來聊聊 JS 中的數據類型與變量。這是在學習 JS 時最基礎的一類問題,但卻很重要。希望我的分享有幫助到你。 文章開頭,我先提幾個面試中遇到的問題: 比如...
摘要:本文是響應式編程第二章序列的深入研究這篇文章的學習筆記。函數科里化的基本應用,也是函數式編程中運算管道構建的基本方法。四資料參考函數式編程指南 本文是Rxjs 響應式編程-第二章:序列的深入研究這篇文章的學習筆記。示例代碼托管在:http://www.github.com/dashnowords/blogs 更多博文:《大史住在大前端》目錄 showImg(https://segme...
摘要:日前,簡歷大數據公司巧達科技被警方一鍋端,高管和員工全部被帶走。買賣簡歷,直接違法。三人累計販賣個人簡歷萬余份,智聯招聘由此蒙受損失近日前,簡歷大數據公司巧達科技被警方一鍋端,高管和員工全部被帶走。到底發生了什么? ?一 、為什么公司全員被抓? 3月14日團隊被警方帶走,有HR等非核心成員回家,但核心高管依然失聯中。3月25日,一位巧達科技前員工告訴燃財經。 在天眼查中北京...
摘要:日前,簡歷大數據公司巧達科技被警方一鍋端,高管和員工全部被帶走。買賣簡歷,直接違法。三人累計販賣個人簡歷萬余份,智聯招聘由此蒙受損失近 日前,簡歷大數據公司巧達科技被警方一鍋端,高管和員工全部被帶走。到底發生了什么??一 、為什么公司全員被抓?3月14日團隊被警方帶走,有HR等非核心成員回家,但核心高管依然失...
閱讀 2894·2021-11-24 09:39
閱讀 3151·2021-11-19 10:00
閱讀 1556·2021-10-27 14:17
閱讀 1825·2021-10-14 09:43
閱讀 978·2021-09-03 10:30
閱讀 3424·2019-08-30 15:54
閱讀 2748·2019-08-30 13:05
閱讀 2023·2019-08-30 11:02