Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 

7.2 KiB

CSP Report Review (PROD + UAT, 2026-08-14)

Review of Content-Security-Policy-Report-Only violations from PNSPS PROD (https://pnsps.gld.gov.hk) and UAT (https://pnspsuat.gld.gov.hk), for deciding Apache CSP updates.

Source logs (external):

  • P1 CSP.txt — PROD node, 168 reports, 2026-07-30 to 2026-08-14
  • P2 CSP.txt — PROD node, 137 reports, 2026-07-30 to 2026-08-14
  • TT CSP.txt — UAT, 133 reports, 2026-05-29 to 2026-08-03

Related app docs:


Verdict

CSP is still Report-Only (disposition: report) — nothing is blocking users yet. There is one real PNSPS SPA problem (proof PDF preview frame-src). Everything else is browser-extension noise or a different app on the same UAT host.

The 2026-08-03 recommendation to add frame-src is still not on the live header.


Add / remove summary

PROD — add one line, remove nothing:

frame-src 'self' data: blob:;

Keep script-src 'self'. Do not add 'unsafe-inline' or 'unsafe-eval'.

UAT — add the same line, remove nothing now:

frame-src 'self' data: blob:;

Keep script-src 'self' 'unsafe-inline' 'unsafe-eval' for now (JSF payment recon on the same host). Do not copy this script-src to PROD.

Do not add on either env: 'wasm-unsafe-eval', Youdao, NetEase CDN, todesktop-internal, Google Fonts.

Optional later (not required for these reports): UAT can drop 'unsafe-inline' 'unsafe-eval' from the SPA header only after /paymentrecon-dept_web/ has its own CSP.


Confirmed current PROD policy (Report-Only)

This is the live header that generated the P1/P2 reports. It matches the original-policy in every PROD violation.

Header always set Content-Security-Policy-Report-Only "default-src 'self'; \
	base-uri 'self'; \
	object-src 'none'; \
	frame-ancestors 'none'; \
	form-action 'self'; \
	script-src 'self'; \
	style-src 'self' 'unsafe-inline'; \
	style-src-elem 'self' 'unsafe-inline'; \
	img-src 'self' data: https://www.w3.org https://w3.org; \
	media-src 'self' blob:; \
	font-src 'self' data:; \
	connect-src 'self'; \
	upgrade-insecure-requests; \
	report-uri https://pnsps.gld.gov.hk/api/csp-report"

Gap vs the reports: no frame-src. Framing therefore falls back to default-src 'self', which is why proof PDF preview reports frame-src with an empty blocked-uri.


Confirmed current UAT policy (Report-Only)

Header always set Content-Security-Policy-Report-Only "default-src 'self'; \
	base-uri 'self'; \
	object-src 'none'; \
	frame-ancestors 'none'; \
	form-action 'self'; \
	script-src 'self' 'unsafe-inline' 'unsafe-eval'; \
	style-src 'self' 'unsafe-inline'; \
	style-src-elem 'self' 'unsafe-inline'; \
	img-src 'self' data: https://www.w3.org https://w3.org; \
	media-src 'self' blob:; \
	font-src 'self' data:; \
	connect-src 'self'; \
	upgrade-insecure-requests; \
	report-uri https://pnspsuat.gld.gov.hk/api/csp-report"

UAT vs PROD differences:

  • UAT script-src is 'self' 'unsafe-inline' 'unsafe-eval' — PROD is 'self' only.
  • Both still lack frame-src.
  • TT report original-policy was older: script-src 'self' 'unsafe-inline' without 'unsafe-eval'. That is why TT logged 42 JSF eval hits. Those should stop under the current UAT header.

Do not copy 'unsafe-inline' or 'unsafe-eval' onto PROD. The React SPA does not need them. 'unsafe-eval' is only there for the shared-host JSF payment recon app.


Real problem (PROD P1 + P2)

Volume Directive Blocked Pages
150 frame-src empty "" /proof/create/{id}

Source is always static/js/4608.4af455e6.chunk.js. Cause is proof file preview in src/pages/Proof/Create_FromApp/UploadFileTable.js: FileReader.readAsDataURL then document.write an <iframe src="data:...">. With no frame-src, CSP uses default-src 'self' and blocks data: frames. Browsers strip the data: URI from reports (empty blocked-uri).

If this policy is promoted to enforcing without frame-src, PDF preview on proof create will break.

Apache fix (already documented in csp-apache.conf.md, not deployed):

frame-src 'self' data: blob:;

Optional frontend follow-up: switch preview to URL.createObjectURL + blob: (still needs frame-src ... blob:).

Optional (low priority): media-src 'self' blob: data:; — current blob: already covers captcha audio.


Not a PNSPS SPA problem — do not allowlist

Volume Where Directive Blocked Why ignore
109 PROD script-src wasm-eval source-file: chrome-extension
18 PROD media-src dict.youdao.com Youdao translation plugin
11 PROD img-src ydlunacommon-cdn.nosdn.127.net Youdao/NetEase CDN icons
3 PROD P2 script-src-elem todesktop-internal Desktop wrapper
105 PROD 14 + UAT 91 img-src www.w3.org/WAI/wcag2AA Already allowed in policy; mostly SPA status-code: 404 noise. Badge is in src/components/cards/AuthFooter.js.

Do not add 'unsafe-eval', 'wasm-unsafe-eval', Youdao, NetEase, or todesktop-internal to the SPA policy.


UAT-only: payment recon JSF (not the React app)

42 TT reports: script-src / eval on:

  • /paymentrecon-dept_web/report/paymentReconRpt01Search.jsf (38)
  • /paymentrecon-dept_web/report/paymentReconRpt02Search.jsf (3)
  • /paymentrecon-dept_web/manualrecon/manualReconSearch.jsf (1)

This is a separate JSF app on the same Apache host. The TT logs were generated under the old UAT policy (script-src 'self' 'unsafe-inline'). Current UAT already adds 'unsafe-eval', so those eval reports should disappear.

That UAT looseness is a workaround for JSF, not a requirement of PNSPS. Before enforcing CSP:

  • Keep PROD at script-src 'self' (do not add 'unsafe-eval').
  • Prefer a path-specific header for /paymentrecon-dept_web/ on UAT so the SPA can later drop 'unsafe-inline' / 'unsafe-eval'.

  1. Add frame-src 'self' data: blob:; to both PROD and UAT Report-Only headers. Do not change PROD script-src 'self'.
  2. Confirm proof-create preview reports drop after that deploy.
  3. Keep Report-Only until frame-src volume is gone; remaining extension noise is expected.
  4. Do not promote UAT’s 'unsafe-inline' 'unsafe-eval' to PROD. Those tokens exist for JSF payment recon on the shared UAT host.
  5. Optional: give /paymentrecon-dept_web/ its own Apache CSP so UAT SPA can later match PROD (script-src 'self').
  6. Optional later: host the WCAG badge locally to cut img-src noise; change preview to blob: URLs.

No application code change is required for the reports to become clean after the Apache frame-src deploy.


Backend reference

  • Report endpoint: POST /csp-report (context path → /api/csp-report)
  • Spring Security also sets a short API CSP on API responses (default-src 'self'; script-src 'self'; frame-ancestors 'self'). Frontend/Apache CSP above is what browsers enforce for the SPA document.