Content Security Policy (CSP) là một cơ chế bảo mật phía browser cho phép website khai báo nguồn nào được phép tải script, style, image, font, frame và một số loại resource khác. CSP đặc biệt hữu ích như một lớp defense-in-depth để giảm khả năng khai thác XSS, nhưng nó không thay thế việc sửa lỗ hổng gốc.
Triển khai CSP an toàn không phải copy một header mẫu rồi bật production. Quy trình đúng cần inventory resource, thiết kế trust model, thử bằng Report-Only, theo dõi violation, sửa dependency và chỉ enforce khi các luồng quan trọng đã được kiểm chứng.
CSP giải quyết bài toán gì?
Khi browser nhận header Content-Security-Policy, nó áp dụng các directive để quyết định resource nào được phép tải hoặc thực thi. Ví dụ:
Content-Security-Policy: default-src 'self'; img-src 'self' https:; object-src 'none'; base-uri 'none'
Policy trên nói rằng resource mặc định chỉ được lấy từ same-origin, image có thể dùng HTTPS, object embed bị chặn và base URI không được thay đổi.
Những directive quan trọng
- default-src: fallback cho nhiều loại resource nếu directive riêng không được khai báo.
- script-src: kiểm soát script execution và là phần quan trọng nhất với XSS mitigation.
- style-src: kiểm soát stylesheet và inline style theo policy.
- img-src: nguồn image được phép.
- connect-src: XHR, fetch, WebSocket và một số outbound connection.
- frame-src: nguồn iframe được phép tải.
- frame-ancestors: ai được phép embed trang của bạn.
- object-src: thường có thể đặt
'none'. - base-uri: giới hạn thẻ
<base>. - form-action: nơi form được phép submit.
- upgrade-insecure-requests: yêu cầu browser nâng một số HTTP resource lên HTTPS.
Allowlist CSP và Strict CSP
Allowlist CSP tin tưởng domain/location, ví dụ:
script-src 'self' https://cdn.example.com
Policy này dễ bắt đầu nhưng có thể trở nên dài, khó bảo trì và vô tình trust endpoint không an toàn.
Strict CSP dựa trên nonce hoặc hash để trust script cụ thể. MDN hiện khuyến nghị strict CSP cho XSS mitigation vì giảm phụ thuộc vào location allowlist.
Content-Security-Policy: script-src 'nonce-{RANDOM}'; object-src 'none'; base-uri 'none'
Phân tích sâu về strength của hai trust model nằm tại CSP Strict vs Allowlist.
Nonce và hash khác nhau thế nào?
Nonce
Server tạo một token khó đoán cho mỗi response và gắn cùng token vào những <script> được phép chạy. Browser chỉ thực thi script có nonce phù hợp với policy.
Nonce phù hợp với application render dynamic HTML, nhưng cần bảo đảm nonce được tạo mới đúng cách và không bị cache/reuse ngoài thiết kế.
Hash
Policy chứa hash của exact script content. Browser chỉ chạy script có hash khớp. Hash phù hợp hơn với static script content nhưng cần cập nhật mỗi khi content thay đổi.
'strict-dynamic' để làm gì?
'strict-dynamic' cho phép trust truyền từ script đã có nonce/hash sang script mà trusted script tạo động. Nó giúp giảm host allowlist dài trong modern application.
Nhưng trusted script vẫn phải an toàn. Nếu trusted loader tạo script từ input attacker-controlled thì trust có thể bị truyền sai. Vì vậy CSP không thay thế secure coding.
Vì sao nên bắt đầu bằng Report-Only?
Content-Security-Policy-Report-Only cho phép browser báo violation mà chưa block resource. Đây là bước rất hữu ích trước enforcement vì giúp thấy resource nào sẽ bị chặn mà không làm vỡ giao diện hoặc chức năng production.
Quy trình rollout khuyến nghị:
- inventory script/style/image/frame/connect sources;
- viết policy ban đầu;
- deploy Report-Only;
- thu thập violation;
- phân loại false positive và dependency thật;
- giảm allowlist, thêm nonce/hash nếu phù hợp;
- test login, checkout, form, analytics, admin và mobile;
- enforce trên pilot hoặc phạm vi nhỏ;
- theo dõi error và violation sau rollout.
Report-Only không phải protection
Report-Only chỉ quan sát. Resource vi phạm policy vẫn được tải/thực thi. Audit cần phân biệt rõ header enforce với header report-only.
Những lỗi CSP phổ biến
- Dùng
*hoặc allowlist quá rộng. - Thêm
'unsafe-inline'để “cho site chạy lại” mà không hiểu impact. - Copy policy của website khác.
- Enforce trực tiếp production không có Report-Only.
- Không test admin route, checkout, payment, consent manager hoặc analytics.
- Chỉ nhìn header text mà không kiểm effective behavior trên browser mục tiêu.
- Dùng CSP như lý do không sửa XSS gốc.
CSP cho WordPress cần chú ý gì?
WordPress thường có plugin/theme thêm inline script, page builder, analytics và third-party tags. Một strict CSP cần hiểu chính xác ai render script và có thể truyền nonce/hash thế nào.
Nếu mục tiêu là WordPress-specific rollout, xem Content Security Policy cho WordPress.
CSP và các Security Headers khác
CSP không thay HSTS. upgrade-insecure-requests không phải cơ chế tương đương HSTS cho future navigation. HSTS quản lý transport upgrade và browser memory ở cấp host; CSP quản lý resource và browser execution policy.
Xem thêm Security Headers cho website.
Checklist trước enforcement
- Đã inventory third-party script/style/frame/connect.
- Đã chọn nonce/hash hay allowlist với lý do rõ ràng.
- Đã dùng Report-Only.
- Đã có reporting endpoint nếu cần.
- Đã test các route business-critical.
- Đã loại bỏ allowlist không cần thiết.
- Đã kiểm browser support của policy.
- Đã có rollback nhanh nếu enforcement gây regression.
Kết luận
CSP hiệu quả không nằm ở việc header có tồn tại, mà ở trust model và cách rollout. Policy tốt phải đủ chặt để giảm exploit path nhưng vẫn phù hợp với resource graph thật của application.
