返回文章列表

NGINX 身分驗證與安全設定完整

本文探討 NGINX 的各種身分驗證方法,包含基本驗證、子請求驗證、JWT 驗證,以及與 SAML 的整合。同時,文章也涵蓋了 CORS 設定、SSL/TLS 加密,以及根據 IP 位址的存取控制等安全強化措施,提供全面的 NGINX 安全設定。

Web 開發 資安

NGINX 身分驗證機制對於保障 Web 應用程式安全至關重要。本文不僅涵蓋基本驗證和子請求驗證等常見方法,更探討了根據 JWT 和 SAML 的現代驗證方案。這些方法各有優劣,適用於不同的應用場景。例如,基本驗證適用於簡單的存取控制,而 JWT 和 SAML 則更適合複雜的單一登入(SSO)情境。此外,文章也詳細說明瞭如何設定 CORS,以允許跨域資源分享,以及如何正確組態 SSL/TLS 加密,確保資料傳輸安全。最後,文章還介紹瞭如何利用 NGINX 設定根據 IP 位址的存取控制,進一步強化 Web 應用程式的安全性。

使用NGINX進行身分驗證的方法

NGINX提供了多種身分驗證方法,以確保只有授權使用者可以存取特定的資源或服務。這些方法包括基本身分驗證、身份驗證子請求以及使用JSON Web Token(JWT)進行驗證。

基本身分驗證

基本身分驗證是一種簡單的身分驗證方法,透過要求使用者輸入使用者名稱和密碼來驗證其身份。NGINX支援這種驗證方法,可以用於保護整個NGINX主機、特定的虛擬伺服器或特定的位置區塊。

設定基本身分驗證

要設定基本身分驗證,需要在NGINX組態檔案中使用auth_basicauth_basic_user_file指令。auth_basic指令指定了驗證域,而auth_basic_user_file指令則指定了包含使用者憑據的檔案路徑。

location /protected/ {
    auth_basic "Restricted Area";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

基本身分驗證的工作原理

當使用者嘗試存取受保護的資源時,NGINX會傳回一個401 Unauthorized HTTP狀態碼,並在回應頭中包含WWW-Authenticate欄位,提示使用者輸入使用者名稱和密碼。使用者輸入憑據後,瀏覽器會將使用者名稱和密碼以base64編碼的形式傳送到伺服器。伺服器然後解碼並驗證這些憑據,如果正確,則允許使用者存取資源。

#### 內容解密:

  • auth_basic指令用於啟用基本身分驗證並指定驗證域。
  • auth_basic_user_file指令指定包含使用者憑據的檔案。
  • 使用者名稱和密碼以base64編碼,但這並不安全,因此建議與HTTPS一起使用,以加密傳輸的憑據。

身份驗證子請求

對於需要與第三方身份驗證系統整合的情況,NGINX提供了身份驗證子請求功能。這允許NGINX在處理請求之前,先向身份驗證服務傳送一個子請求,以驗證使用者的身份。

設定身份驗證子請求

要使用身份驗證子請求,需要在NGINX組態檔案中設定auth_request指令,指定一個內部位置來處理身份驗證子請求。

location /private/ {
    auth_request /auth;
    auth_request_set $auth_status $upstream_status;
}

location = /auth {
    internal;
    proxy_pass http://auth-server;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}

身份驗證子請求的工作原理

當使用者傳送請求時,NGINX會先向指定的身份驗證服務傳送一個子請求。如果子請求傳回200 OK狀態碼,則允許原始請求繼續;否則,NGINX會傳回與子請求相同的狀態碼給使用者。

#### 內容解密:

  • auth_request指令指定了用於身份驗證的子請求的位置。
  • auth_request_set指令允許從身份驗證子請求的回應中設定變數。
  • 身份驗證服務可以根據需要檢查請求的任何方面,包括頭部和URI。

使用JSON Web Token(JWT)進行驗證

NGINX Plus支援使用JSON Web Token(JWT)進行身份驗證。JWT是一種安全的令牌格式,可以用來在各方之間安全地傳遞資訊。

設定JWT驗證

要使用JWT驗證,需要在NGINX Plus組態檔案中設定auth_jwt指令。

location /api/ {
    auth_jwt "api";
    auth_jwt_key_file conf/keys.json;
}

JWT驗證的工作原理

NGINX Plus會檢查請求中的JWT令牌,驗證其簽名,並將令牌中的宣告和頭部作為變數提供給組態。

#### 內容解密:

  • auth_jwt指令啟用了JWT驗證並指定了驗證域。
  • auth_jwt_key_file指令指定了包含JSON Web Key(JWK)的檔案,用於驗證JWT簽名。
  • NGINX Plus支援多種簽名演算法,包括HS256、RS256和ES256。

建立JSON Web Key(JWK)

要使用JWT驗證,需要有一個JSON Web Key(JWK)檔案。JWK是一種標準格式,用於表示可以用於簽署和驗證JWT的加密金鑰。

JWK檔案範例

{
    "keys": [
        {
            "kty": "oct",
            "kid": "0001",
            "k": "OctetSequenceKeyValue"
        },
        {
            "kty": "EC",
            "kid": "0002",
            "crv": "P-256",
            "x": "XCoordinateValue",
            "y": "YCoordinateValue",
            "d": "PrivateExponent",
            "use": "sig"
        }
    ]
}

#### 內容解密:

  • JWK檔案包含一個或多個金鑰物件,每個物件代表一個可以用於JWT簽名或加密的金鑰。
  • kty欄位指定了金鑰型別,例如oct表示對稱金鑰,EC表示橢圓曲線金鑰。
  • 其他欄位根據金鑰型別不同而有所不同,例如k用於對稱金鑰,而xyd等用於橢圓曲線金鑰。

綜上所述,NGINX提供了多種靈活的身分驗證方法,可以根據具體需求選擇最合適的方式來保護資源和服務。無論是基本身分驗證、身份驗證子請求還是JWT驗證,NGINX都能提供強大的支援,確保只有授權使用者可以存取敏感資訊。

JSON Web Key(JWK)與 NGINX Plus 的應用

JWK 格式與型別

JSON Web Key(JWK)是一種用於表示加密金鑰的 JSON 格式。RFC 標準定義了 JWK 的格式和多種金鑰型別,包括 Octet Sequence(oct)、Elliptic Curve(EC)和 RSA。

以下是一個 JWK 檔案的範例:

{
  "keys": [
    {
      "kty": "oct",
      "kid": "0001",
      "k": "HMAC金鑰"
    },
    {
      "kty": "EC",
      "kid": "0002",
      "crv": "P-256",
      "x": "X座標",
      "y": "Y座標",
      "d": "私鑰"
    },
    {
      "kty": "RSA",
      "kid": "0003",
      "n": "模數",
      "e": "指數",
      "d": "私鑰"
    }
  ]
}

內容解密:

  • kty屬性表示金鑰型別。
  • kid屬性是金鑰 ID,用於識別不同的金鑰。
  • 不同型別的金鑰有不同的屬性,例如 EC 金鑰有 crvxyd 屬性,而 RSA 金鑰有 ned 屬性。

使用 NGINX Plus 驗證 JSON Web Tokens(JWT)

NGINX Plus 可以使用 JWT 模組來驗證 JWT。以下是一個範例設定:

location /private/ {
  auth_jwt "Google Oauth" token=$cookie_auth_token;
  auth_jwt_key_file /etc/nginx/google_certs.jwk;
}

內容解密:

  • auth_jwt指令用於啟用 JWT 驗證。
  • token=$cookie_auth_token指定了 JWT 的位置,在此例中是 auth_token cookie。
  • auth_jwt_key_file指定了用於驗證 JWT 簽名的 JWK 檔案路徑。

自動取得和快取 JSON Web Key Sets(JWKS)

NGINX Plus 可以使用 auth_jwt_key_request指令自動從身份提供者取得 JWKS 並快取。以下是一個範例設定:

proxy_cache_path /data/nginx/cache levels=1 keys_zone=foo:10m;

server {
  # ...
  location / {
    auth_jwt "closed site";
    auth_jwt_key_request /jwks_uri;
  }

  location = /jwks_uri {
    internal;
    proxy_cache foo;
    proxy_pass https://idp.example.com/keys;
  }
}

內容解密:

  • auth_jwt_key_request指令指示 NGINX Plus 從內部子請求取得 JWKS。
  • 子請求被導向 /jwks_uri,該位置代理請求到身份提供者。
  • 使用快取來限制對身份提供者的請求頻率。

將 NGINX Plus 組態為 SAML 身份提供者的服務提供者

NGINX Plus 可以與 SAML 身份提供者整合以保護資源。以下是一個範例設定:

# 安裝 njs 模組
$ apt install nginx-plus-module-njs

# 在 nginx.conf 中載入 njs 模組
load_module modules/ngx_http_js_module.so;

內容解密:

  • 需要安裝 njs 模組來支援 SAML 身份驗證。
  • 載入 njs 模組需要在 nginx.conf 中新增相應的設定。

NGINX 與 SAML 整合實作單一登入(SSO)驗證

NGINX Plus 提供了一種根據 JavaScript 的 SAML 服務提供者(SP)解決方案,用於保護資源並實作單一登入(SSO)。本解決方案結合 NGINX JavaScript 模組和 NGINX Plus 鍵值儲存模組,實作了 SAML SP 功能。

設定步驟

  1. 載入 NGINX JavaScript 模組

    load_module modules/ngx_http_js_module.so;
    
  2. 下載並設定 SAML JavaScript 和 NGINX Plus 組態檔案

    • 下載 SAML 解決方案:$ wget https://github.com/nginxinc/nginx-saml/archive/refs/heads/main.zip -O nginx-saml-main.zip
    • 解壓縮:$ unzip nginx-saml-main.zip
    • 移動組態檔案:$ mv nginx-saml-main/* /etc/nginx/conf.d/
  3. 更新組態檔案

    • saml_sp_configuration.conf:設定服務提供者(SP)和身份提供者(IdP)的相關組態。
      • 修改 $saml_sp_ 字首的變數以符合 SP 組態。
      • 修改 $saml_idp_ 字首的變數以符合 IdP 組態。
      • 設定登出後重定向的 URI。
    • frontend.conf:範例反向代理組態,使用 SAML 解決方案保護資源。
      • server 組態中包含 saml_sp.server_conf
      • 使用 error_page 指令啟動 SAML SP 流程。
    • saml_sp.server_conf:處理 IdP 回應的 NGINX 組態,通常不需要修改。
    • saml_sp.js:執行 SAML 認證的 JavaScript 程式碼,無需修改。

設定檔解說

此處使用了多個設定檔來達成SAML SSO的功能:

  • saml_sp_configuration.conf:主要用於定義SP和IdP的組態,使用map區塊來進行多重組態。
  • frontend.conf:用於反向代理組態,保護特定資源。
  • saml_sp.server_conf:用於處理來自IdP的回應,一般無需變更。
  • saml_sp.js:SAML驗證的核心JavaScript程式碼,無需修改。

SAML SSO 工作流程

  1. SP 和 IdP 組態:透過 saml_sp_configuration.conf 組態 SP 和 IdP。
  2. 啟動 SP 流程:當 NGINX Plus 沒有為使用者儲存會話時,使用 error_page 指令啟動 SP 流程,將使用者重定向到 IdP。
  3. 驗證和會話儲存:IdP 驗證使用者後,將 SAML 回應發送回 NGINX Plus。NGINX Plus 驗證回應並將會話儲存在鍵值儲存中。
  4. Cookie 設定:將 SAML 回應的鍵以 Cookie 形式傳回給客戶端,用於後續請求。

單一登出(SLO)功能

SLO 功能允許使用者透過單一操作登出所有 SP 和 IdP。可以透過設定 $saml_idp_slo_url 為空字串來停用 SLO 功能。

SLO 工作流程

  1. SP 發起的登出:NGINX Plus 向 IdP 傳送 LogoutRequest,IdP 終止使用者會話並回傳 LogoutResponse。
  2. IdP 發起的登出:IdP 向 NGINX Plus 傳送 LogoutRequest,NGINX Plus 刪除相關會話並回傳 LogoutResponse。

安全控制

本章節討論了多種使用 NGINX 加固 Web 應用程式安全的方法,包括根據 IP 位址的存取控制。

根據 IP 位址的存取控制

location /admin/ {
    deny 10.0.0.1;
    allow 10.0.0.0/20;
    deny all;
}

此組態限制了對 /admin/ 路徑的存取,只允許來自 10.0.0.0/20 網段的 IP 位址,但拒絕 10.0.0.1

NGINX 存取控制與安全設定

7.1 利用 NGINX 進行存取控制

問題描述

需要對特定資源進行存取控制,限制特定 IP 地址或網段的存取許可權。

解決方案

使用 NGINX 的 allowdeny 指令來控制存取:

location / {
    deny 10.0.0.1;
    allow 10.0.0.0/20;
    allow 2001:0db8::/32;
    deny all;
}

內容解密:

  1. deny 10.0.0.1; - 禁止特定的 IPv4 地址 10.0.0.1 存取。
  2. allow 10.0.0.0/20; - 允許 10.0.0.010.0.15.255 的 IPv4 地址範圍存取。
  3. allow 2001:0db8::/32; - 允許特定的 IPv6 網段 2001:0db8::/32 存取。
  4. deny all; - 禁止所有其他未被明確允許的 IP 地址存取。

這些指令按照順序檢查,直到找到匹配的規則為止。

7.2 啟用跨來源資源共用(CORS)

問題描述

需要允許來自不同網域的資源被瀏覽器使用。

解決方案

使用 NGINX 設定 CORS 頭部資訊:

map $request_method $cors_method {
    OPTIONS 11;
    GET 1;
    POST 1;
    default 0;
}

server {
    location / {
        if ($cors_method ~ '1') {
            add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
            add_header 'Access-Control-Allow-Origin' '*.example.com';
            add_header 'Access-Control-Allow-Headers' 'DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
        }
        if ($cors_method = '11') {
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain; charset=UTF-8';
            add_header 'Content-Length' 0;
            return 204;
        }
    }
}

內容解密:

  1. 使用 map 將請求方法對映到特定的變數值,簡化 CORS 設定。
  2. GETPOST 請求,設定允許的方法、來源和頭部資訊。
  3. OPTIONS 請求,傳回預檢請求的結果,包含快取時間等資訊。

7.3 使用者端加密

問題描述

需要在 NGINX 伺服器和使用者端之間加密傳輸的資料。

解決方案

使用 SSL/TLS 模組加密傳輸:

http {
    server {
        listen 8443 ssl;
        ssl_certificate /etc/nginx/ssl/example.crt;
        ssl_certificate_key /etc/nginx/ssl/example.key;
    }
}

內容解密:

  1. listen 8443 ssl; - 設定伺服器監聽在 8443 連線埠,並啟用 SSL/TLS。
  2. ssl_certificate - 指定伺服器的憑證檔案。
  3. ssl_certificate_key - 指定伺服器的私鑰檔案。

7.4 高階使用者端加密設定

問題描述

需要對 SSL/TLS 交握過程進行更細緻的控制。

解決方案

使用 NGINX 的 SSL/TLS 相關指令進行詳細設定:

http {
    server {
        listen 8443 ssl;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_certificate /etc/nginx/ssl/example.crt;
        ssl_certificate_key /etc/nginx/ssl/example.pem;
        ssl_certificate $ecdsa_cert;
        ssl_certificate_key data:$ecdsa_key_path;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
    }
}

內容解密:

  1. ssl_protocols - 指定接受的 TLS 版本。
  2. ssl_ciphers - 設定加密演算法,HIGH:!aNULL:!MD5 表示使用高強度加密演算法,並排除不安全的演算法。
  3. 使用多個憑證和私鑰檔案,包括檔案路徑和變數值。
  4. ssl_session_cachessl_session_timeout - 設定 SSL/TLS 交握結果的快取。