iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0
Odoo

Odoo 部署策略系列 第 25

將 odoo 靜態資源交給反向代理:效能與 XSS 防護的雙重提升

  • 分享至 

  • xImage
  •  

今天的內容又是關於反向代理、效能與安全性的提升。不過,關於安全性的部分設定,往往需要透過限制某些功能或增加檢查來達成。因此,在進行正式佈署前,務必測試這些變更是否對系統原本的設計造成影響。


為什麼需要將靜態檔案服務交給 nginx?

為了開發方便,odoo 會直接在每個模組中提供所有靜態檔案,開發者在本地環境中可以快速存取這些資源,無需額外設定;然而,當系統進入生產環境時,因為這些檔案會與其他對 odoo 的動態請求競爭伺服器資源,導致效能下降。因此,為了改善系統的效能,應該將靜態檔案交由 NGINX 這種專門的靜態 HTTP 伺服器處理。


什麼是 XSS 和 CSP

在網頁安全領域,XSS(跨站腳本攻擊,Cross-Site Scripting) 是一種常見的攻擊方式。攻擊者利用網站的漏洞,將惡意的腳本程式注入到網頁中。當其他使用者瀏覽受感染的頁面時,這些惡意腳本就會在他們的瀏覽器中執行。這可能導致:

  • 敏感資訊洩露:如用戶的帳號、密碼、信用卡資訊等。
  • 帳號被盜:攻擊者可以以用戶的身份進行未經授權的操作。
  • 網站內容被篡改:顯示假消息或誘導用戶執行某些操作。

CSP(內容安全政策,Content Security Policy) 是一種用來防止 XSS 攻擊的瀏覽器安全機制。它透過讓網站管理員制定一組規則,告訴瀏覽器應該允許或阻止哪些類型的資源載入和執行。

資源載入是什麼意思?

當我們瀏覽一個網頁時,瀏覽器會從伺服器請求並載入各種資源,例如:

  • HTML 文件:網頁的結構和內容。
  • CSS 檔案:控制網頁的外觀和樣式。
  • JavaScript 檔案:提供互動功能的腳本。
  • 圖片、影片、字體等多媒體資源

這些資源可能來自於同一個網站(同源),也可能來自於其他網站(跨源)。在沒有適當限制的情況下,惡意資源可能會被載入並執行,帶來安全風險。

CSP 如何防止 XSS 攻擊?

透過設定 CSP,網站可以指定哪些來源的資源是被信任的,瀏覽器只會載入和執行這些被允許的資源。例如:

  • 限制腳本來源:只允許從特定域名載入 JavaScript 檔案,阻止未經授權的腳本執行。
  • 限制圖片來源:只允許從指定的來源載入圖片,防止惡意圖片載入或資料洩露。
  • 禁止內聯腳本:阻止在 HTML 中直接寫入的腳本執行,因為這些腳本容易被攻擊者注入。

使用 nginx reverse-proxy 服務 odoo 靜態檔案

docker-compose.yml

為了讓 nginx 能夠存取這些靜態檔案,我們需要在 docker-compose.yml 的反向代理容器中掛載相應的檔案:

# 掛載 odoo 靜態檔案來處理(如 JS、CSS 等靜態資源)
- ./odoo-dev/source/addons:/opt/odoo-dev/addons:ro
- ./odoo-dev/source/odoo:/opt/odoo-dev/core:ro

這樣,我們就能夠在 /opt/odoo-dev 路徑下訪問到 odoo 的靜態資源。

nginx.conf & nginx_odoo.conf

odoo 的靜態檔案位於每個模組的 static/ 資料夾中,因此可以透過攔截所有 /MODULE/static/FILE 的請求,並根據不同的 addons 路徑查找相應的模組與檔案,來服務這些靜態檔案。

另外我們同時進行建議的 CSP 設定,為伺服器傳遞的所有圖片設置 Content-Security-Policy: default-src 'none' 標頭:雖然使用者無法修改或注入模組的 static/ 資料夾內容,且已存在的圖片也是最終版本(不會自行抓取新的資源),但這仍然是一種良好的安全實踐。

首先,在 nginx.conf 中添加以下 map 區塊:

# 根據傳遞的內容類型設置 Content-Security-Policy 標頭,只對圖片資源應用安全策略
map $sent_http_content_type $content_type_csp {
    default "";
    ~image/ "default-src 'none'";
}

接下來,在 nginx_odoo.confodoo-dev server {} 區塊中加入:

# 定義一個命名位置,用於將未被其他規則處理的請求代理到 odoo 伺服器
location @odoo { # 內容跟 default 的 location / 一樣
    set $upstream odoo-dev:8069;
    proxy_pass http://$upstream;
    include /etc/nginx/conf.d/proxy_odoo_http.include;
}

# 匹配所有指向模組靜態資源的請求,直接由 NGINX 服務
location ~ ^/[^/]+/static/.+$ {
    # 指定靜態檔案的根目錄,我們設定為 /opt/odoo-dev
    root /opt/odoo-dev;
    # 按照順序嘗試在指定路徑中尋找請求的檔案
    # 如果都找不到,則將請求轉發到 @odoo
    try_files /core/odoo/addons$uri /core/addons$uri /addons$uri @odoo;
    # 設置客戶端快取過期時間為 24 小時
    expires 24h;
    # 添加 Content-Security-Policy 標頭,應用我們在 map 中定義的策略
    add_header Content-Security-Policy $content_type_csp;
}

減少請求數量的驗證結果

設定好後,我測試了在同樣的操作下登入 odoo,並觀察 odoo container 的 log 差異。原本在未設定反向代理處理靜態檔案時,有大約 60 個請求;設定完成後,請求數量減少到了約 20 個。像下方這些關於 static 資源的請求,都已經由 reverse-proxy 直接處理掉了。

2024-10-10 15:50:06 2024-10-10 07:50:06,342 90 INFO ? werkzeug: 172.19.0.1 - - [10/Oct/2024 07:50:06] "GET /website_hr_recruitment/static/description/icon.png HTTP/1.0" 200 - 0 0.000 0.001
2024-10-10 15:50:06 2024-10-10 07:50:06,344 95 INFO ? werkzeug: 172.19.0.1 - - [10/Oct/2024 07:50:06] "GET /base/static/img/icons/sale_amazon.png HTTP/1.0" 200 - 0 0.000 0.001
2024-10-10 15:50:06 2024-10-10 07:50:06,355 92 INFO ? werkzeug: 172.19.0.1 - - [10/Oct/2024 07:50:06] "GET /base/static/img/icons/sale_ebay.png HTTP/1.0" 200 - 0 0.000 0.002
2024-10-10 15:50:06 2024-10-10 07:50:06,359 92 INFO ? werkzeug: 172.19.0.1 - - [10/Oct/2024 07:50:06] "GET /hr_contract/static/description/icon.png HTTP/1.0" 200 - 0 0.000 0.002

透過今天設定,我們可以直接使用 reverse-proxy 來處理 odoo 的靜態檔案,提升整體系統的效能。還有設定適當的安全標頭也能增強系統的安全性,明天會繼續處理類似的問題。


上一篇
(重新)自動化 odoo 設定:用 Python 腳本完成資料庫初始化
下一篇
又又又是 odoo 安全與效能:X-Sendfile、X-Accel、HSTS、Cookie 安全標記、Gzip 壓縮
系列文
Odoo 部署策略30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言