CSP Content Security Policy 前端 angular

CSP Header 是必要的嗎?

陳瑞泰 John Chen 2025/06/08 23:35:24
5

 

CSP Header 是必要的嗎?

作為軟體公司的技術管理者,您可能經常遇到資安掃描報告中出現「CSP Header Not Set」的警告。本文將深入探討 Content Security Policy (CSP) 的必要性、實作方式,以及為什麼資安掃描工具會將其視為必要檢查項目。

CSP 是否為強制性要求?

答案是:不是強制性的,但強烈建議實施。

CSP 的實施優先級取決於您的應用場景:

高優先級場景

  • 面向公眾的網站:直接暴露於網際網路的應用
  • 敏感資料處理:涉及金融、醫療、個人隱私資料的系統
  • 企業級應用:即使是內部系統,也需要多層防護
  • 合規要求:PCI DSS、GDPR 等法規標準的要求
  • 現代化應用:大量使用 JavaScript 框架的 SPA 應用

可彈性處理的場景

  • 純靜態展示頁面:無用戶互動的資訊頁面
  • 開發測試環境:但生產環境仍建議加入
  • 遺留系統:可採用漸進式實施策略

CSP 的核心價值

Content Security Policy 作為瀏覽器的安全機制,提供以下防護能力:

  • XSS 攻擊防護:阻止惡意腳本注入和執行
  • 資源來源控制:限制可載入的 JavaScript、CSS、圖片等資源
  • 點擊劫持防護:防止網頁被嵌入惡意框架
  • 資料外洩防護:控制資料傳輸的目標位址

實務部署指南 基礎設定範例

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. 命令列檢測

curl -i https://your-domain.com

查看回應標頭中的 Content-Security-Policy 欄位

3. 線上檢測工具

使用 Security Headers 進行全面的安全標頭檢測

資安掃描軟體的判斷邏輯 檢測機制

資安掃描工具主要透過 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)

Content-Security-Policy-Report-Only: default-src 'self'
  • 收集違規報告
  • 分析現有應用的資源載入模式
  • 評估實施影響

階段二:政策調整

  • 根據報告調整 CSP 規則
  • 處理第三方服務整合
  • 測試關鍵功能完整性

階段三:正式部署

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

{
  "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 模板

❌ 避免使用:

<button onclick="doSomething()">按鈕</button>
<div onmouseover="showTooltip()">懸停</div>

✅ 改為:

<button (click)="doSomething()">按鈕</button>
<div (mouseover)="showTooltip()">懸停</div>

3. 處理動態樣式 使用 Angular Renderer2

❌ 避免直接操作 style:

// 不要這樣做
element.style.color = 'red';
element.setAttribute('style', 'color: red;');

✅ 使用 Renderer2:

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 類別替代內聯樣式

❌ 避免:

@Component({
  template: `<div [style.color]="dynamicColor">文字</div>`
})

✅ 改為:

@Component({
  template: `<div [class.red-text]="isRed" [class.blue-text]="isBlue">文字</div>`,
  styles: [`
    .red-text { color: red; }
    .blue-text { color: blue; }
  `]
})

4. 第三方函式庫處理 檢查並替換有問題的函式庫

# 檢查哪些函式庫使用內聯樣式
npm audit --audit-level moderate

常見問題函式庫替代方案

  • Bootstrap: 使用 ng-bootstrap 而非原生 Bootstrap
  • jQuery: 盡量用 Angular 原生方法替代
  • 圖表函式庫: 選擇支援 CSP 的版本(如 Chart.js 配置 CSP 模式)

5. 測試配置 本地測試 CSP

src/index.html 中暫時加入:

<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:;">

6. 建置和部署

# 使用 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:;

參考網站

陳瑞泰 John Chen