摘要:遷移到安全的構(gòu)造函數(shù)移植到概述本指南介紹了如何遷移到安全的構(gòu)造函數(shù)方法,遷移修復(fù)了以下棄用警告由于安全性和可用性問題,不建議使用和構(gòu)造函數(shù),請改用或構(gòu)造方法。
遷移到安全的Buffer構(gòu)造函數(shù)
移植到Buffer.from()/Buffer.alloc() API.
概述本指南介紹了如何遷移到安全的Buffer構(gòu)造函數(shù)方法,遷移修復(fù)了以下棄用警告:
由于安全性和可用性問題,不建議使用Buffer()和new Buffer()構(gòu)造函數(shù),請改用new Buffer.alloc()、Buffer.allocUnsafe()或Buffer.from()構(gòu)造方法。
變式1:放棄對Node.js ≤4.4.x和5.0.0 - 5.9.x的支持(推薦)。
變式2:使用polyfill。
變式3:手動檢測,帶有安全措施。
使用grep查找有問題的代碼位只需運(yùn)行grep -nrE "[^a-zA-Z](Slow)?Buffers*(" --exclude-dir node_modules。
它會在你自己的代碼中找到所有可能不安全的地方(有一些不太常見的例外)。
使用Node.js 8查找有問題的代碼位如果你使用的是Node.js ≥ 8.0.0(推薦使用),Node.js會公開多個(gè)選項(xiàng),以幫助你找到相關(guān)的代碼片段:
--trace-warnings將使Node.js顯示此警告的堆棧跟蹤以及Node.js打印的其他警告。
--trace-deprecation執(zhí)行相同的操作,但僅適用于棄用警告。
--pending-deprecation將顯示更多類型的棄用警告,特別是,它也會顯示Buffer()棄用警告,即使在Node.js 8上。
你可以使用環(huán)境變量設(shè)置這些標(biāo)志:
$ export NODE_OPTIONS="--trace-warnings --pending-deprecation" $ cat example.js "use strict"; const foo = new Buffer("foo"); $ node example.js (node:7147) [DEP0005] DeprecationWarning: The Buffer() and new Buffer() constructors are not recommended for use due to security and usability concerns. Please use the new Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() construction methods instead. at showFlaggedDeprecation (buffer.js:127:13) at new Buffer (buffer.js:148:3) at Object.使用linters查找有問題的代碼位(/path/to/example.js:2:13) [... more stack trace lines ...]
ESLint規(guī)則no-buffer-constructor或node/no-deprecated-api也查找對不推薦使用的Buffer() API的調(diào)用,這些規(guī)則包含在一些預(yù)設(shè)中。
但是有一個(gè)缺點(diǎn),當(dāng)Buffer被重寫時(shí),它并不總是正確工作,例如使用polyfill,因此建議將此與上述其他方法結(jié)合使用。
變式1:放棄對Node.js ≤4.4.x和5.0.0 - 5.9.x的支持這是目前推薦的解決方案,僅意味著最小的開銷。
自2016年7月以來,Node.js 5.x版本系列一直未得到支持,并且Node.js 4.x版本系列在2018年4月達(dá)到其生命周期結(jié)束(→計(jì)劃)。
這意味著即使出現(xiàn)安全問題,這些版本的Node.js也不會收到任何更新,因此如果可能的話,應(yīng)該避免使用這些版本線。
在這種情況下,你要做的是將所有new Buffer()或Buffer()調(diào)用轉(zhuǎn)換為使用Buffer.alloc()或Buffer.from(),方法如下:
對于new Buffer(number),將其替換為Buffer.alloc(number)。
對于new Buffer(string)(或new Buffer(string, encoding)),將其替換為Buffer.from(string)(或Buffer.from(string, encoding))。
對于所有其他參數(shù)組合(這些更為罕見),還要用Buffer.from(...arguments)替換new Buffer(...arguments)。
請注意,Buffer.alloc()在當(dāng)前Node.js版本上的速度也比new Buffer(size).fill(0)快,這是你需要確保零??填充的原因。
建議啟用ESLint規(guī)則no-buffer-constructor或node/no-deprecated-api以避免意外的不安全Buffer API使用。
還有一個(gè)JSCodeshift codemod,用于自動將Buffer構(gòu)造函數(shù)遷移到Buffer.alloc()或Buffer.from(),請注意,它目前僅適用于參數(shù)為文字或使用兩個(gè)參數(shù)調(diào)用構(gòu)造函數(shù)的情況。
如果你當(dāng)前支持那些較舊的Node.js版本并且無法刪除對它們的支持,或者如果你支持包的舊分支,考慮在較舊的分支上使用變式2或變式3,因此使用這些舊分支的人也將收到修復(fù)。這樣,你將消除由不謹(jǐn)慎的Buffer API使用引起的潛在問題,并且在Node.js 10上運(yùn)行代碼時(shí),你的用戶將不會觀察到運(yùn)行時(shí)棄用警告。
變式2:使用polyfill有三種不同的polyfill可用:
safer-buffer是整個(gè)Buffer API的替代品,在使用new Buffer()時(shí)會拋出。
你將采用與變式1完全相同的步驟,但是在使用新的Buffer API的所有文件中都使用polyfill const Buffer = require("safer-buffer").Buffer。
不要使用舊的new Buffer() API,在添加上面一行的任何文件中,使用舊的new Buffer() API將拋出。
buffer-from和/或buffer-alloc是Buffer API各自部分的ponyfill,你只需添加與你正在使用的API相對應(yīng)的包。
你可以使用適當(dāng)?shù)拿Q導(dǎo)入所需的模塊,例如const bufferFrom = require("buffer-from")然后使用它而不是調(diào)用new Buffer(),例如:new Buffer("test")變?yōu)?b>bufferFrom("test")。
使用這種方法的一個(gè)缺點(diǎn)是從它們遷移出來的代碼更改略多(因?yàn)槟銓⑹褂貌煌Q下的Buffer.from())。
safe-buffer也是整個(gè)Buffer API的替代品,但使用new Buffer()仍然可以像以前一樣工作。
這種方法的缺點(diǎn)是它允許你在代碼中使用較舊的new Buffer() API,這是有問題的,因?yàn)樗赡軙?dǎo)致代碼中出現(xiàn)問題,并將從Node.js 10開始發(fā)出運(yùn)行時(shí)棄用警告(在此處閱讀更多內(nèi)容)。
請注意,在任何一種情況下,你還必須手動刪除對舊Buffer API的所有調(diào)用,只是投入safe-buffer本身并不能解決問題,它只是為新API提供了一個(gè)polyfill,我看到有人犯了這個(gè)錯(cuò)誤。
建議啟用ESLint規(guī)則no-buffer-constructor或node/no-deprecated-api。
放棄對Node.js <4.5.0的支持后,不要忘記刪除polyfill使用。
變式3 - 手動檢測,帶有安全措施如果你只在幾個(gè)地方(例如一個(gè))創(chuàng)建Buffer實(shí)例,或者你有自己的包裝器,這將非常有用。
Buffer(0)這個(gè)用于創(chuàng)建空緩沖區(qū)的特殊情況可以安全地替換為Buffer.concat([]),它返回相同的結(jié)果一直到Node.js 0.8.x。
Buffer(notNumber)之前:
const buf = new Buffer(notNumber, encoding);
以后:
let buf; if (Buffer.from && Buffer.from !== Uint8Array.from) { buf = Buffer.from(notNumber, encoding); } else { if (typeof notNumber === "number") { throw new Error("The "size" argument must be not of type number."); } buf = new Buffer(notNumber, encoding); }
encoding是可選的。
請注意,typeof notNumber必須在new Buffer()之前,(對于notNumber參數(shù)未進(jìn)行硬編碼的情況)并且不是由Buffer構(gòu)造函數(shù)的棄用引起的 - 這正是不推薦使用Buffer構(gòu)造函數(shù)的原因。缺乏此類型檢查的生態(tài)系統(tǒng)包導(dǎo)致了許多安全問題 - 當(dāng)未經(jīng)過處理的用戶輸入可能最終出現(xiàn)在Buffer(arg)中時(shí),會出現(xiàn)從DoS到從進(jìn)程內(nèi)存向攻擊者泄漏敏感信息等問題。
當(dāng)notNumber參數(shù)被硬編碼時(shí)(例如文字"abc"或[0,1,2]),可以省略typeof檢查。
另請注意,使用TypeScript不能解決此問題 - 當(dāng)從JS中使用用TypeScript編寫的庫時(shí),或者當(dāng)用戶輸入結(jié)束時(shí) - 它的行為與純JS一樣,因?yàn)樗蓄愋蜋z查只是轉(zhuǎn)換時(shí)間,并且不存在于TS編譯的實(shí)際JS代碼中。
Buffer(number)對于Node.js 0.10.x(及以下)支持:
var buf; if (Buffer.alloc) { buf = Buffer.alloc(number); } else { buf = new Buffer(number); buf.fill(0); }
否則(Node.js ≥ 0.12.x):
const buf = Buffer.alloc ? Buffer.alloc(number) : new Buffer(number).fill(0);關(guān)于Buffer.allocUnsafe()
使用Buffer.allocUnsafe()時(shí)要格外小心:
如果你沒有充分的理由,請不要使用它。
例如你可能永遠(yuǎn)不會看到小緩沖區(qū)的性能差異,事實(shí)上,使用Buffer.alloc()可能會更快。
如果你的代碼不在熱代碼路徑中 - 你也可能不會注意到差異。
請記住,零填充可以最大限度地降低潛在風(fēng)險(xiǎn)。
如果使用它,請確保永遠(yuǎn)不會以部分填充狀態(tài)返回buffer。
如果你按順序?qū)懰?- 總是將它截?cái)酁閷?shí)際的書寫長度。
處理使用Buffer.allocUnsafe()分配的緩沖區(qū)中的錯(cuò)誤可能會導(dǎo)致各種問題,包括代碼的未定義行為,以及泄露給遠(yuǎn)程攻擊者的敏感數(shù)據(jù)(用戶輸入、密碼、證書)。
請注意,這同樣適用于沒有零填充的new Buffer()用法,具體取決于Node.js版本(缺少類型檢查也會將DoS添加到潛在問題列表中)。
常問問題Buffer構(gòu)造函數(shù)有什么問題?
Buffer構(gòu)造函數(shù)可用于以多種不同方式創(chuàng)建緩沖區(qū):
new Buffer(42)創(chuàng)建一個(gè)42字節(jié)的Buffer,在Node.js 8之前,由于性能原因,此緩沖區(qū)包含任意內(nèi)存,其中可能包括從程序源代碼到密碼和加密密鑰的任何內(nèi)容。
new Buffer("abc")創(chuàng)建一個(gè)Buffer,其中包含字符串"abc"的UTF-8編碼版本,第二個(gè)參數(shù)可以指定另一個(gè)編碼:例如,可以使用new Buffer(string, "base64")將Base64字符串轉(zhuǎn)換為它所代表的原始字節(jié)序列。
還有其他幾種參數(shù)組合。
這意味著在像var buffer = new Buffer(foo);這樣的代碼中,在不知道foo類型的情況下,無法確定生成的緩沖區(qū)的確切內(nèi)容。
有時(shí),foo的值來自外部來源,例如,此函數(shù)可以作為Web服務(wù)器上的服務(wù)公開,將UTF-8字符串轉(zhuǎn)換為其Base64格式:
function stringToBase64(req, res) { // The request body should have the format of `{ string: "foobar" }`. const rawBytes = new Buffer(req.body.string); const encoded = rawBytes.toString("base64"); res.end({ encoded }); }
請注意,此代碼不驗(yàn)證req.body.string的類型:
req.body.string應(yīng)該是一個(gè)字符串,如果是這種情況,一切順利。
req.body.string由發(fā)送請求的客戶端控制。
如果req.body.string是數(shù)字50,則rawBytes將是50個(gè)字節(jié):
在Node.js 8之前,內(nèi)容將是未初始化的。
在Node.js 8之后,內(nèi)容將是50個(gè)字節(jié),值為0。
由于缺少類型檢查,攻擊者可以故意發(fā)送一個(gè)號碼作為請求的一部分,使用它,他們可以:
讀取未初始化的內(nèi)存,這將泄露密碼、加密密鑰和其他類型的敏感信息(信息泄露)。
強(qiáng)制程序分配大量內(nèi)存,例如,當(dāng)指定500000000作為輸入值時(shí),每個(gè)請求將分配500MB的內(nèi)存,這可以用來完全耗盡程序可用的內(nèi)存并使其崩潰,或者顯著減慢程序速度(拒絕服務(wù))。
在現(xiàn)實(shí)世界的Web服務(wù)器環(huán)境中,這兩種情況都被認(rèn)為是嚴(yán)重的安全問題。
當(dāng)使用Buffer.from(req.body.string)時(shí),傳遞一個(gè)數(shù)字將總是拋出一個(gè)異常,提供可由程序始終處理的受控行為。
Buffer()構(gòu)造函數(shù)已被棄用了一段時(shí)間,這真的是一個(gè)問題嗎?npm生態(tài)系統(tǒng)中的代碼調(diào)查表明,Buffer()構(gòu)造函數(shù)仍然被廣泛使用,這包括新代碼,并且此類代碼的總體使用實(shí)際上已經(jīng)增加。
上一篇:Docker化Node.js Web應(yīng)用程序 下一篇:阻塞與非阻塞概述文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/99223.html
Node.js 指南 Node.js?是基于Chrome的V8 JavaScript引擎構(gòu)建的JavaScript運(yùn)行時(shí)。 常規(guī) 關(guān)于Node.js 入門指南 輕松分析Node.js應(yīng)用程序 Docker化Node.js Web應(yīng)用程序 遷移到安全的Buffer構(gòu)造函數(shù) Node.js核心概念 阻塞與非阻塞概述 Node.js事件循環(huán)、定時(shí)器和process.nextTick() 不要阻塞事...
摘要:標(biāo)準(zhǔn)庫中的所有方法都提供非阻塞的異步版本,并接受回調(diào)函數(shù),某些方法還具有對應(yīng)的阻塞方法,其名稱以結(jié)尾。比較代碼阻塞方法同步執(zhí)行,非阻塞方法異步執(zhí)行。 阻塞與非阻塞概述 此概述介紹了Node.js中阻塞與非阻塞調(diào)用之間的區(qū)別,此概述將引用事件循環(huán)和libuv,但不需要事先了解這些主題,假設(shè)讀者對JavaScript語言和Node.js回調(diào)模式有基本的了解。 I/O主要指與libuv支持的...
摘要:化應(yīng)用程序此示例的目的是向你展示如何將應(yīng)用程序放入容器中,該指南旨在用于開發(fā),而不用于生產(chǎn)部署,本指南還假設(shè)你有一個(gè)有效的安裝,并且基本了解應(yīng)用程序的結(jié)構(gòu)。 Docker化Node.js Web應(yīng)用程序 此示例的目的是向你展示如何將Node.js應(yīng)用程序放入Docker容器中,該指南旨在用于開發(fā),而不用于生產(chǎn)部署,本指南還假設(shè)你有一個(gè)有效的Docker安裝,并且基本了解Node.js應(yīng)...
摘要:在數(shù)據(jù)緩沖區(qū)已超過或?qū)懭腙?duì)列當(dāng)前正忙的任何情況下,將返回。當(dāng)返回值時(shí),背壓系統(tǒng)啟動,它會暫停傳入的流發(fā)送任何數(shù)據(jù),并等待消費(fèi)者再次準(zhǔn)備就緒,清空數(shù)據(jù)緩沖區(qū)后,將發(fā)出事件并恢復(fù)傳入的數(shù)據(jù)流。 流中的背壓 在數(shù)據(jù)處理過程中會出現(xiàn)一個(gè)叫做背壓的常見問題,它描述了數(shù)據(jù)傳輸過程中緩沖區(qū)后面數(shù)據(jù)的累積,當(dāng)傳輸?shù)慕邮斩司哂袕?fù)雜的操作時(shí),或者由于某種原因速度較慢時(shí),來自傳入源的數(shù)據(jù)就有累積的趨勢,就像...
摘要:參考文檔是基于的引擎構(gòu)建的運(yùn)行時(shí)。關(guān)于文檔用法和示例斷言測試穩(wěn)定性穩(wěn)定模塊提供了一組簡單的斷言測試,可用于測試不變量。存在和模式,但建議僅使用模式。類在全局作用域內(nèi),因此不太可能需要使用。以下所有示例均可供下載,可用作擴(kuò)展庫的起點(diǎn)。 Node.js v11.5.0 API參考文檔 Node.js?是基于Chrome的V8 JavaScript引擎構(gòu)建的JavaScript運(yùn)行時(shí)。 關(guān)...
閱讀 2139·2021-09-27 14:04
閱讀 1883·2019-08-30 15:55
閱讀 1707·2019-08-30 13:13
閱讀 1076·2019-08-30 13:07
閱讀 2754·2019-08-29 15:20
閱讀 3247·2019-08-29 12:42
閱讀 3345·2019-08-28 17:58
閱讀 3606·2019-08-28 17:56