Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

csp-report-review-2026-09-22.md 6.3 KiB

6 дней назад
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. # CSP Report Review (PROD, 2026-09-22)
  2. Review of Content-Security-Policy-Report-Only violations from PNSPS PROD
  3. (`https://pnsps.gld.gov.hk`).
  4. Source logs (external):
  5. - `All_CSP.txt` — 196 reports, 2026-08-27 to 2026-09-17
  6. Related app docs:
  7. - [csp-apache.conf.md](./csp-apache.conf.md) — Apache header snippets to deploy
  8. - [csp-report-review-2026-08-14.md](./csp-report-review-2026-08-14.md) — earlier PROD + UAT review
  9. - [csp-report-review-2026-08-03.md](./csp-report-review-2026-08-03.md) — earlier PROD review
  10. ---
  11. ## Verdict
  12. **No app-side CSP concern in this dump.** Almost every line is a browser
  13. extension, not PNSPS code. `/proof/reply/{id}` is just a busy authenticated
  14. page, so the same extension noise shows up there a lot.
  15. CSP is still **Report-Only** (`disposition: report`) — the browser logged these
  16. hits and **did not block the page**.
  17. The 2026-08-14 app-owned issue (proof PDF preview `frame-src`) is **gone** from
  18. this dump. Live PROD now includes `frame-src 'self' data: blob:;`.
  19. ---
  20. ## Add / remove summary
  21. **PROD — add nothing required. Remove nothing.**
  22. Keep `script-src 'self'`. Do not add `'unsafe-inline'`, `'unsafe-eval'`, or
  23. `'wasm-unsafe-eval'`.
  24. **Optional (low priority, already in [csp-apache.conf.md](./csp-apache.conf.md)):**
  25. ```apache
  26. media-src 'self' blob: data:;
  27. ```
  28. Live PROD is still `media-src 'self' blob:` (no `data:`). This dump has only
  29. 2 matching hits in three weeks.
  30. **Do not add:** `'wasm-unsafe-eval'`, Perplexity CDN, Youdao, NetEase CDN,
  31. Google Fonts.
  32. ---
  33. ## Confirmed current PROD policy (Report-Only)
  34. This is the live header that generated every report in `All_CSP.txt`. It matches
  35. `original-policy` in all 196 violations.
  36. ```apache
  37. Header always set Content-Security-Policy-Report-Only "default-src 'self'; \
  38. base-uri 'self'; \
  39. object-src 'none'; \
  40. frame-ancestors 'none'; \
  41. frame-src 'self' data: blob:; \
  42. form-action 'self'; \
  43. script-src 'self'; \
  44. style-src 'self' 'unsafe-inline'; \
  45. style-src-elem 'self' 'unsafe-inline'; \
  46. img-src 'self' data:; \
  47. media-src 'self' blob:; \
  48. font-src 'self' data:; \
  49. connect-src 'self'; \
  50. upgrade-insecure-requests; \
  51. report-uri https://pnsps.gld.gov.hk/api/csp-report"
  52. ```
  53. Changes vs the 2026-08-14 live header:
  54. - `frame-src 'self' data: blob:;` is now present.
  55. - `img-src` no longer allowlists `https://www.w3.org` / `https://w3.org`
  56. (badge is hosted locally).
  57. `style-src 'unsafe-inline'` is expected for MUI and is the only real policy
  58. weakness. These reports do not show a new XSS issue.
  59. ---
  60. ## Summary of findings
  61. | Count | Directive | Blocked | Verdict |
  62. |---:|---|---|---|
  63. | **192** | `script-src` | `wasm-eval` | Noise — Chrome extension |
  64. | 2 | `media-src` | `data` | Optional leftover — `data:` not in live `media-src` |
  65. | 1 | `font-src` | `frontend-cdn.perplexity.ai` … `FKGroteskNeue.woff2` | Noise — Perplexity sidebar |
  66. | 1 | `img-src` | `ydlunacommon-cdn.nosdn.127.net` … `.svg` | Noise — Youdao / NetEase plugin |
  67. No `frame-src` reports. No app `eval`. No Google Fonts.
  68. ---
  69. ## Why `wasm-eval` volume is high
  70. 192 of 196 reports (98%) are `script-src` / `wasm-eval`.
  71. | Count | `source-file` | Notes |
  72. |---:|---|---|
  73. | 103 | `chrome-extension` | Every one with a location is **line 23, column 39316** — the same injected script |
  74. | 89 | (none) | Chrome often sends a second report for the same violation without `source-file` |
  75. About 46 timestamps have 2+ reports in the same second (paired duplicates).
  76. That is why the log looks twice as large as the number of real events.
  77. Password managers, translators, Grammarly-style tools, and similar extensions
  78. compile WebAssembly into the page. `script-src 'self'` (without
  79. `'wasm-unsafe-eval'`) reports that. Do **not** loosen `script-src` to silence
  80. it.
  81. If quieter logs are needed, filter `blocked-uri=wasm-eval` plus
  82. `source-file=chrome-extension` (and the paired empty-source twin).
  83. ---
  84. ## Why many `/proof/reply` reports
  85. | Count | Page group |
  86. |---:|---|
  87. | 90 | `/login` |
  88. | **38** | `/proof/reply/{id}` |
  89. | 23 | `/publicNotice/{id}` |
  90. | 15 | `/publicNotice/apply` |
  91. | 10 | `/publicNotice` |
  92. | 10 | `/proof/search` |
  93. | 4 | `/paymentPage/*` |
  94. | 3 | `/user/changePassword` |
  95. | 2 | `/registerFromOrganization` |
  96. | 1 | `/verify/*` |
  97. The 38 Reply Proof hits span **12 proof IDs** (`29518`, `29948`, `30112`,
  98. `30114`, `30134`, `30166`, `30190`, `30266`, `30306`, `30326`, `30484`,
  99. `30958`). They are the same `wasm-eval` + Chrome extension pattern as login,
  100. apply, and notice detail.
  101. Reply Proof is a long, authenticated screen. Anyone with a WASM extension
  102. triggers a report on every visit. **No Reply Proof code change is required.**
  103. ---
  104. ## Not a PNSPS SPA problem — do not allowlist
  105. | Count | Page | Directive | Blocked | Why ignore |
  106. |---:|---|---|---|---|
  107. | 192 | many (login 90, reply 38, …) | `script-src` | `wasm-eval` | `chrome-extension` (line 23, col 39316) or paired empty source |
  108. | 1 | `/login` | `font-src` | Perplexity `FKGroteskNeue.woff2` | Sidebar / extension |
  109. | 1 | `/login` | `img-src` | NetEase `ydlunacommon-cdn.nosdn.127.net` | Youdao-style translator |
  110. | 2 | `/publicNotice/apply`, `/proof/reply/30166` | `media-src` | `data` | Optional `data:` gap only; 2 hits in three weeks |
  111. `status-code: 404` on 166 reports is typical SPA client-route noise, not a
  112. broken document.
  113. ---
  114. ## Optional: `media-src` and `data:`
  115. Live policy: `media-src 'self' blob:;`
  116. Captcha audio already uses `blob:` (`CustomFormWizard.js` and similar). Adding
  117. `data:` is low risk and already documented:
  118. ```apache
  119. media-src 'self' blob: data:;
  120. ```
  121. Not required for this dump.
  122. ---
  123. ## Recommended actions
  124. 1. **No Apache change required** for these reports. `frame-src` deploy from
  125. 2026-08-14 looks effective (zero `frame-src` hits here).
  126. 2. Keep PROD at `script-src 'self'`. Do not add `'unsafe-eval'` or
  127. `'wasm-unsafe-eval'`.
  128. 3. Optional: add `data:` to `media-src` to match
  129. [csp-apache.conf.md](./csp-apache.conf.md).
  130. 4. Keep Report-Only until remaining volume is understood as extension noise;
  131. then promote the same policy to enforcing.
  132. 5. Optional log hygiene: drop or sample `wasm-eval` + `chrome-extension` so
  133. real app regressions stay visible.
  134. No application code change is required.
  135. ---
  136. ## Backend reference
  137. - Report endpoint: `POST /csp-report` (context path → `/api/csp-report`)
  138. - Controller: `CspReportController` in PNSPS-backend
  139. - Frontend/Apache CSP above is what browsers apply to the SPA document