# CSP Header 是必要的嗎? 作為軟體公司的技術管理者,您可能經常遇到資安掃描報告中出現「CSP Header Not Set」的警告。本文將深入探討 Content Security Policy (CSP) 的必要性、實作方式,以及為什麼資安掃描工具會將其視為必要檢查項目。 ## CSP 是否為強制性要求? **答案是:不是強制性的,但強烈建議實施。** CSP 的實施優先級取決於您的應用場景: ### 高優先級場景 - **面向公眾的網站**:直接暴露於網際網路的應用 - **敏感資料處理**:涉及金融、醫療、個人隱私資料的系統 - **企業級應用**:即使是內部系統,也需要多層防護 - **合規要求**:PCI DSS、GDPR 等法規標準的要求 - **現代化應用**:大量使用 JavaScript 框架的 SPA 應用 ### 可彈性處理的場景 - **純靜態展示頁面**:無用戶互動的資訊頁面 - **開發測試環境**:但生產環境仍建議加入 - **遺留系統**:可採用漸進式實施策略 ## CSP 的核心價值 Content Security Policy 作為瀏覽器的安全機制,提供以下防護能力: - **XSS 攻擊防護**:阻止惡意腳本注入和執行 - **資源來源控制**:限制可載入的 JavaScript、CSS、圖片等資源 - **點擊劫持防護**:防止網頁被嵌入惡意框架 - **資料外洩防護**:控制資料傳輸的目標位址 ## 實務部署指南 ### 基礎設定範例 ```http Content-Security-Policy: default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:; frame-ancestors 'none'; form-action 'self'; ``` ## 部署驗證方法 ### 1. 瀏覽器開發者工具檢查 1. 開啟目標網站 2. 按 F12 開啟開發者工具 3. 切換至 Network 分頁 4. 重新載入頁面 5. 檢查主要請求的 Response Headers 是否包含 CSP 標頭 ### 2. 命令列檢測 ```bash curl -i https://your-domain.com ``` 查看回應標頭中的 `Content-Security-Policy` 欄位 ### 3. 線上檢測工具 使用 [Security Headers](https://securityheaders.com/) 進行全面的安全標頭檢測 ## 資安掃描軟體的判斷邏輯 ### 檢測機制 資安掃描工具主要透過 HTTP Response Headers 分析來判斷: ``` 檢測邏輯: IF (HTTP Response 中無 Content-Security-Policy 標頭) THEN 標記為 "CSP Header Not Set" 風險等級 = Medium 建議 = 實施 CSP 政策 END IF ``` ### 不同工具的評估標準 | 掃描工具 | 檢測範圍 | 風險等級 | 主要考量 | |---------|---------|---------|---------| | OWASP ZAP | 所有 Web 回應 | Medium | OWASP Top 10 合規 | | Nessus | 動態內容頁面 | Medium | 企業安全標準 | | Burp Suite | JavaScript 執行頁面 | Medium-High | 實際攻擊向量 | | Security Headers | 所有 HTTP 回應 | Warning | 最佳實務建議 | ### 為什麼採用統一標準? 1. **預防性安全原則**:假設所有 Web 應用都存在潛在風險 2. **自動化檢測需求**:無法動態判斷應用的複雜度和風險等級 3. **標準化合規要求**:遵循 OWASP、NIST 等安全框架 4. **成本效益考量**:統一實施比個案評估更具經濟效益 ## 分階段實施策略 ### 階段一:觀察模式 (Report-Only) ```http Content-Security-Policy-Report-Only: default-src 'self' ``` - 收集違規報告 - 分析現有應用的資源載入模式 - 評估實施影響 ### 階段二:政策調整 - 根據報告調整 CSP 規則 - 處理第三方服務整合 - 測試關鍵功能完整性 ### 階段三:正式部署 ```http Content-Security-Policy: default-src 'self'; script-src 'self' ``` - 移除 Report-Only 模式 - 監控應用運行狀況 - 建立長期維護機制 ## 技術決策建議 ### 風險評估矩陣 **高風險應用(立即實施)** - 處理用戶敏感資料 - 面向公眾的商業應用 - 金融、醫療相關系統 **中風險應用(計劃實施)** - 企業內部系統 - 有限用戶群的應用 - 資料敏感度中等的系統 **低風險應用(可延後實施)** - 純展示型網站 - 測試開發環境 - 無用戶互動的靜態頁面 ### 實施成本考量 **開發成本** - CSP 政策設計:2-4 MD - 測試和調整:4-8 MD - 文件和維護:1-2 MD **維護成本** - 定期政策檢視 - 第三方服務整合調整 - 安全事件回應機制 **綜合常見修改工作量評估** - **小型專案**:2-4 MD - **中型專案**:4-8 MD - **大型專案**:14-28 MD **耗時最多時間花在** 1. 找出所有內聯樣式和事件 2. 測試第三方函式庫相容性 3. 調整動態樣式邏輯 ## 結論與建議 CSP Header 雖非法律強制要求,但在現今的網路威脅環境下,它是一個**投資回報率極高的安全措施**。資安掃描軟體將其標記為必要檢查項目,反映了業界對於「縱深防禦」安全理念的共識。 **建議行動方案:** 1. **立即行動**:為面向公眾的生產環境實施基礎 CSP 2. **漸進部署**:採用 Report-Only 模式進行測試和調整 3. **持續優化**:建立 CSP 政策的定期檢視和更新機制 4. **團隊培訓**:確保開發團隊理解 CSP 的原理和最佳實務 記住,安全不是一次性的實施,而是持續的過程。CSP 作為現代 Web 安全架構的重要組成部分,值得每個技術團隊認真對待和實施。 ## ZAP 與 Angular 程式碼實務 以下為實際通過ZAP 運作的 CSP header 內容, 注意到它未使用了 unsafe-inline, 增加了 fallback 處理(frame-ancestors & form-action)。 ``` default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:; frame-ancestors 'none'; form-action 'self'; ``` 要讓 Angular 應用能使用最嚴格的 CSP (`'self'` only),需要進行以下修改: ## 1. Angular 建置配置修改 ### 修改 `angular.json` ```json { "projects": { "your-app": { "architect": { "build": { "options": { "extractCss": true, "optimization": true, "buildOptimizer": true, "aot": true, "vendorChunk": true, "commonChunk": true, "namedChunks": false }, "configurations": { "production": { "extractCss": true, "optimization": { "scripts": true, "styles": { "minify": true, "inlineCritical": false } } } } } } } } } ``` 關鍵設定: - `"extractCss": true` - 將所有樣式提取到外部檔案 - `"inlineCritical": false` - 禁用關鍵 CSS 內聯 ## 2. 移除內聯事件處理器 ### 修改 HTML 模板 **❌ 避免使用:** ```html <button onclick="doSomething()">按鈕</button> <div onmouseover="showTooltip()">懸停</div> ``` **✅ 改為:** ```html <button (click)="doSomething()">按鈕</button> <div (mouseover)="showTooltip()">懸停</div> ``` ## 3. 處理動態樣式 ### 使用 Angular Renderer2 **❌ 避免直接操作 style:** ```typescript // 不要這樣做 element.style.color = 'red'; element.setAttribute('style', 'color: red;'); ``` **✅ 使用 Renderer2:** ```typescript import { Renderer2, ElementRef } from '@angular/core'; constructor(private renderer: Renderer2, private el: ElementRef) {} // 設定樣式 this.renderer.setStyle(this.el.nativeElement, 'color', 'red'); // 或使用 CSS 類別 this.renderer.addClass(this.el.nativeElement, 'red-text'); ``` ### 使用 CSS 類別替代內聯樣式 **❌ 避免:** ```typescript @Component({ template: `<div [style.color]="dynamicColor">文字</div>` }) ``` **✅ 改為:** ```typescript @Component({ template: `<div [class.red-text]="isRed" [class.blue-text]="isBlue">文字</div>`, styles: [` .red-text { color: red; } .blue-text { color: blue; } `] }) ``` ## 4. 第三方函式庫處理 ### 檢查並替換有問題的函式庫 ```bash # 檢查哪些函式庫使用內聯樣式 npm audit --audit-level moderate ``` ### 常見問題函式庫替代方案 - **Bootstrap**: 使用 `ng-bootstrap` 而非原生 Bootstrap - **jQuery**: 盡量用 Angular 原生方法替代 - **圖表函式庫**: 選擇支援 CSP 的版本(如 Chart.js 配置 CSP 模式) ## 5. 測試配置 ### 本地測試 CSP 在 `src/index.html` 中暫時加入: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:;"> ``` ## 6. 建置和部署 ```bash # 使用 production 建置 ng build --configuration=production # 檢查生成的檔案中是否有內聯內容 grep -r "style=" dist/ grep -r "onclick=" dist/ ``` ## 7. 段階式驗證 ### 階段 1:先測試樣式 ``` Content-Security-Policy: default-src 'self'; style-src 'self'; script-src 'self' 'unsafe-inline'; img-src 'self' data:; ``` ### 階段 2:再測試腳本 ``` Content-Security-Policy: default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:; ``` ## 參考網站 - https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP