黑人生命也是命。
支持平等正義倡議.

生產最佳實務:安全性

概觀

術語「生產」是指軟體生命週期中,應用程式或 API 通常可供其最終使用者或消費者使用的階段。相對地,在「開發」階段,您仍在積極撰寫和測試程式碼,而應用程式並未開放外部存取。對應的系統環境分別稱為生產開發環境。

開發和生產環境通常設定不同,且有截然不同的需求。在開發環境中可以接受的,在生產環境中可能無法接受。例如,在開發環境中,您可能想要詳細記錄錯誤以進行除錯,而相同的行為在生產環境中可能會成為安全問題。在開發中,您不必擔心可擴充性、可靠性和效能,而這些問題在生產中會變得至關重要。

注意:如果您認為已在 Express 中發現安全漏洞,請參閱安全政策和程序

在生產環境中,Express 應用程式的安全最佳實務包括

不要使用已棄用或有漏洞的 Express 版本

Express 2.x 和 3.x 不再維護。這些版本中的安全性和效能問題將不會修復。請勿使用它們!如果您尚未移轉到版本 4,請遵循移轉指南

另外,請確保您沒有使用安全更新頁面上列出的任何有漏洞的 Express 版本。如果您有使用,請更新到其中一個穩定版本,最好是最新版本。

使用 TLS

如果您的應用程式處理或傳輸敏感資料,請使用 傳輸層安全性 (TLS) 來保護連線和資料。這項技術會在從客戶端傳送至伺服器之前加密資料,進而防止一些常見(且容易)的駭客攻擊。儘管 Ajax 和 POST 要求可能並不明顯,且看似「隱藏」在瀏覽器中,但其網路流量容易受到 封包嗅探中間人攻擊 的影響。

您可能熟悉安全通訊協定層 (SSL) 加密。 TLS 只是 SSL 的下一代。換句話說,如果您之前使用 SSL,請考慮升級至 TLS。一般來說,我們建議使用 Nginx 來處理 TLS。如需設定 Nginx(和其他伺服器)上 TLS 的良好參考,請參閱 建議的伺服器設定(Mozilla Wiki)

此外,取得免費 TLS 憑證的便利工具是 Let’s Encrypt,這是由 網際網路安全研究小組 (ISRG) 提供的免費、自動化且開放的憑證授權 (CA)。

使用 Helmet

Helmet 可以透過適當地設定 HTTP 標頭來協助保護您的應用程式,避免一些眾所周知的網路弱點。

Helmet 是由數個較小的中間件函式組成的集合,這些函式設定與安全性相關的 HTTP 回應標頭。一些範例包括

Helmet 包含許多其他中間件函式,您可以在 其文件網站 中閱讀相關資訊。

像安裝其他模組一樣安裝 Helmet

$ npm install --save helmet

然後在您的程式碼中使用它

// ...

const helmet = require('helmet')
app.use(helmet())

// ...

減少指紋辨識

它可以提供額外的安全層,以減少伺服器指紋辨識。雖然這本身不是安全問題,但改善網路伺服器整體態勢的方法是採取措施,減少辨識伺服器上所使用軟體的能力。伺服器軟體可以透過其對特定要求的回應怪癖來進行指紋辨識。

預設情況下,Express.js 會傳送 X-Powered-By 回應標頭橫幅。這可以使用 app.disable() 方法停用

app.disable('x-powered-by')

注意:停用 X-Powered-By 標頭 並不能阻止老練的攻擊者判斷應用程式正在執行 Express。它可能會阻止隨意的攻擊,但還有其他方法可以判斷應用程式正在執行 Express。

Express.js 也會傳送它自己的格式化 404 找不到訊息和自己的格式化錯誤回應訊息。這些可以透過 新增您自己的找不到處理常式撰寫您自己的錯誤處理常式 來變更

// last app.use calls right before app.listen():

// custom 404
app.use((req, res, next) => {
  res.status(404).send("Sorry can't find that!")
})

// custom error handler
app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

安全地使用 Cookie

為確保 Cookie 沒有讓您的應用程式曝露於攻擊中,請不要使用預設的會話 Cookie 名稱,並適當地設定 Cookie 安全性選項。

有兩個主要的 Cookie 會話中間件模組

這兩個模組之間的主要差異在於它們儲存 Cookie 會話資料的方式。express-session 中介軟體將會話資料儲存在伺服器上;它只會將會話 ID 儲存在 Cookie 本身,而不是會話資料。預設情況下,它使用記憶體內儲存,且不適用於生產環境。在生產環境中,您需要設定可擴充的會話儲存;請參閱 相容會話儲存 的清單。

相反地,cookie-session 中介軟體實作 Cookie 支援的儲存:它會將整個會話序列化到 Cookie,而不仅仅是會話金鑰。僅在會話資料相對較小且容易編碼為原始值(而不是物件)時才使用它。儘管瀏覽器應支援每個 Cookie 至少 4096 位元組,但為確保您不會超過限制,請勿超過每個網域 4093 位元組的大小。此外,請注意 Cookie 資料將對用戶端可見,因此如果有任何理由要讓它保持安全或模糊,則 express-session 可能會是更好的選擇。

使用預設的會話 Cookie 名稱可能會讓您的應用程式面臨攻擊。所造成的安全性問題類似於 X-Powered-By:潛在攻擊者可以使用它來對伺服器進行指紋辨識,並針對攻擊目標。

為避免此問題,請使用一般的 Cookie 名稱;例如使用 express-session 中介軟體

const session = require('express-session')
app.set('trust proxy', 1) // trust first proxy
app.use(session({
  secret: 's3Cur3',
  name: 'sessionId'
}))

設定以下 Cookie 選項以增強安全性

以下是使用 cookie-session 中介軟體的範例

const session = require('cookie-session')
const express = require('express')
const app = express()

const expiryDate = new Date(Date.now() + 60 * 60 * 1000) // 1 hour
app.use(session({
  name: 'session',
  keys: ['key1', 'key2'],
  cookie: {
    secure: true,
    httpOnly: true,
    domain: 'example.com',
    path: 'foo/bar',
    expires: expiryDate
  }
}))

防止針對授權的暴力攻擊

請務必保護登入端點,以提升私人資料的安全性。

一個簡單且強大的技術是使用兩個指標來封鎖授權嘗試

  1. 第一個是同一個使用者名稱和 IP 位址連續失敗嘗試的次數。
  2. 第二個是在一段長時間內從一個 IP 位址發出的失敗嘗試次數。例如,如果一個 IP 位址在一天內有 100 次失敗嘗試,則封鎖該 IP 位址。

rate-limiter-flexible 套件提供工具,讓這項技術變得簡單且快速。您可以在 文件 中找到暴力破解防護的範例

確保您的相依項是安全的

使用 npm 來管理應用程式的相依性既強大又方便。但您使用的套件可能包含可能會影響應用程式的重大安全性漏洞。應用程式的安全性僅與相依性中「最弱的連結」一樣強。

自 npm@6 起,npm 會自動檢閱每個安裝請求。您也可以使用「npm audit」來分析您的相依性樹狀結構。

$ npm audit

如果您想要更安全,請考慮 Snyk

Snyk 提供 命令列工具Github 整合,會根據 Snyk 的開源漏洞資料庫 檢查您的應用程式,找出相依性中任何已知的漏洞。請按照下列方式安裝 CLI

$ npm install -g snyk
$ cd your-app

使用此命令來測試您的應用程式是否有漏洞

$ snyk test

避免其他已知的漏洞

注意 Node Security ProjectSnyk 的公告,這些公告可能會影響您的應用程式使用的 Express 或其他模組。一般而言,這些資料庫是關於 Node 安全性的知識和工具的絕佳資源。

最後,Express 應用程式(就像其他網路應用程式一樣)可能會受到各種網路攻擊的威脅。熟悉已知的 網路漏洞,並採取預防措施來避免它們。

其他注意事項

以下是來自優秀的 Node.js 安全檢查清單 的一些進一步建議。請參閱該部落格文章以取得這些建議的所有詳細資訊