Content Security Policy cho WordPress: rollout CSP an toàn

Cách triển khai Content Security Policy cho WordPress bằng inventory, Report-Only, nonce/hash, frame-ancestors và rollout có kiểm soát.

Content Security Policy cho WordPress với kiểm soát nguồn tải, XSS protection, policy tuning và violation reporting

Content Security Policy (CSP) cho WordPress nên được rollout như một change có kiểm soát, không phải copy một header “cứng” rồi bật ngay trên production. Mục tiêu của CSP là giới hạn nguồn tài nguyên mà browser được phép tải/thực thi và giảm impact của XSS/content injection. Nhưng WordPress thường có inline script/style, page builder, plugin frontend, analytics, font, CDN, iframe và third-party integration; policy quá chặt có thể làm hỏng login, checkout, form, media hoặc admin flow.

Quy trình tốt là inventory → Report-Only → phân loại violation → refactor/nonce/hash → pilot enforcement → full enforcement → monitoring + rollback.

CSP kiểm soát những lớp nào?

Directive Vai trò Điểm cần lưu ý
default-src Fallback cho nhiều fetch directive Không thay mọi directive; một số directive như frame-ancestors không fallback từ đây
script-src Kiểm soát JavaScript Strict CSP thường dùng nonce/hash
style-src Kiểm soát CSS WordPress/plugin có thể dùng inline style
img-src Kiểm soát image source Cần xét CDN/data URI nếu thực sự dùng
font-src Kiểm soát font source Hay bị bỏ sót khi dùng font ngoài
connect-src XHR/fetch/WebSocket/beacon Ảnh hưởng API, analytics, realtime
frame-src Page được phép load iframe từ đâu Khác với frame-ancestors
frame-ancestors Ai được phép embed trang của bạn Defense against clickjacking
base-uri Giới hạn <base> Hữu ích trong strict CSP
object-src Kiểm soát object/embed Strict policy thường đặt 'none'

Đừng bắt đầu bằng allowlist domain khổng lồ

Policy dựa chủ yếu vào danh sách host thường phình to khi site dùng nhiều vendor và dễ vô tình cho phép domain rộng hơn cần thiết. Với script/style quan trọng, nonce hoặc hash giúp ràng buộc execution chặt hơn. Tuy nhiên nonce phải được tạo mới cho mỗi response và không đoán được; đây là thay đổi kiến trúc chứ không chỉ chỉnh header.

WordPress/plugin ecosystem có thể khiến strict CSP phức tạp hơn. Vì vậy cần inventory owner và refactor dần, thay vì thêm 'unsafe-inline' hoặc wildcard mỗi khi gặp violation.

Inventory trước rollout

Resource Owner Source Route sử dụng Action
Core/theme JS Theme/core self Frontend Allow / nonce/hash nếu cần
Plugin JS/CSS Plugin self/CDN Frontend/admin Verify owner + route
Analytics/tag manager Marketing/Security Third-party Selected routes Need + data flow review
Payment/SSO iframe Business integration Third-party Checkout/login Frame/connect/form dependencies
Fonts/images Theme/design self/CDN Frontend Allow minimal source

Nếu resource không có owner hoặc business reason, trạng thái nên là INVESTIGATE, không phải auto-allow.

Stage 1 — Report-Only trước enforcement

Dùng Content-Security-Policy-Report-Only để browser báo violation nhưng chưa block resource. Đây là phase để tìm dependency thật và false positive trước khi enforcement.

Content-Security-Policy-Report-Only:
  default-src 'self';
  script-src 'self' 'nonce-<dynamic-value>';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'self';
  report-to csp-endpoint;
  report-uri /csp-report

Header trên chỉ là cấu trúc minh họa. Không copy nguyên vào production nếu site chưa có nonce generation, reporting endpoint và dependency inventory.

Violation Triage Matrix

Violation Owner Legitimate? Decision
script-src-elem blocked third-party Unknown Unknown Investigate, không auto-allow
Inline script bị block Theme/plugin Có thể Refactor hoặc nonce/hash
Connect tới API vendor Integration Nếu flow cần Allow minimal origin
Frame bị block Payment/SSO/widget Tùy route Review frame-src / vendor flow
Violation từ injected script lạ Không owner Không Security investigation, không nới policy

Violation Report Record mẫu

report_id: CSP-YYYY-NNN
policy_version: v1-report-only
document_uri: ...
violated_directive: script-src-elem
blocked_uri: ...
source_file: ...
line_number: ...
route: frontend|login|admin|checkout
owner: core|theme|plugin|tag-manager|vendor|unknown
legitimate: yes|no|unknown
decision: allow|minimize|nonce|hash|remove|investigate
change_ref: ...
validation_ref: ...

Nonce và hash: dùng khi nào?

Nonce phù hợp khi server có thể sinh giá trị ngẫu nhiên mới cho từng response và gắn cùng nonce vào các script/style được phép. Hash phù hợp hơn với nội dung tĩnh có thể fingerprint ổn định. Không reuse nonce cố định giữa các response vì làm mất mục tiêu bảo mật.

Trong WordPress, nonce CSP khác với WordPress nonce dùng cho CSRF/action validation; không nên nhầm hai khái niệm.

frame-ancestors và clickjacking

frame-ancestors xác định origin nào được phép embed page của bạn. Nếu site không cần bị embed, policy chặt có thể dùng 'none'. Nếu có portal/payment/support integration, chỉ allow đúng parent origin cần thiết.

frame-ancestors khác frame-src: một cái kiểm parent được embed bạn, cái kia kiểm page của bạn load iframe từ đâu.

Stage 2 — Pilot enforcement

Sau Report-Only, đừng chuyển toàn site sang enforcement một lần nếu blast radius lớn. Chọn route/user flow đại diện và có rollback:

  1. Frontend public route.
  2. Login/logout/password reset.
  3. Admin/editor flow cần thiết.
  4. Form/contact.
  5. Checkout/payment/SSO nếu có.
  6. Media/embed/page builder route.

Trong pilot, giữ Report-Only policy mới song song với enforced policy hiện tại nếu cần test revision tiếp theo.

Acceptance Test Matrix

Flow PASS FAIL
Frontend render JS/CSS/media cần thiết hoạt động Layout/function chính bị block
Login/admin Auth và admin action hoạt động Login/editor/plugin flow lỗi
Form/checkout Submit/payment callback hoạt động Connect/frame/form endpoint bị block
Security Injected/unapproved test resource bị CSP chặn hoặc report đúng Policy phải nới rộng mới “hết lỗi”
Monitoring Violation report tới đúng endpoint Report pipeline mất dữ liệu

Rollback Plan

Trước enforcement, lưu policy/version hiện tại và điểm cấu hình tạo header: web server, CDN, reverse proxy, security plugin hoặc application. Nếu business flow critical fail:

  1. Quay về policy version trước đã PASS.
  2. Không xóa toàn bộ CSP trừ khi rollback plan đã xác định như vậy.
  3. Ghi route/directive/resource gây fail.
  4. Chuyển revision mới về Report-Only.
  5. Fix owner/dependency rồi pilot lại.

Không dùng CSP để che lỗ hổng ứng dụng

CSP là defense-in-depth, không thay sanitize/escape output, permission check, input validation, patch plugin/theme hoặc incident remediation. Nếu CSP report phát hiện injected script lạ, đó là tín hiệu cần điều tra source chèn code, không phải lý do thêm domain vào allowlist.

Liên kết với security headers và HTTPS

CSP là một phần của browser security controls. Xem Security headers cho WordPress để phối hợp với HSTS, nosniff và các header khác. Trước khi rollout HSTS hoặc CSP yêu cầu HTTPS-only resource, đối chiếu HTTPS/TLS WordPress an toàn.

PASS/FAIL cho rollout CSP

  • PASS: dependency inventory có owner; Report-Only đã chạy đủ route; violation được phân loại; pilot flow PASS; policy version + rollback rõ; reporting hoạt động.
  • FAIL: bật enforcement trực tiếp; dùng wildcard/'unsafe-inline' rộng chỉ để hết lỗi; không biết owner resource; login/checkout/admin bị phá; hoặc reporting không hoạt động.
  • HOLD: còn violation chưa biết owner hoặc route critical chưa test. HOLD phải tiếp tục Report-Only/pilot, không được ép sang full enforcement.

Nguồn kỹ thuật

Kết luận

CSP WordPress tốt không phải policy “càng chặt càng tốt”, mà là policy đủ chặt, có owner, có evidence và không phá business flow. Rollout đúng là inventory → Report-Only → violation triage → nonce/hash/refactor → pilot enforcement → full enforcement → monitoring + rollback.

◇
Cần hỗ trợ kiểm tra và xử lý website?Đội ngũ SecureWebOps sẵn sàng hỗ trợ theo phạm vi phù hợp.
Liên hệ ngay →
Đoàn Trình Dục
Về tác giả Đoàn Trình Dục TD Digital · Website Operations & Security

Đoàn Trình Dục là tác giả nội dung trên SecureWebOps. Các bài viết tập trung vào bảo mật WordPress, giám sát an ninh website, malware/backdoor, hardening, backup/recovery và Incident Response theo hướng thực hành, có bước kiểm tra, bằng chứng, validation và rollback khi phù hợp.

Xem hồ sơ tác giả →