<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [?]: assets/images/checkbox-small-blue.png # Node.js 最佳實踐 <h1 align="center"> <img src="https://github.com/i0natan/nodebestpractices/blob/master/assets/images/banner-2.jpg" alt="Node.js Best Practices" /> </h1> <br/> <div align="center"> <img src="https://img.shields.io/badge/?%20Item%20count%20-%2073%20Best%20practices-blue.svg" alt="73 items"> <img src="https://img.shields.io/badge/%F0%9F%93%85%20Last%20update%20-%20September%209%202018-green.svg" alt="Last update: September 9th, 2018"> <img src="https://img.shields.io/badge/%E2%9C%94%20Updated%20For%20Version%20-%20Node%208.11.3%20LTS-brightgreen.svg" alt="Updated for Node 8.11.3 LTS"> </div> <br/> [![nodepractices](/assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/) <br/> # 歡迎! 首先您應該知道的三件事情: **1. 當您讀到這里,實際上您讀了很多關于Node.js的優秀文章 -** 這是對Node.js最佳實踐中排名最高的內容的總結和分享 **2. 這里是最大的匯集,且每周都在增長 -** 當前,超過50個最佳實現,樣式指南,架構建議已經呈現。每天都有新的issue和PR被創建,以使這本在線書籍不斷更新。我們很樂于見到您能在這里做出貢獻,不管是修復一些代碼的錯誤,或是提出絕妙的新想法。請查看我們的[milestones](https://github.com/i0natan/nodebestpractices/milestones?direction=asc&sort=due_date&state=open) **3. 大部分的條目包含額外的信息 -** 大部分的最佳實踐條目的旁邊,您將發現 **??Read More** 鏈接,它將呈現給您示例代碼,博客引用和更多信息 <br/><br/><br/> ## [目錄](#table-of-contents) 1. [項目結構實踐 (5) ](#1-project-structure-practices) 2. [異常處理實踐 (11) ](#2-error-handling-practices) 3. [編碼規范實踐 (12) ](#3-code-style-practices) 4. [測試和總體質量實踐 (8) ](#4-testing-and-overall-quality-practices) 5. [進入生產實踐 (16) ](#5-going-to-production-practices) 6. :star: 新: [安全實踐(23)](#6-security-best-practices) 7. Performance Practices ([coming soon](https://github.com/i0natan/nodebestpractices/milestones?direction=asc&sort=due_date&state=open)) <br/><br/><br/> <h1 id="1-project-structure-practices"><code>1. 項目結構實踐</code></h1> ## ![?] 1.1 組件式構建你的解決方案 **TL;DR:** 大型項目的最壞的隱患就是維護一個龐大的,含有幾百個依賴的代碼庫 - 當開發人員準備整合新的需求的時候,這樣一個龐然大物勢必減緩了開發效率。反之,把您的代碼拆分成組件,每一個組件有它自己的文件夾和代碼庫,并且確保每一個組件小而簡單。查看正確的項目結構的例子請訪問下面的 ‘更多’ 鏈接。 **否則:** 當編寫新需求的開發人員逐步意識到他所做改變的影響,并擔心會破壞其他的依賴模塊 - 部署會變得更慢,風險更大。當所有業務邏輯沒有被分開,這也會被認為很難擴展 ?? [**更多: 組件結構**](/sections/projectstructre/breakintcomponents.chinese.md) <br/><br/> ## ![?] 1.2 分層設計組件,保持Express在特定的區域 **TL;DR:** 每一個組件都應該包含'層級' - 一個專注的用于接入網絡,邏輯,數據的概念。這樣不僅獲得一個清晰的分離考量,而且使仿真和測試系統變得異常容易。盡管這是一個普通的模式,但接口開發者易于混淆層級關系,比如把網絡層的對象(Express req, res)傳給業務邏輯和數據層 - 這會令您的應用彼此依賴,并且只能通過Express使用。 **否則:** 對于混淆了網絡層和其它層的應用,將不易于測試,執行CRON的任務,其它非-Express的調用者無法使用 ?? [**更多: 應用分層**](/sections/projectstructre/createlayers.chinese.md) <br/><br/> ## ![?] 1.3 封裝公共模塊成為NPM的包 **TL;DR:** 由大量代碼構成的一個大型應用中,貫徹全局的,比如日志,加密和其它類似的公共組件,應該進行封裝,并暴露成一個私有的NPM包。這將使其在更多的代碼庫和項目中被使用變成了可能。 **否則:** 您將不得不重造部署和依賴的輪子 ?? [**更多: 通過需求構建**](/sections/projectstructre/wraputilities.chinese.md) <br/><br/> ## ![?] 1.4 分離 Express 'app' and 'server' **TL;DR:** 避免定義整個[Express](https://expressjs.com/)應用在一個單獨的大文件里, 這是一個不好的習慣 - 分離您的 'Express' 定義至少在兩個文件中: API聲明(app.js) 和 網絡相關(WWW)。對于更好的結構,是把你的API聲明放在組件中。 **否則:** 您的API將只能通過HTTP的調用進行測試(慢,并且很難產生測試覆蓋報告)。維護一個有著上百行代碼的文件也不是一個令人開心的事情。 ?? [**更多: 分離 Express 'app' and 'server'**](/sections/projectstructre/separateexpress.chinese.md) <br/><br/> ## ![?] 1.5 使用易于設置環境變量,安全和分級的配置 **TL;DR:** 一個完美無瑕的配置安裝應該確保 (a) 元素可以從文件中,也可以從環境變量中讀取 (b) 密碼排除在提交的代碼之外 (c) 為了易于檢索,配置是分級的。僅有幾個包可以滿足這樣的條件,比如[rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf) 和 [config](https://www.npmjs.com/package/config)。 **否則:** 不能滿足任意的配置要求將會使開發,運維團隊,或者兩者,易于陷入泥潭。 ?? [**更多: 配置最佳實踐**](/sections/projectstructre/configguide.chinese.md) <br/><br/><br/> <p align="right"><a href="#table-of-contents">? 返回頂部</a></p> <h1 id="2-error-handling-practices"><code>2. 錯誤處理最佳實踐</code></h1> ## ![?] 2.1 使用 Async-Await 和 promises 用于異步錯誤處理 **TL;DR:** 使用回調的方式處理異步錯誤可能是導致災難的最快的方式(a.k.a the pyramid of doom)。對您的代碼來說,最好的禮物就是使用規范的promise庫或async-await來替代,這會使其像try-catch一樣更加簡潔,具有熟悉的代碼結構。 **否則:** Node.js回調特性, function(err, response), 是導致不可維護代碼的一個必然的方式。究其原因,是由于混合了隨意的錯誤處理代碼,臃腫的內嵌,蹩腳的代碼模式。 ?? [**更多: 避免回調**](/sections/errorhandling/asyncerrorhandling.chinese.md) <br/><br/> ## ![?] 2.2 僅使用內建的錯誤對象 **TL;DR:** 很多人拋出異常使用字符串類型或一些自定義類型 - 這會導致錯誤處理邏輯和模塊間的調用復雜化。是否您reject一個promise,拋出異常或發出(emit)錯誤 - 使用內建的錯誤對象將會增加設計一致性,并防止信息的丟失。 **否則:** 調用某些模塊,將不確定哪種錯誤類型會返回 - 這將會使恰當的錯誤處理更加困難。更壞的情況是,使用特定的類型描述錯誤,會導致重要的錯誤信息缺失,比如stack trace! ?? [**更多: 使用內建錯誤對象**](/sections/errorhandling/useonlythebuiltinerror.chinese.md) <br/><br/> ## ![?] 2.3 區分運行錯誤和程序設計錯誤 **TL;DR:** 運行錯誤(例如, API接受到一個無效的輸入)指的是一些已知場景下的錯誤,這類錯誤的影響已經完全被理解,并能被考慮周全的處理掉。同時,程序設計錯誤(例如,嘗試讀取未定義的變量)指的是未知的編碼問題,影響到應用得當的重啟。 **否則:** 當一個錯誤產生的時候,您總是得重啟應用,但為什么要讓 ~5000 個在線用戶不能訪問,僅僅是因為一個細微的,可以預測的,運行時錯誤?相反的方案,也不完美 – 當未知的問題(程序問題)產生的時候,使應用依舊可以訪問,可能導致不可預測行為。區分兩者會使處理更有技巧,并在給定的上下文下給出一個平衡的對策。 ?? [**更多: 運行錯誤和程序設計錯誤**](/sections/errorhandling/operationalvsprogrammererror.chinese.md) <br/><br/> ## ![?] 2.4 集中處理錯誤,不要在Express中間件中處理錯誤 **TL;DR:** 錯誤處理邏輯,比如給管理員發送郵件,日志應該封裝在一個特定的,集中的對象當中,這樣當錯誤產生的時候,所有的終端(例如 Express中間件,cron任務,單元測試)都可以調用。 **否則:** 錯誤處理的邏輯不放在一起將會導致代碼重復和非常可能不恰當的錯誤處理。 ?? [**更多: 集中處理錯誤**](/sections/errorhandling/centralizedhandling.chinese.md) <br/><br/> ## ![?] 2.5 對API錯誤使用Swagger文檔化 **TL;DR:** 讓你的API調用者知道哪種錯誤會返回,這樣他們就能完全的處理這些錯誤,而不至于系統崩潰。Swagger,REST API的文檔框架,通常處理這類問題。 **否則:** 任何API的客戶端可能決定崩潰并重啟,僅僅因為它收到一個不能處理的錯誤。注意:API的調用者可能是你(在微服務環境中非常典型)。 ?? [**更多: 使用Swagger記錄錯誤**](/sections/errorhandling/documentingusingswagger.chinese.md) <br/><br/> ## ![?] 2.6 當一個特殊的情況產生,停掉服務是得體的 **TL;DR:** 當一個不確定錯誤產生(一個開發錯誤,最佳實踐條款#3) - 這就意味著對應用運轉健全的不確定。一個普通的實踐將是建議仔細地重啟進程,并使用一些‘啟動器’工具,比如Forever和PM2。 **否則:** 當一個未知的異常被拋出,意味著某些對象包含錯誤的狀態(例如某個全局事件發生器由于某些內在的錯誤,不在產生事件),未來的請求可能失敗或者行為異常。 ?? [**更多: 停掉服務**](/sections/errorhandling/shuttingtheprocess.chinese.md) <br/><br/> ## ![?] 2.7 使用一個成熟的日志工具提高錯誤的可見性 **TL;DR:** 一系列成熟的日志工具,比如Winston,Bunyan和Log4J,會加速錯誤的發現和理解。忘記console.log吧。 **否則:** 瀏覽console的log,和不通過查詢工具或者一個好的日志查看器,手動瀏覽繁瑣的文本文件,會使你忙于工作到很晚。 ?? [**更多: 使用好用的日志工具**](/sections/errorhandling/usematurelogger.chinese.md) <br/><br/> ## ![?] 2.8 使用你最喜歡的測試框架測試錯誤流 **TL;DR:** 無論專業的自動化測試或者簡單的手動開發測試 - 確保您的代碼不僅滿足正常的場景,而且處理并且返回正確的錯誤。測試框架,比如Mocha & Chai可以非常容易的處理這些問題(在"Gist popup"中查看代碼實例) 。 **否則:** 沒有測試,不管自動還是手動,您不可能依賴代碼去返回正確的錯誤。而沒有可以理解的錯誤,那將毫無錯誤處理可言。 ?? [**更多: 測試錯誤流向**](/sections/errorhandling/testingerrorflows.chinese.md) <br/><br/> ## ![?] 2.9 使用APM產品發現錯誤和宕機時間 **TL;DR:** 監控和性能產品 (別名 APM) 先前一步的檢測您的代碼庫和API,這樣他們能自動的,像使用魔法一樣的強調錯誤,宕機和您忽略的性能慢的部分。 **否則:** 您花了很多的力氣在測量API的性能和錯誤,但可能您從來沒有意識到真實場景下您最慢的代碼塊和他們對UX的影響。 ?? [**更多: 使用APM產品**](/sections/errorhandling/apmproducts.chinese.md) <br/><br/> ## ![?] 2.10 捕獲未處理的promise rejections **TL;DR:** 任何在promise中被拋出的異常將被收回和遺棄,除非開發者沒有忘記去明確的處理。即使您的代碼調用的是process.uncaughtException!解決這個問題可以注冊到事件process.unhandledRejection。 **否則:** 您的錯誤將被回收,無蹤跡可循。沒有什么可以需要考慮。 ?? [**更多: 捕獲未處理的promise rejection**](/sections/errorhandling/catchunhandledpromiserejection.chinese.md) <br/><br/> ## ![?] 2.11 快速查錯,驗證參數使用一個專門的庫Fail fast, validate arguments using a dedicated library **TL;DR:** 這應該是您的Express最佳實踐中的一部分 – assert API輸入避免難以理解的漏洞,這類漏洞以后會非常難以追蹤。而驗證代碼通常是一件乏味的事情,除非使用一些非常炫酷的幫助庫比如Joi。 **否則:** 考慮這種情況 – 您的功能期望一個數字參數 “Discount” ,然而調用者忘記傳值,之后在您的代碼中檢查是否 Discount!=0 (允許的折扣值大于零),這樣它將允許用戶使用一個折扣。OMG,多么不爽的一個漏洞。你能明白嗎? ?? [**更多: 快速查錯**](/sections/errorhandling/failfast.chinese.md) <br/><br/><br/> <p align="right"><a href="#table-of-contents">? 返回頂部</a></p> <h1 id="3-code-style-practices"><code>3. 編碼風格實踐</code></h1> ## ![?] 3.1 使用ESLint **TL;DR:** [ESLint](https://eslint.org)是檢查可能的代碼錯誤和修復代碼樣式的事實上的標準,不僅可以識別實際的間距問題, 而且還可以檢測嚴重的反模式代碼, 如開發人員在不分類的情況下拋出錯誤。盡管ESlint可以自動修復代碼樣式,但其他的工具比如[prettier](https://www.npmjs.com/package/prettier)和[beautify](https://www.npmjs.com/package/js-beautify)在格式化修復上功能強大,可以和Eslint結合起來使用。 **否則:** 開發人員將必須關注單調乏味的間距和線寬問題, 并且時間可能會浪費在過多考慮項目的代碼樣式。 <br/><br/> ## ![?] 3.2 Node.js特定的插件 **TL;DR:** 除了僅僅涉及 vanilla JS 的 ESLint 標準規則,添加 Node 相關的插件,比如[eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) and [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security) **否則:** 許多錯誤的Node.js代碼模式可能在檢測下逃生。例如,開發人員可能需要某些文件,把一個變量作為路徑名 (variableAsPath) ,這會導致攻擊者可以執行任何JS腳本。Node.JS linters可以檢測這類模式,并及早預警。 <br/><br/> ## ![?] 3.3 在同一行開始一個代碼塊的大括號 **TL;DR:** 代碼塊的第一個大括號應該和聲明的起始保持在同一行中。 ### 代碼示例 ```javascript // 建議 function someFunction() { // 代碼塊 } // 避免 function someFunction { // 代碼塊 } ``` **否則:** 不遵守這項最佳實踐可能導致意外的結果,在Stackoverflow的帖子中可以查看到,如下: ?? [**更多:** "Why does a results vary based on curly brace placement?" (Stackoverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement) <br/><br/> ## ![?] 3.4 不要忘記分號 **TL;DR:** 即使沒有獲得一致的認同,但在每一個表達式后面放置分號還是值得推薦的。這將使您的代碼, 對于其他閱讀代碼的開發者來說,可讀性,明確性更強。 **否則:** 在前面的章節里面已經提到,如果表達式的末尾沒有添加分號,JavaScript的解釋器會在自動添加一個,這可能會導致一些意想不到的結果。 <br/><br/> ## ![?] 3.5 命名您的方法 **TL;DR:** 命名所有的方法,包含閉包和回調, 避免匿名方法。當剖析一個node應用的時候,這是特別有用的。命名所有的方法將會使您非常容易的理解內存快照中您正在查看的內容。 **否則:** 使用一個核心dump(內存快照)調試線上問題,會是一項非常挑戰的事項,因為你注意到的嚴重內存泄漏問題極有可能產生于匿名的方法。 <br/><br/> ## ![?] 3.6 變量、常量、函數和類的命名約定 **TL;DR:** 當命名變量和方法的時候,使用 ***lowerCamelCase*** ,當命名類的時候,使用 ***UpperCamelCase*** (首字母大寫),對于常量,則 ***UPPERCASE*** 。這將幫助您輕松地區分普通變量/函數和需要實例化的類。使用描述性名稱,但使它們盡量簡短。 **否則:** JavaScript是世界上唯一一門不需要實例化,就可以直接調用構造函數("Class")的編碼語言。因此,類和函數的構造函數由采用UpperCamelCase開始區分。 ### 代碼示例 ### ```javascript // 使用UpperCamelCase命名類名 class SomeClassExample () { // 常量使用const關鍵字,并使用lowerCamelCase命名 const config = { key: 'value' }; // 變量和方法使用lowerCamelCase命名 let someVariableExample = 'value'; function doSomething() { } } ``` <br/><br/> ## ![?] 3.7 使用const優于let,廢棄var **TL;DR:** 使用`const`意味著一旦一個變量被分配,它不能被重新分配。使用const將幫助您免于使用相同的變量用于不同的用途,并使你的代碼更清晰。如果一個變量需要被重新分配,以在一個循環為例,使用`let`聲明它。let的另一個重要方面是,使用let聲明的變量只在定義它的塊作用域中可用。 `var`是函數作用域,不是塊級作用域,既然您有const和let讓您隨意使用,那么[不應該在ES6中使用var](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70)。 **否則:** 當經常更改變量時,調試變得更麻煩了。 ?? [**更多: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75) <br/><br/> ## ![?] 3.8 先require, 而不是在方法內部 **TL;DR:** 在每個文件的起始位置,在任何函數的前面和外部require模塊。這種簡單的最佳實踐,不僅能幫助您輕松快速地在文件頂部辨別出依賴關系,而且避免了一些潛在的問題。 **否則:** 在Node.js中,require 是同步運行的。如果從函數中調用它們,它可能會阻塞其他請求,在更關鍵的時間得到處理。另外,如果所require的模塊或它自己的任何依賴項拋出錯誤并使服務器崩潰,最好盡快查明它,如果該模塊在函數中require的,則可能不是這樣的情況。 <br/><br/> ## ![?] 3.9 在文件夾上 require ,而不是直接在文件上 **TL;DR:** 當在一個文件夾中開發庫/模塊,放置一個文件index.js暴露模塊的 內部,這樣每個消費者都會通過它。這將作為您模塊的一個接口,并使未來的變化簡單而不違反規則。 **否則:** 更改文件內部結構或簽名可能會破壞與客戶端的接口。 ### 代碼示例 ```javascript // 建議 module.exports.SMSProvider = require('./SMSProvider'); module.exports.SMSNumberResolver = require('./SMSNumberResolver'); // 避免 module.exports.SMSProvider = require('./SMSProvider/SMSProvider.js'); module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolver.js'); ``` <br/><br/> ## ![?] 3.10 使用 `===` 操作符 **TL;DR:** 對比弱等于 `==`,優先使用嚴格的全等于 `===` 。`==`將在它們轉換為普通類型后比較兩個變量。在 `===` 中沒有類型轉換,并且兩個變量必須是相同的類型。 **否則:** 與 `==` 操作符比較,不相等的變量可能會返回true。 ### 代碼示例 ```javascript '' == '0' // false 0 == '' // true 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true ' \t\r\n ' == 0 // true ``` 如果使用`===`, 上面所有語句都將返回 false。 <br/><br/> ## ![?] 3.11 使用 Async Await, 避免回調 **TL;DR:** Node 8 LTS現已全面支持異步等待。這是一種新的方式處理異步請求,取代回調和promise。Async-await是非阻塞的,它使異步代碼看起來像是同步的。您可以給你的代碼的最好的禮物是用async-await提供了一個更緊湊的,熟悉的,類似try catch的代碼語法。 **否則:** 使用回調的方式處理異步錯誤可能是陷入困境最快的方式 - 這種方式必須面對不停地檢測錯誤,處理別扭的代碼內嵌,難以推理編碼流。 ??[**更多:** async await 1.0 引導](https://github.com/yortus/asyncawait) <br/><br/> ## ![?] 3.12 使用 (=>) 箭頭函數 **TL;DR:** 盡管使用 async-await 和避免方法作為參數是被推薦的, 但當處理那些接受promise和回調的老的API的時候 - 箭頭函數使代碼結構更加緊湊,并保持了根方法上的語義上下文 (例如 'this')。 **否則:** 更長的代碼(在ES5方法中)更易于產生缺陷,并讀起來很是笨重。 ?? [**更多: 這是擁抱箭頭函數的時刻**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75) <br/><br/><br/> <p align="right"><a href="#table-of-contents">? 返回頂部</a></p> <h1 id="4-testing-and-overall-quality-practices"><code>4. 測試和總體的質量實踐</code></h1> ## ![?] 4.1 至少,編寫API(組件)測試 **TL;DR:** 大多數項目只是因為時間表太短而沒有進行任何自動化測試,或者測試項目失控而正被遺棄。因此,優先從API測試開始,這是最簡單的編寫和提供比單元測試更多覆蓋率的事情(你甚至可能不需要編碼而進行API測試,像[Postman](https://www.getpostman.com/)。之后,如果您有更多的資源和時間,繼續使用高級測試類型,如單元測試、DB測試、性能測試等。 **否則:** 您可能需要花很長時間編寫單元測試,才發現只有20%的系統覆蓋率。 <br/><br/> ## ![?] 4.2 使用一個linter檢測代碼問題 **TL;DR:** 使用代碼linter檢查基本質量并及早檢測反模式。在任何測試之前運行它, 并將其添加為預提交的git鉤子, 以最小化審查和更正任何問題所需的時間。也可在[Section 3](https://github.com/i0natan/nodebestpractices#3-code-style-practices)中查閱編碼樣式實踐 **否則:** 您可能讓一些反模式和易受攻擊的代碼傳遞到您的生產環境中。 <br/><br/> ## ![?] 4.3 仔細挑選您的持續集成(CI)平臺 **TL;DR:** 您的持續集成平臺(cicd)將集成各種質量工具(如測試、lint),所以它應該是一個充滿活力的生態系統,包含各種插件。[jenkins](https://jenkins.io/)曾經是許多項目的默認選項,因為它有最大的社區,同時也是一個非常強大的平臺,這樣的代價是要求一個陡峭的學習曲線。如今,使用SaaS工具,比如[CircleCI](https://circleci.com)及其他,安裝一套CI解決方案,相對是一件容易的事情。這些工具允許構建靈活的CI管道,而無需管理整個基礎設施。最終,這是一個魯棒性和速度之間的權衡 - 仔細選擇您支持的方案。 **否則:** 一旦您需要一些高級定制,選擇一些細分市場供應商可能會讓您停滯不前。另一方面,伴隨著jenkins,可能會在基礎設施設置上浪費寶貴的時間。 ?? [**更多: 挑選 CI 平臺**](/sections/testingandquality/citools.chinese.md) <br/><br/> ## ![?] 4.4 經常檢查易受攻擊的依賴 **TL;DR:** 即使是那些最有名的依賴模塊,比如Express,也有已知的漏洞。使用社區和商業工具,比如 ?? [npm audit](https://docs.npmjs.com/cli/audit) ,集成在您的CI平臺上,在每一次構建的時候都會被調用,這樣可以很容易地解決漏洞問題。 **否則:** 在沒有專用工具的情況下,使代碼清除漏洞,需要不斷地跟蹤有關新威脅的在線出版物,相當繁瑣。 <br/><br/> ## ![?] 4.5 測試標簽化 **TL;DR:** 不同的測試必須運行在不同的情景:quick smoke,IO-less,當開發者保存或提交一個文件,測試應該啟動;完整的端到端的測試通常運行在一個新的pull request被提交之后,等等。這可以通過對測試用例設置標簽,比如關鍵字像#cold #api #sanity,來完成。這樣您可以對您的測試集進行grep,調用需要的子集。例如,這就是您通過[Mocha](https://mochajs.org/)僅僅調用sanity測試集所需要做的:mocha --grep 'sanity'。 **否則:** 運行所有的測試,包括執行數據庫查詢的幾十個測試,任何時候開發者進行小的改動都可能很慢,這使得開發者不愿意運行測試。 <br/><br/> ## ![?] 4.6 檢查測試覆蓋率,它有助于識別錯誤的測試模式 **TL;DR:** 代碼覆蓋工具比如[Istanbul/NYC ](https://github.com/gotwarlost/istanbul),很好用有3個原因:它是免費的(獲得這份報告不需要任何開銷),它有助于確定測試覆蓋率降低的部分,以及最后但非最不重要的是它指出了測試中的不匹配:通過查看顏色標記的代碼覆蓋報告您可以注意到,例如,從來不會被測到的代碼片段像catch語句(即測試只是調用正確的路徑,而不調用應用程序發生錯誤時的行為)。如果覆蓋率低于某個閾值,則將其設置為失敗的構建。 **否則:** 當你的大部分代碼沒有被測試覆蓋時,就不會有任何自動化的度量指標告訴你了。 <br/><br/> ## ![?] 4.7 檢查過期的依賴包 **TL;DR:** 使用您的首選工具 (例如 “npm outdated” or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) 來檢測已安裝的過期依賴包, 將此檢查注入您的 CI 管道, 甚至在嚴重的情況下使構建失敗。例如, 當一個已安裝的依賴包滯后5個補丁時 (例如:本地版本是1.3.1 的, 存儲庫版本是1.3.8 的), 或者它被其作者標記為已棄用, 可能會出現嚴重的情況 - 停掉這次構建并防止部署此版本。 **否則:** 您的生產環境將運行已被其作者明確標記為有風險的依賴包 <br/><br/> ## ![?] 4.8 對于e2e testing,使用docker-compose **TL;DR:** 端對端(e2e)測試包含現場數據,由于它依賴于很多重型服務如數據庫,習慣被認為是CI過程中最薄弱的環節。Docker-compose通過制定類似生產的環境,并使用一個簡單的文本文件和簡單的命令,輕松化解了這個問題。它為了e2e測試,允許制作所有相關服務,數據庫和隔離網絡。最后但并非最不重要的一點是,它可以保持一個無狀態環境,該環境在每個測試套件之前被調用,然后立即消失。 **否則:** 沒有docker-compose,團隊必須維護一個測試數據庫在每一個測試環境上,包含開發機器,保持所有數據同步,這樣測試結果不會因環境不同而不同。 <br/><br/><br/> <p align="right"><a href="#table-of-contents">? 返回頂部</a></p> <h1 id="5-going-to-production-practices"><code>5. 上線實踐</code></h1> ## ![?] 5.1. 監控! **TL;DR:** 監控是一種在顧客之前發現問題的游戲 – 顯然這應該被賦予前所未有的重要性。考慮從定義你必須遵循的基本度量標準開始(我的建議在里面),到檢查附加的花哨特性并選擇解決所有問題的解決方案。市場已經淹沒其中。點擊下面的 ‘The Gist’ ,了解解決方案的概述。 **否則:** 錯誤 === 失望的客戶. 非常簡單. ?? [**更多: 監控!**](/sections/production/monitoring.chinese.md) <br/><br/> ## ![?] 5.2. 使用智能日志增加透明度 **TL;DR:** 日志可以是調試語句的一個不能說話的倉庫,或者表述應用運行過程的一個漂亮儀表板的驅動。從第1天計劃您的日志平臺:如何收集、存儲和分析日志,以確保所需信息(例如,錯誤率、通過服務和服務器等完成整個事務)都能被提取出來。 **否則:** 您最終像是面對一個黑盒,不知道發生了什么事情,然后你開始重新寫日志語句添加額外的信息。 ?? [**更多: 使用智能日志增加透明度**](/sections/production/smartlogging.chinese.md) <br/><br/> ## ![?] 5.3. 委托可能的一切(例如:gzip,SSL)給反向代理 **TL;DR:** Node處理CPU密集型任務,如gzipping,SSL termination等,表現糟糕。相反,使用一個 ‘真正’ 的中間件服務像Nginx,HAProxy或者云供應商的服務。 **否則:** 可憐的單線程Node將不幸地忙于處理網絡任務,而不是處理應用程序核心,性能會相應降低。 ?? [**更多: 委托可能的一切(例如:gzip,SSL)給反向代理**](/sections/production/delegatetoproxy.chinese.md) <br/><br/> ## ![?] 5.4. 鎖住依賴 **TL;DR:** 您的代碼必須在所有的環境中是相同的,但是令人驚訝的是,NPM默認情況下會讓依賴在不同環境下發生偏移 – 當在不同的環境中安裝包的時候,它試圖拿包的最新版本。克服這種問題可以利用NPM配置文件, .npmrc,告訴每個環境保存準確的(不是最新的)包的版本。另外,對于更精細的控制,使用NPM “shrinkwrap”。*更新:作為NPM5,依賴默認鎖定。新的包管理工具,Yarn,也默認鎖定。 **否則:** QA測試通過的代碼和批準的版本,在生產中表現不一致。更糟糕的是,同一生產集群中的不同服務器可能運行不同的代碼。 ?? [**更多: 鎖住依賴**](/sections/production/lockdependencies.chinese.md) <br/><br/> ## ![?] 5.5. 使用正確的工具保護進程正常運行 **TL;DR:** 進程必須繼續運行,并在失敗時重新啟動。對于簡單的情況下,“重啟”工具如PM2可能足夠,但在今天的“Dockerized”世界 – 集群管理工具也值得考慮 **否則:** 運行幾十個實例沒有明確的戰略和太多的工具(集群管理,docker,PM2)可能導致一個DevOps混亂 ?? [**更多: 使用正確的工具保護進程正常運行**](/sections/production/guardprocess.chinese.md) <br/><br/> ## ![?] 5.6. 利用CPU多核 **TL;DR:** 在基本形式上,node應用程序運行在單個CPU核心上,而其他都處于空閑狀態。復制node進程和利用多核,這是您的職責 – 對于中小應用,您可以使用Node Cluster和PM2. 對于一個大的應用,可以考慮使用一些Docker cluster(例如k8s,ECS)復制進程或基于Linux init system(例如systemd)的部署腳本 **否則:** 您的應用可能只是使用了其可用資源中的25% (!),甚至更少。注意,一臺典型的服務器有4個或更多的CPU,默認的Node.js部署僅僅用了一個CPU(甚至使用PaaS服務,比如AWS beanstalk,也一樣)。 ?? [**更多: 利用所有的CPU**](/sections/production/utilizecpu.chinese.md) <br/><br/> ## ![?] 5.7. 創建一個“維護端點” **TL;DR:** 在一個安全的API中暴露一組系統相關的信息,比如內存使用情況和REPL等等。盡管這里強烈建議依賴標準和作戰測試工具,但一些有價值的信息和操作更容易使用代碼完成。 **否則:** 您會發現,您正在執行許多“診斷部署” – 將代碼發送到生產中,僅僅只為了診斷目的提取一些信息。 ?? [**更多: 創建一個 '維護端點'**](/sections/production/createmaintenanceendpoint.chinese.md) <br/><br/> ## ![?] 5.8. 使用APM產品發現錯誤和宕機時間 **TL;DR:** 監控和性能的產品(即APM)先前一步地評估代碼庫和API,自動的超過傳統的監測,并測量在服務和層級上的整體用戶體驗。例如,一些APM產品可以突顯導致最終用戶負載過慢的事務,同時指出根本原因。 **否則:** 你可能會花大力氣測量API性能和停機時間,也許你永遠不會知道,真實場景下哪個是你最慢的代碼部分,這些怎么影響用戶體驗。 ?? [**更多: 使用APM產品發現錯誤和宕機時間**](/sections/production/apmproducts.chinese.md) <br/><br/> ## ![?] 5.9. 使您的代碼保持生產環境就緒 **TL;DR:** 在意識中抱著最終上線的想法進行編碼,從第1天開始計劃上線。這聽起來有點模糊,所以我編寫了一些與生產維護密切相關的開發技巧(點擊下面的要點) **否則:** 一個世界冠軍級別的IT/運維人員也不能拯救一個編碼低劣的系統。 ?? [**更多: 使您的代碼保持生產環境就緒**](/sections/production/productoncode.chinese.md) <br/><br/> ## ![?] 5.10. 測量和保護內存使用 **TL;DR:** Node.js和內存有引起爭論的聯系:V8引擎對內存的使用有稍微的限制(1.4GB),在node的代碼里面有內存泄漏的很多途徑 – 因此監視node的進程內存是必須的。在小應用程序中,你可以使用shell命令周期性地測量內存,但在中等規模的應用程序中,考慮把內存監控建成一個健壯的監控系統。 **否則:** 您的內存可能一天泄漏一百兆,就像曾發生在沃爾瑪的一樣。 ?? [**更多: 測量和保護內存使用**](/sections/production/measurememory.chinese.md) <br/><br/> ## ![?] 5.11. Node外管理您的前端資源 **TL;DR:** 使用專門的中間件(nginx,S3,CDN)服務前端內容,這是因為在處理大量靜態文件的時候,由于node的單線程模型,它的性能很受影響。 **否則:** 您的單個node線程將忙于傳輸成百上千的html/圖片/angular/react文件,而不是分配其所有的資源為了其擅長的任務 – 服務動態內容 ?? [**更多: Node外管理您的前端資源**](/sections/production/frontendout.chinese.md) <br/><br/> ## ![?] 5.12. 保持無狀態,幾乎每天都要停下服務器 **TL;DR:** 在外部數據存儲上,存儲任意類型數據(例如用戶會話,緩存,上傳文件)。考慮間隔地停掉您的服務器或者使用 ‘serverless’ 平臺(例如 AWS Lambda),這是一個明確的強化無狀態的行為。 **否則:** 某個服務器上的故障將導致應用程序宕機,而不僅僅是停用故障機器。此外,由于依賴特定服務器,伸縮彈性會變得更具挑戰性。 ?? [**更多: 保持無狀態,幾乎每天都要停下服務器**](/sections/production/bestateless.chinese.md) <br/><br/> ## ![?] 5.13. 使用自動檢測漏洞的工具 **TL;DR:** 即使是最有信譽的依賴項,比如Express,會有使系統處于危險境地的已知漏洞(隨著時間推移)。通過使用社區的或者商業工具,不時的檢查漏洞和警告(本地或者Github上),這類問題很容易被抑制,有些問題甚至可以立即修補。 **否則:** 否則: 在沒有專用工具的情況下,使代碼清除漏洞,需要不斷地跟蹤有關新威脅的在線出版物。相當繁瑣。 ?? [**更多: 使用自動檢測漏洞的工具**](/sections/production/detectvulnerabilities.chinese.md) <br/><br/> ## ![?] 5.14. 在每一個log語句中指明 ‘TransactionId’ **TL;DR:** 在每一個請求的每一條log入口,指明同一個標識符,transaction-id: {某些值}。然后在檢查日志中的錯誤時,很容易總結出前后發生的事情。不幸的是,由于Node異步的天性自然,這是不容易辦到的,看下代碼里面的例子 **否則:** 在沒有上下文的情況下查看生產錯誤日志,這會使問題變得更加困難和緩慢去解決。 ?? [**更多: 在每一個log語句中指明 ‘TransactionId’**](/sections/production/assigntransactionid.chinese.md) <br/><br/> ## ![?] 5.15. 設置NODE_ENV=production **TL;DR:** 設置環境變量NODE_ENV為‘production’ 或者 ‘development’,這是一個是否激活上線優化的標志 - 很多NPM的包通過它來判斷當前的環境,據此優化生產環境代碼。 **否則:** 遺漏這個簡單的屬性可能大幅減弱性能。例如,在使用Express作為服務端渲染頁面的時候,如果未設置NODE_ENV,性能將會減慢大概三分之一! ?? [**更多: 設置NODE_ENV=production**](/sections/production/setnodeenv.chinese.md) <br/><br/> ## ![?] 5.16. 設計自動化、原子化和零停機時間部署 **TL;DR:** 研究表明,執行許多部署的團隊降低了嚴重上線問題的可能性。不需要危險的手動步驟和服務停機時間的快速和自動化部署大大改善了部署過程。你應該達到使用Docker結合CI工具,使他們成為簡化部署的行業標準。 **否則:** 長時間部署 -> 線上宕機 & 和人相關的錯誤 -> 團隊部署時不自信 -> 更少的部署和需求 <br/><br/><br/> <p align="right"><a href="#table-of-contents">? 返回頂部</a></p> <h1 id="6-security-best-practices"><code>6. 安全最佳實踐</code></h1> <div align="center"> <img src="https://img.shields.io/badge/OWASP%20Threats-Top%2010-green.svg" alt="53 items"/> </div> ## ![?] 6.1. 擁護linter安全準則 <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20XSS%20-green.svg" alt=""/></a> **TL;DR:** 使用安全相關的linter插件,比如[eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security),盡早捕獲安全隱患或者問題,最好在編碼階段。這能幫助察覺安全的問題,比如使用eval,調用子進程,或者根據字面含義(比如,用戶輸入)引入模塊等等。點擊下面‘更多’獲得一個安全linter可以檢測到的代碼示例。 **Otherwise:** 在開發過程中, 可能一個直白的安全隱患, 成為生產環境中一個嚴重問題。此外, 項目可能沒有遵循一致的安全規范, 而導致引入漏洞, 或敏感信息被提交到遠程倉庫中。 ?? [**更多: Lint 規范**](/sections/security/lintrules.md) <br/><br/> ## ![?] 6.2. 使用中間件限制并發請求 <a href="https://www.owasp.org/index.php/Denial_of_Service" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg" alt=""/></a> **TL;DR:** DOS攻擊非常流行而且相對容易處理。使用外部服務,比如cloud負載均衡, cloud防火墻, nginx, 或者(對于小的,不是那么重要的app)一個速率限制中間件(比如[express-rate-limit](https://www.npmjs.com/package/express-rate-limit)),來實現速率限制。 **否則:** 應用程序可能受到攻擊, 導致拒絕服務, 在這種情況下, 真實用戶會遭受服務降級或不可用。 ?? [**更多: 實施速率限制**](/sections/security/limitrequests.md) <br/><br/> ## ![?] 6.3 把機密信息從配置文件中抽離出來,或者使用包對其加密 <a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A3:Sensitive%20Data%20Exposure%20-green.svg" alt=""/></a> **TL;DR:** 不要在配置文件或源代碼中存儲純文本機密信息。相反, 使用諸如Vault產品、Kubernetes/Docker Secrets或使用環境變量之類的安全管理系統。最后一個結果是, 存儲在源代碼管理中的機密信息必須進行加密和管理 (滾動密鑰(rolling keys)、過期時間、審核等)。使用pre-commit/push鉤子防止意外提交機密信息。 **否則:** 源代碼管理, 即使對于私有倉庫, 也可能會被錯誤地公開, 此時所有的秘密信息都會被公開。外部組織的源代碼管理的訪問權限將無意中提供對相關系統 (數據庫、api、服務等) 的訪問。 ?? [**更多: 安全管理**](/sections/security/secretmanagement.md) <br/><br/> ## ![?] 6.4. 使用 ORM/ODM 庫防止查詢注入漏洞 <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> **TL;DR:** 要防止 SQL/NoSQL 注入和其他惡意攻擊, 請始終使用 ORM/ODM 或database庫來轉義數據或支持命名的或索引的參數化查詢, 并注意驗證用戶輸入的預期類型。不要只使用JavaScript模板字符串或字符串串聯將值插入到查詢語句中, 因為這會將應用程序置于廣泛的漏洞中。所有知名的Node.js數據訪問庫(例如[Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose))包含對注入漏洞的內置包含措施。 **否則:** 未經驗證或未脫敏處理的用戶輸入,可能會導致操作員在使用MongoDB進行NoSQL操作時進行注入, 而不使用適當的過濾系統或ORM很容易導致SQL注入攻擊, 從而造成巨大的漏洞。 ?? [**更多: 使用 ORM/ODM 庫防止查詢注入**](/sections/security/ormodmusage.md) <br/><br/> ## ![?] 6.5. 通用安全最佳實際集合 **TL;DR:** 這些是與Node.js不直接相關的安全建議的集合-Node的實現與任何其他語言沒有太大的不同。單擊 "閱讀更多" 瀏覽。 ?? [**更多: 通用安全最佳實際**](/sections/security/commonsecuritybestpractices.md) <br/><br/> ## ![?] 6.6. 調整 HTTP 響應頭以加強安全性 <a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a> **TL;DR:** 應用程序應該使用安全的header來防止攻擊者使用常見的攻擊方式,諸如跨站點腳本(XSS)、點擊劫持和其他惡意攻擊。可以使用模塊,比如 [helmet](https://www.npmjs.com/package/helmet)輕松進行配置。 **否則:** 攻擊者可以對應用程序的用戶進行直接攻擊, 導致巨大的安全漏洞 ?? [**更多: 在應用程序中使用安全的header**](/sections/security/secureheaders.md) <br/><br/> ## ![?] 6.7. 經常自動檢查易受攻擊的依賴庫 <a href="https://www.owasp.org/index.php/Top_10-2017_A9-Using_Components_with_Known_Vulnerabilities" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Known%20Vulnerabilities%20-green.svg" alt=""/></a> **TL;DR:** 在npm的生態系統中, 一個項目有許多依賴是很常見的。在找到新的漏洞時, 應始終將依賴項保留在檢查中。使用工具,類似于[npm audit](https://docs.npmjs.com/cli/audit) 或者 [snyk](https://snyk.io/)跟蹤、監視和修補易受攻擊的依賴項。將這些工具與 CI 設置集成, 以便在將其上線之前捕捉到易受攻擊的依賴庫。 **否則:** 攻擊者可以檢測到您的web框架并攻擊其所有已知的漏洞。 ?? [**更多: 安全依賴**](/sections/security/dependencysecurity.md) <br/><br/> ## ![?] 6.8. 避免使用Node.js的crypto庫處理密碼,使用Bcrypt <a href="https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg" alt=""/></a> **TL;DR:** 密碼或機密信息(API密鑰)應該使用安全的哈希+salt函數(如 "bcrypt")來存儲, 因為性能和安全原因, 這應該是其JavaScript實現的首選。 **否則:** 在不使用安全功能的情況下,保存的密碼或秘密信息容易受到暴力破解和字典攻擊, 最終會導致他們的泄露。 ?? [**更多: 使用Bcrypt**](/sections/security/bcryptpasswords.chinese.md) <br/><br/> ## ![?] 6.9. 轉義 HTML、JS 和 CSS 輸出 <a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a> **TL;DR:** 發送給瀏覽器的不受信任數據可能會被執行, 而不是顯示, 這通常被稱為跨站點腳本(XSS)攻擊。使用專用庫將數據顯式標記為不應執行的純文本內容(例如:編碼、轉義),可以減輕這種問題。 **否則:** 攻擊者可能會將惡意的JavaScript代碼存儲在您的DB中, 然后將其發送給可憐的客戶端。 ?? [**更多: 轉義輸出**](/sections/security/escape-output.md) <br/><br/> ## ![?] 6.10. 驗證傳入的JSON?schemas <a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7: XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg" alt=""/></a> **TL;DR:** 驗證傳入請求的body payload,并確保其符合預期要求, 如果沒有, 則快速報錯。為了避免每個路由中繁瑣的驗證編碼, 您可以使用基于JSON的輕量級驗證架構,比如[jsonschema](https://www.npmjs.com/package/jsonschema) or [joi](https://www.npmjs.com/package/joi) **否則:** 您疏忽和寬松的方法大大增加了攻擊面, 并鼓勵攻擊者嘗試許多輸入, 直到他們找到一些組合, 使應用程序崩潰。 ?? [**更多: 驗證傳人的JSON schemas**](/sections/security/validation.md) <br/><br/> ## ![?] 6.11. 支持黑名單的JWT <a href="https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg" alt=""/></a> **TL;DR:** 當使用JSON Web Tokens(例如, 通過[Passport.js](https://github.com/jaredhanson/passport)), 默認情況下, 沒有任何機制可以從發出的令牌中撤消訪問權限。一旦發現了一些惡意用戶活動, 只要它們持有有效的標記, 就無法阻止他們訪問系統。通過實現一個不受信任令牌的黑名單,并在每個請求上驗證,來減輕此問題。 **否則:** 過期或錯誤的令牌可能被第三方惡意使用,以訪問應用程序,并模擬令牌的所有者。 ?? [**更多: 為JSON Web Token添加黑名單**](/sections/security/expirejwt.md) <br/><br/> ## ![?] 6.12. 限制每個用戶允許的登錄請求 <a href="https://www.owasp.org/index.php/Top_10-2017_A2-Broken_Authentication" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A9:Broken%20Authentication%20-green.svg" alt=""/></a> **TL;DR:** 一類保護暴力破解的中間件,比如[express-brute](https://www.npmjs.com/package/express-brute),應該被用在express的應用中,來防止暴力/字典攻擊;這類攻擊主要應用于一些敏感路由,比如/admin 或者 /login,基于某些請求屬性, 如用戶名, 或其他標識符, 如正文參數等。 **否則:** 攻擊者可以發出無限制的密碼匹配嘗試, 以獲取對應用程序中特權帳戶的訪問權限。 ?? [**更多: 限制登錄頻率**](/sections/security/login-rate-limit.md) <br/><br/> ## ![?] 6.13. 使用非root用戶運行Node.js <a href="https://www.owasp.org/index.php/Top_10-2017_A5-Broken_Access_Control" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A5:Broken%20Access%20Access%20Control-green.svg" alt=""/></a> **TL;DR:** Node.js作為一個具有無限權限的root用戶運行,這是一種普遍的情景。例如,在Docker容器中,這是默認行為。建議創建一個非root用戶,并保存到Docker鏡像中(下面給出了示例),或者通過調用帶有"-u username" 的容器來代表此用戶運行該進程。 **否則:** 在服務器上運行腳本的攻擊者在本地計算機上獲得無限制的權利 (例如,改變iptable,引流到他的服務器上) ?? [**更多: 使用非root用戶運行Node.js**](/sections/security/non-root-user.md) <br/><br/> ## ![?] 6.14. 使用反向代理或中間件限制負載大小 <a href="https://www.owasp.org/index.php/Top_10-2017_A8-Insecure_Deserialization" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A8:Insecured%20Deserialization%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg" alt=""/></a> **TL;DR:** 請求body有效載荷越大, Node.js的單線程就越難處理它。這是攻擊者在沒有大量請求(DOS/DDOS 攻擊)的情況下,就可以讓服務器跪下的機會。在邊緣上(例如,防火墻,ELB)限制傳入請求的body大小,或者通過配置[express body parser](https://github.com/expressjs/body-parser)僅接收小的載荷,可以減輕這種問題。 **否則:** 您的應用程序將不得不處理大的請求, 無法處理它必須完成的其他重要工作, 從而導致對DOS攻擊的性能影響和脆弱性。 ?? [**更多: 限制負載大小**](/sections/security/requestpayloadsizelimit.md) <br/><br/> ## ![?] 6.15. 避免JavaScript的eval聲明 <a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg" alt=""/></a> **TL;DR:** `eval` 是邪惡的, 因為它允許在運行時執行自定義的JavaScript代碼。這不僅是一個性能方面的問題, 而且也是一個重要的安全問題, 因為惡意的JavaScript代碼可能來源于用戶輸入。應該避免的另一種語言功能是 `new Function` 構造函數。`setTimeout` 和 `setInterval` 也不應該傳入動態JavaScript代碼。 **否則:** 惡意JavaScript代碼查找傳入 `eval` 或其他實時判斷的JavaScript函數的文本的方法, 并將獲得在該頁面上javascript權限的完全訪問權。此漏洞通常表現為XSS攻擊。 ?? [**更多: 避免JavaScript的eval聲明**](/sections/security/avoideval.chinese.md) <br/><br/> ## ![?] 6.16. 防止惡意RegEx讓Node.js的單線程過載執行 <a href="https://www.owasp.org/index.php/Denial_of_Service" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg" alt=""/></a> **TL;DR:** 正則表達式,在方便的同時,對JavaScript應用構成了真正的威脅,特別是Node.js平臺。匹配文本的用戶輸入需要大量的CPU周期來處理。在某種程度上,正則處理是效率低下的,比如驗證10個單詞的單個請求可能阻止整個event loop長達6秒,并讓CPU引火燒身。由于這個原因,偏向第三方的驗證包,比如[validator.js](https://github.com/chriso/validator.js),而不是采用正則,或者使用[safe-regex](https://github.com/substack/safe-regex)來檢測有問題的正則表達式。 **否則:** 寫得不好的正則表達式可能容易受到正則表達式DoS攻擊的影響, 這將完全阻止event loop。例如,流行的`moment`包在2017年的11月,被發現使用了錯誤的RegEx用法而易受攻擊。 ?? [**更多: 防止惡意正則**](/sections/security/regex.md) <br/><br/> ## ![?] 6.17. 使用變量避免模塊加載 <a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg" alt=""/></a> **TL;DR:** 避免通過作為參數的路徑requiring/importing另一個文件, 原因是它可能源自用戶輸入。此規則可擴展為訪問一般文件(即:`fs.readFile()`)或使用來自用戶輸入的動態變量訪問其他敏感資源。[Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter可以捕捉這樣的模式, 并盡早提前警告。 **否則:** 惡意用戶輸入可以找到用于獲得篡改文件的參數, 例如, 文件系統上以前上載的文件, 或訪問已有的系統文件。 ?? [**更多: 安全地加載模塊**](/sections/security/safemoduleloading.chinese.md) <br/><br/> ## ![?] 6.18. 在沙箱中運行不安全代碼 <a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg" alt=""/></a> **TL;DR:** 當任務執行在運行時給出的外部代碼時(例如, 插件), 使用任何類型的`沙盒`執行環境保護主代碼,并隔離開主代碼和插件。這可以通過一個專用的過程來實現 (例如:cluster.fork()), 無服務器環境或充當沙盒的專用npm包。 **否則:** 插件可以通過無限循環、內存超載和對敏感進程環境變量的訪問等多種選項進行攻擊 ?? [**更多: 在沙箱中運行不安全代碼**](/sections/security/sandbox.chinese.md) <br/><br/> ## ![?] 6.19. 使用子進程時要格外小心 <a href="https://www.owasp.org/index.php/Top_10-2017_A7-Cross-Site_Scripting_(XSS)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A7:XSS%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A1:Injection%20-green.svg" alt=""/></a> <a href="https://www.owasp.org/index.php/Top_10-2017_A4-XML_External_Entities_(XXE)" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A4:External%20Entities%20-green.svg" alt=""/></a> **TL;DR:** 盡可能地避免使用子進程,如果您仍然必須這樣做,驗證和清理輸入以減輕shell注入攻擊。更喜歡使用 "child_process"。execFile 的定義將只執行具有一組屬性的單個命令, 并且不允許 shell 參數擴展。傾向于使用`child_process.execFile`,從定義上來說,它將僅僅執行具有一組屬性的單個命令,并且不允許shell參數擴展。 **否則:** 由于將惡意用戶輸入傳遞給未脫敏處理的系統命令, 直接地使用子進程可能導致遠程命令執行或shell注入攻擊。 ?? [**更多: 處理子進程時要格外小心**](/sections/security/childprocesses.chinese.md) <br/><br/> ## ![?] 6.20. 隱藏客戶端的錯誤詳細信息 <a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a> **TL;DR:** 默認情況下, 集成的express錯誤處理程序隱藏錯誤詳細信息。但是, 極有可能, 您實現自己的錯誤處理邏輯與自定義錯誤對象(被許多人認為是最佳做法)。如果這樣做, 請確保不將整個Error對象返回到客戶端, 這可能包含一些敏感的應用程序詳細信息。 **否則:** 敏感應用程序詳細信息(如服務器文件路徑、使用中的第三方模塊和可能被攻擊者利用的應用程序的其他內部工作流)可能會從stack trace發現的信息中泄露。 ?? [**更多: 隱藏客戶端的錯誤詳細信息**](/sections/security/hideerrors.md) <br/><br/> ## ![?] 6.21. 對npm或Yarn,配置2FA <a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a> **TL;DR:** 開發鏈中的任何步驟都應使用MFA(多重身份驗證)進行保護, npm/Yarn對于那些能夠掌握某些開發人員密碼的攻擊者來說是一個很好的機會。使用開發人員憑據, 攻擊者可以向跨項目和服務廣泛安裝的庫中注入惡意代碼。甚至可能在網絡上公開發布。在npm中啟用2因素身份驗證(2-factor-authentication), 攻擊者幾乎沒有機會改變您的軟件包代碼。 **否則:** [Have you heard about the eslint developer who's password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8) <br/><br/> ## ![?] 6.22. 修改session中間件設置 <a href="https://www.owasp.org/index.php/Top_10-2017_A6-Security_Misconfiguration" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20A6:Security%20Misconfiguration%20-green.svg" alt=""/></a> **TL;DR:** 每個web框架和技術都有其已知的弱點-告訴攻擊者我們使用的web框架對他們來說是很大的幫助。使用session中間件的默認設置, 可以以類似于`X-Powered-By`header的方式向模塊和框架特定的劫持攻擊公開您的應用。嘗試隱藏識別和揭露技術棧的任何內容(例如:Nonde.js, express)。 **否則:** 可以通過不安全的連接發送cookie, 攻擊者可能會使用會話標識來標識web應用程序的基礎框架以及特定于模塊的漏洞。 ?? [**更多: cookie和session安全**](/sections/security/sessions.md) <br/><br/> ## ![?] 6.23. 通過顯式設置進程應崩潰的情況,以避免DOS攻擊 <a href="https://www.owasp.org/index.php/Denial_of_Service" target="_blank"><img src="https://img.shields.io/badge/%E2%9C%94%20OWASP%20Threats%20-%20DDOS%20-green.svg" alt=""/></a> **TL;DR:** 當錯誤未被處理時, Node進程將崩潰。即使錯誤被捕獲并得到處理,許多最佳實踐甚至建議退出。例如, Express會在任何異步錯誤上崩潰 - 除非使用catch子句包裝路由。這將打開一個非常愜意的攻擊點, 攻擊者識別哪些輸入會導致進程崩潰并重復發送相同的請求。沒有即時補救辦法, 但一些技術可以減輕苦楚: 每當進程因未處理的錯誤而崩潰,都會發出警報,驗證輸入并避免由于用戶輸入無效而導致進程崩潰,并使用catch將所有路由處理包裝起來,并在請求中出現錯誤時, 考慮不要崩潰(與全局發生的情況相反)。 **否則:** 這只是一個起到教育意義的假設: 給定許多Node.js應用程序, 如果我們嘗試傳遞一個空的JSON正文到所有POST請求 - 少數應用程序將崩潰。在這一點上, 我們可以只是重復發送相同的請求, 就可以輕松地搞垮應用程序。 <br/><br/><br/> <p align="right"><a href="#table-of-contents">? Return to top</a></p> # `API Practices` ## Our contributors are working on this section. Would you like to join? # `Performance Practices` ## Our contributors are working on this section. Would you like to join? <br/><br/><br/> # Milestones To maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with the help of the community. You can follow our [milestones](https://github.com/i0natan/nodebestpractices/milestones) and join the working groups if you want to contribute to this project. <br/><br/> # Contributors ## `Yoni Goldberg` Independent Node.js consultant who works with customers at USA, Europe and Israel on building large-scale scalable Node applications. Many of the best practices above were first published on his blog post at [http://www.goldbergyoni.com](http://www.goldbergyoni.com). Reach Yoni at @goldbergyoni or me@goldbergyoni.com ## `Ido Richter` ????? Software engineer, ?? web developer, ?? emojis enthusiast. ## `Refael Ackermann` [@refack](https://github.com/refack) &lt;refack@gmail.com&gt; (he/him) Node.js Core Collaborator, been noding since 0.4, and have noded in multiple production sites. Founded `node4good` home of [`lodash-contrib`](https://github.com/node4good/lodash-contrib), [`formage`](https://github.com/node4good/formage), and [`asynctrace`](https://github.com/node4good/asynctrace). `refack` on freenode, Twitter, GitHub, GMail, and many other platforms. DMs are open, happy to help. ## `Bruno Scheufler` ?? full-stack web developer and Node.js enthusiast. ## `Kyle Martin` [@js-kyle](https://github.com/js-kyle) Full Stack Developer based in New Zealand, interested in architecting and building Node.js applications to perform at global scale. Keen contributor to open source software, including Node.js Core. <br/><br/> # Thank You Notes This repository is being kept up to date thanks to the help from the community. We appreciate any contribution, from a single word fix to a new best practice. Below is a list of everyone who contributed to this project. A :sunflower: marks a successful pull request and a :star: marks an approved new best practice. ### Flowers ?? [Kevin Rambaud](https://github.com/kevinrambaud), ?? [Michael Fine](https://github.com/mfine15), ?? [Shreya Dahal](https://github.com/squgeim), ?? [ChangJoo Park](https://github.com/ChangJoo-Park), ?? [Matheus Cruz Rocha](https://github.com/matheusrocha89), ?? [Yog Mehta](https://github.com/BitYog), ?? [Kudakwashe Paradzayi](https://github.com/kudapara), ?? [t1st3](https://github.com/t1st3), ?? [mulijordan1976](https://github.com/mulijordan1976), ?? [Matan Kushner](https://github.com/matchai), ?? [Fabio Hiroki](https://github.com/fabiothiroki), ?? [James Sumners](https://github.com/jsumners), ?? [Chandan Rai](https://github.com/crowchirp), ?? [Dan Gamble](https://github.com/dan-gamble), ?? [PJ Trainor](https://github.com/trainorpj), ?? [Remek Ambroziak](https://github.com/reod), ?? [Yoni Jah](https://github.com/yonjah), ?? [Misha Khokhlov](https://github.com/hazolsky), ?? [Evgeny Orekhov](https://github.com/EvgenyOrekhov), ?? [Gediminas Petrikas](https://github.com/gediminasml), ?? [Isaac Halvorson](https://github.com/hisaac), ?? [Vedran Kara?i?](https://github.com/vkaracic), ?? [lallenlowe](https://github.com/lallenlowe), ?? [Nathan Wells](https://github.com/nwwells), ?? [Paulo Vítor S Reis](https://github.com/paulovitin), ?? [syzer](https://github.com/syzer), ?? [David Sancho](https://github.com/davesnx), ?? [Robert Manolea](https://github.com/pupix), ?? [Xavier Ho](https://github.com/spaxe), ?? [Aaron Arney](https://github.com/ocularrhythm), ?? [Jan Charles Maghirang Adona](https://github.com/septa97), ?? [Allen Fang](https://github.com/AllenFang), ?? [Leonardo Villela](https://github.com/leonardovillela), ?? [Michal Zalecki](https://github.com/MichalZalecki) ?? [Chris Nicola](https://github.com/chrisnicola), ?? [Alejandro Corredor](https://github.com/aecorredor), ?? [Ye Min Htut](https://github.com/ymhtut), ?? [cwar](https://github.com/cwar), ?? [Yuwei](https://github.com/keyfoxth), ?? [Utkarsh Bhatt](https://github.com/utkarshbhatt12), ?? [Duarte Mendes](https://github.com/duartemendes), ?? [Sagir Khan](https://github.com/sagirk), ?? [Jason Kim](https://github.com/serv), ?? [Mitja O.](https://github.com/Max101), ?? [Sandro Miguel Marques](https://github.com/SandroMiguel), ?? [Gabe Kuslansky](https://github.com/GabeKuslansky), ?? [Ron Gross](https://github.com/ripper234), ?? [Valeri Karpov](https://github.com/vkarpov15) ### Stars <br/> ? [Kyle Martin](https://github.com/js-kyle) ? [Keith Holliday](https://github.com/TheHollidayInn) <br/><br/>
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看