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.

csp-report-review-2026-08-14.md 7.3 KiB

​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
vor 5 Tagen
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. # CSP Report Review (PROD + UAT, 2026-08-14)
  2. Review of Content-Security-Policy-Report-Only violations from PNSPS PROD
  3. (`https://pnsps.gld.gov.hk`) and UAT (`https://pnspsuat.gld.gov.hk`), for
  4. deciding Apache CSP updates.
  5. Source logs (external):
  6. - `P1 CSP.txt` — PROD node, 168 reports, 2026-07-30 to 2026-08-14
  7. - `P2 CSP.txt` — PROD node, 137 reports, 2026-07-30 to 2026-08-14
  8. - `TT CSP.txt` — UAT, 133 reports, 2026-05-29 to 2026-08-03
  9. Related app docs:
  10. - [csp-apache.conf.md](./csp-apache.conf.md) — Apache header snippets to deploy
  11. - [csp-report-review-2026-08-03.md](./csp-report-review-2026-08-03.md) — earlier PROD review
  12. - [csp-report-review-2026-09-22.md](./csp-report-review-2026-09-22.md) — later PROD review (`All_CSP.txt`)
  13. ---
  14. ## Verdict
  15. CSP is still **Report-Only** (`disposition: report`) — nothing is blocking users
  16. yet. There is **one real PNSPS SPA problem** (proof PDF preview `frame-src`).
  17. Everything else is browser-extension noise or a **different app** on the same
  18. UAT host.
  19. The 2026-08-03 recommendation to add `frame-src` is **still not on the live
  20. header**.
  21. ---
  22. ## Add / remove summary
  23. **PROD — add one line, remove nothing:**
  24. ```apache
  25. frame-src 'self' data: blob:;
  26. ```
  27. Keep `script-src 'self'`. Do not add `'unsafe-inline'` or `'unsafe-eval'`.
  28. **UAT — add the same line, remove nothing now:**
  29. ```apache
  30. frame-src 'self' data: blob:;
  31. ```
  32. Keep `script-src 'self' 'unsafe-inline' 'unsafe-eval'` for now (JSF payment recon
  33. on the same host). Do not copy this `script-src` to PROD.
  34. **Do not add on either env:** `'wasm-unsafe-eval'`, Youdao, NetEase CDN,
  35. `todesktop-internal`, Google Fonts.
  36. **Optional later (not required for these reports):** UAT can drop
  37. `'unsafe-inline' 'unsafe-eval'` from the SPA header only after
  38. `/paymentrecon-dept_web/` has its own CSP.
  39. ---
  40. ## Confirmed current PROD policy (Report-Only)
  41. This is the live header that generated the P1/P2 reports. It matches the
  42. `original-policy` in every PROD violation.
  43. ```apache
  44. Header always set Content-Security-Policy-Report-Only "default-src 'self'; \
  45. base-uri 'self'; \
  46. object-src 'none'; \
  47. frame-ancestors 'none'; \
  48. form-action 'self'; \
  49. script-src 'self'; \
  50. style-src 'self' 'unsafe-inline'; \
  51. style-src-elem 'self' 'unsafe-inline'; \
  52. img-src 'self' data: https://www.w3.org https://w3.org; \
  53. media-src 'self' blob:; \
  54. font-src 'self' data:; \
  55. connect-src 'self'; \
  56. upgrade-insecure-requests; \
  57. report-uri https://pnsps.gld.gov.hk/api/csp-report"
  58. ```
  59. Gap vs the reports: **no `frame-src`**. Framing therefore falls back to
  60. `default-src 'self'`, which is why proof PDF preview reports `frame-src` with
  61. an empty `blocked-uri`.
  62. ---
  63. ## Confirmed current UAT policy (Report-Only)
  64. ```apache
  65. Header always set Content-Security-Policy-Report-Only "default-src 'self'; \
  66. base-uri 'self'; \
  67. object-src 'none'; \
  68. frame-ancestors 'none'; \
  69. form-action 'self'; \
  70. script-src 'self' 'unsafe-inline' 'unsafe-eval'; \
  71. style-src 'self' 'unsafe-inline'; \
  72. style-src-elem 'self' 'unsafe-inline'; \
  73. img-src 'self' data: https://www.w3.org https://w3.org; \
  74. media-src 'self' blob:; \
  75. font-src 'self' data:; \
  76. connect-src 'self'; \
  77. upgrade-insecure-requests; \
  78. report-uri https://pnspsuat.gld.gov.hk/api/csp-report"
  79. ```
  80. UAT vs PROD differences:
  81. - UAT `script-src` is `'self' 'unsafe-inline' 'unsafe-eval'` — PROD is `'self'` only.
  82. - Both still lack `frame-src`.
  83. - TT report `original-policy` was older: `script-src 'self' 'unsafe-inline'`
  84. **without** `'unsafe-eval'`. That is why TT logged 42 JSF `eval` hits. Those
  85. should stop under the current UAT header.
  86. Do **not** copy `'unsafe-inline'` or `'unsafe-eval'` onto PROD. The React SPA
  87. does not need them. `'unsafe-eval'` is only there for the shared-host JSF
  88. payment recon app.
  89. ---
  90. ## Real problem (PROD P1 + P2)
  91. | Volume | Directive | Blocked | Pages |
  92. |---:|---|---|---|
  93. | 150 | `frame-src` | empty `""` | `/proof/create/{id}` |
  94. Source is always `static/js/4608.4af455e6.chunk.js`. Cause is proof file preview
  95. in `src/pages/Proof/Create_FromApp/UploadFileTable.js`:
  96. `FileReader.readAsDataURL` then `document.write` an `<iframe src="data:...">`.
  97. With no `frame-src`, CSP uses `default-src 'self'` and blocks `data:` frames.
  98. Browsers strip the `data:` URI from reports (empty `blocked-uri`).
  99. **If this policy is promoted to enforcing without `frame-src`, PDF preview on
  100. proof create will break.**
  101. Apache fix (already documented in [csp-apache.conf.md](./csp-apache.conf.md),
  102. not deployed):
  103. ```apache
  104. frame-src 'self' data: blob:;
  105. ```
  106. Optional frontend follow-up: switch preview to `URL.createObjectURL` + `blob:`
  107. (still needs `frame-src ... blob:`).
  108. Optional (low priority): `media-src 'self' blob: data:;` — current `blob:`
  109. already covers captcha audio.
  110. ---
  111. ## Not a PNSPS SPA problem — do not allowlist
  112. | Volume | Where | Directive | Blocked | Why ignore |
  113. |---:|---|---|---|---|
  114. | 109 | PROD | `script-src` | `wasm-eval` | `source-file: chrome-extension` |
  115. | 18 | PROD | `media-src` | `dict.youdao.com` | Youdao translation plugin |
  116. | 11 | PROD | `img-src` | `ydlunacommon-cdn.nosdn.127.net` | Youdao/NetEase CDN icons |
  117. | 3 | PROD P2 | `script-src-elem` | `todesktop-internal` | Desktop wrapper |
  118. | 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`. |
  119. Do **not** add `'unsafe-eval'`, `'wasm-unsafe-eval'`, Youdao, NetEase, or
  120. `todesktop-internal` to the SPA policy.
  121. ---
  122. ## UAT-only: payment recon JSF (not the React app)
  123. 42 TT reports: `script-src` / `eval` on:
  124. - `/paymentrecon-dept_web/report/paymentReconRpt01Search.jsf` (38)
  125. - `/paymentrecon-dept_web/report/paymentReconRpt02Search.jsf` (3)
  126. - `/paymentrecon-dept_web/manualrecon/manualReconSearch.jsf` (1)
  127. This is a **separate JSF app** on the same Apache host. The TT logs were
  128. generated under the **old** UAT policy (`script-src 'self' 'unsafe-inline'`).
  129. Current UAT already adds `'unsafe-eval'`, so those `eval` reports should
  130. disappear.
  131. That UAT looseness is a workaround for JSF, not a requirement of PNSPS. Before
  132. enforcing CSP:
  133. - Keep PROD at `script-src 'self'` (do not add `'unsafe-eval'`).
  134. - Prefer a path-specific header for `/paymentrecon-dept_web/` on UAT so the SPA
  135. can later drop `'unsafe-inline'` / `'unsafe-eval'`.
  136. ---
  137. ## Recommended actions (ops / Apache, not app code)
  138. 1. Add `frame-src 'self' data: blob:;` to both PROD and UAT Report-Only headers.
  139. Do not change PROD `script-src 'self'`.
  140. 2. Confirm proof-create preview reports drop after that deploy.
  141. 3. Keep Report-Only until `frame-src` volume is gone; remaining extension noise
  142. is expected.
  143. 4. Do not promote UAT's `'unsafe-inline' 'unsafe-eval'` to PROD. Those tokens
  144. exist for JSF payment recon on the shared UAT host.
  145. 5. Optional: give `/paymentrecon-dept_web/` its own Apache CSP so UAT SPA can
  146. later match PROD (`script-src 'self'`).
  147. 6. Optional later: host the WCAG badge locally to cut `img-src` noise; change
  148. preview to `blob:` URLs.
  149. No application code change is required for the reports to become clean after
  150. the Apache `frame-src` deploy.
  151. ---
  152. ## Backend reference
  153. - Report endpoint: `POST /csp-report` (context path → `/api/csp-report`)
  154. - Spring Security also sets a short API CSP on API responses
  155. (`default-src 'self'; script-src 'self'; frame-ancestors 'self'`).
  156. Frontend/Apache CSP above is what browsers enforce for the SPA document.