NGINX的SSL TLS與Security Header的安全性強化

NGINX的SSL TLS與Security Header的安全性強化

前一篇,在取得 NGINX 可用的憑證格式與套用後,就開始以 HTTPS 來連線與測試。但 nginx.conf 裡還有許多安全性設定值可以調整。

  1. NGINX HTTP Server 組態
  2. SSL/TLS 組態
  3. Security Header 組態

以下是我目前與安全性有關的設定值:

http {
    server_tokens off;
    server {
        listen 443 ssl;
        listen [::]:443 ssl;
        http2 on;
        server_name kkbruce.net;
        ssl_certificate server.crt;
        ssl_certificate_key server.key;
        ssl_dhparam dhparam.pem;
        ssl_session_timeout       1d;
        ssl_session_cache         shared:SSL:10m;
        ssl_protocols             TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
        ssl_session_tickets       off;
        ssl_stapling              off;
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options nosniff;
        add_header Cross-Origin-Opener-Policy same-origin;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        location / {
            root html;
            index index.html index.htm;
        }
    }
}

注意,請依你的使用環境進行細部調整。

NGINX http 安全性強化

http {
    # 隱藏 nginx 版本資訊,防止洩漏攻擊資訊
    server_tokens off;
}

原本會帶版本號的 HTTP Header,變成只會帶伺服器名稱,例如:

server: nginx

SSL/TLS 組態安全性強化

server {
        // 省略
        listen 443 ssl;
        listen [::]:443 ssl;
        http2 on;
        ssl_dhparam dhparam.pem;
        ssl_session_timeout       1d;
        ssl_session_cache         shared:SSL:10m;
        ssl_protocols             TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
        ssl_session_tickets       off;
        ssl_stapling              off;
}

詳細說明可以參考上面兩篇官方文件。以下是簡單說明。

啟用NGINX的HTTP/2

都已經上到 HTTPS 了,不用 HTTP/2 實在太可借了。

listen 443 ssl http2;

在網路上,大多數會查詢到以上語法,當 nginx reload 組態時會看到以下 warn,但不影響 HTTP/2 的啟用。

[warn] 14564#31588: the "listen ... http2" directive is deprecated, use the "http2" directive instead in C:\Tools\nginx/conf/nginx.conf:466

NGINX 1.25.1 之後提供新的 http2 on; 指令,因此就改為以下設定方式:

listen 443 ssl;
listen [::]:443 ssl;
http2 on;

啟用NGINX的HTTP/3

注意:HTTP/3 僅支援 TLSv1.3

listen 443 quic reuseport;
location / {
    add_header Alt-Svc 'h3=":443"; ma=86400';
    root html;
    index index.html index.htm;
}

如果你在 NGINX for Windows 套用會得到以下錯誤:「[emerg] 28092#37880: the "quic" parameter requires ngx_http_v3_module in C:\nginx/conf/nginx.conf:472」,官方文件有說:「Support for QUIC and HTTP/3 protocols is available since 1.25.0. Also, since 1.25.0, the QUIC and HTTP/3 support is available in Linux binary packages.」只好再等等,等我回到 NGINX (Linux)的那一天(苦笑)。

ssl_ 組態安全性強化

# Diffie-Hellman(DH)金鑰交換機制提供額外的安全性
ssl_dhparam dhparam.pem;
# 啟用快取,提高 TLS 效能
ssl_session_timeout       1d;
ssl_session_cache         shared:SSL:10m;
# 停用 TLS 1.0 / 1.1,提高安全性
ssl_protocols             TLSv1.2 TLSv1.3;
# 使用安全的加密演算法
ssl_prefer_server_ciphers on;
ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# 禁用 Session Tickets,防止密鑰重複使用
ssl_session_tickets       off;
# 停用 OCSP Stapling,啟用需要額外設定與憑證供應商的支援,僅影響驗證效能,不影響安全性。
# 內網環境不需要可停用。
ssl_stapling              off;

注意,dhparam 可以利用 WSL 的 OpenSSL 來手動產生,產生後複製到 NGINX 的 conf 目錄下。

openssl dhparam -out dhparam.pem 4096

另外,ssl_ciphers 我是參考在 Linux 上使用 Nginx 裝載 ASP.NET Core文件裡面的設定值,請依你的需要調整。

Security Header 安全性強化

Security Header 主要防禦來自 Web 攻擊。以下有兩個很好的參考資料:

# 指示文件是否能夠透過 <frame>、<iframe> 以及 <object> 載入。
# SAMEORIGIN 唯有當符合同源政策下,才能被嵌入到 frame 中。
add_header X-Frame-Options SAMEORIGIN;
# 當瀏覽器偵測到 XSS 攻擊時,會阻擋頁面載入。
add_header X-XSS-Protection "1; mode=block";
# 當瀏覽器偵測到 MIME 類型不正確時,會阻擋頁面載入。
add_header X-Content-Type-Options nosniff;
### https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Guides/Cross-Origin_Resource_Policy
# same-origin: 只有來自相同來源(即方案 + 主機 + 通訊埠)的請求可以讀取資源。
add_header Cross-Origin-Opener-Policy same-origin;
#add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://apis.example.com";
# Strict-Transport-Security (HSTS)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

可以注意到 Content-Security-Policy 我是註解掉的,因為它的設定與測試比較麻煩與複雜。一樣請讀者自行評估。

這些選項值不是絕對值,例如,X-Frame-OptionsX-XSS-Protection 都還有其他選項值,每種選項值作用不同,因此請自行評估那組選項值符合你的需求。

補充一份找到不錯的參考資料:https://docsaid.org/docs/nginx-notes/security/

小結:注意 TLS 1.2

目前測起來只有 ssl_protocols TLSv1.2 TLSv1.3; 這組設定比較可能讓你的應用程式壞掉,但關閉 TLS 1.0 與 TLS 1.1 是趨勢,要修正其實也不難,以 ASP.NET Core 應用程式為例,可以在 Program.csKestrel 加上以下組態,讓 HTTPS 之間走 TLS 1.2 協定。

// Setup Kestrel to use TLS 1.2
builder.WebHost.UseKestrel(kestrelOptions =>
{
    kestrelOptions.ConfigureHttpsDefaults(httpsOptions =>
    {
        httpsOptions.SslProtocols = SslProtocols.Tls12;
    });
});

一般 .NET 應用程式,可能要在適當的地方加上以下組態:

ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

其他程式語言應該都有對應 TLS 1.2 的設定,大家在伺服器端導入 TLS 1.2 組態後,記的用戶端也要進行對應的設定。

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。