Page title generator on browser tab rebuilded.
This commit is contained in:
+78
-1
@@ -61,4 +61,81 @@ ZAWSZE wyłączaj w dev: `hsts: process.env.NODE_ENV === 'production'`.
|
||||
|
||||
`additional` z tym samym kluczem NADPISUJE domyślny (np. zmień X-Frame-Options
|
||||
na SAMEORIGIN). Nowy klucz (jak CSP) dodaje. CSP zawsze przez `additional` —
|
||||
plugin go nie generuje, bo zależy od projektu.
|
||||
plugin go nie generuje, bo zależy od projektu.
|
||||
|
||||
### Dlaczego CSP zostaje w projekcie (nie plugin)
|
||||
|
||||
HSTS, nosniff, Referrer-Policy są IDENTYCZNE dla każdego projektu → plugin je
|
||||
generuje. CSP wylicza KONKRETNE domeny, z których projekt ładuje (jego R2,
|
||||
analytics, Turnstile, fonty). Generyczny CSP byłby albo za luźny (`*` =
|
||||
bezużyteczny), albo psułby stronę. Więc plugin daje mechanizm (`additional`),
|
||||
projekt dostarcza CSP dopasowany do siebie.
|
||||
|
||||
### Budowa CSP — domeny z env, nie hardkod
|
||||
|
||||
Domenę mediów czytaj z `R2_PUBLIC_URL` (env), nie zaszywaj. Resztę źródeł
|
||||
dopasuj do tego, co projekt faktycznie ładuje:
|
||||
|
||||
```ts
|
||||
// next.config.ts
|
||||
const r2Url = process.env.R2_PUBLIC_URL || ''
|
||||
|
||||
const csp = [
|
||||
"default-src 'self'",
|
||||
// skrypty: self + Turnstile (Cloudflare) + analytics (GTM/GA jeśli używasz)
|
||||
"script-src 'self' 'unsafe-inline' https://challenges.cloudflare.com https://www.googletagmanager.com",
|
||||
// style: self + inline (Tailwind) + Google Fonts
|
||||
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
|
||||
// obrazy: self + media R2 (z env!) + data:
|
||||
`img-src 'self' data: ${r2Url}`.trim(),
|
||||
"font-src 'self' https://fonts.gstatic.com data:",
|
||||
"connect-src 'self' https://www.google-analytics.com",
|
||||
// ramki: Turnstile (widget captcha)
|
||||
"frame-src https://challenges.cloudflare.com",
|
||||
"form-action 'self'",
|
||||
"frame-ancestors 'none'", // zastępuje X-Frame-Options w nowych przeglądarkach
|
||||
].join('; ')
|
||||
|
||||
const securityHeaders = buildSecurityHeaders({
|
||||
hsts: process.env.NODE_ENV === 'production',
|
||||
additional: [{ key: 'Content-Security-Policy', value: csp }],
|
||||
})
|
||||
```
|
||||
|
||||
Dopasuj źródła do projektu: mapy Google (`https://maps.googleapis.com`,
|
||||
`https://*.google.com`), inne embedy, inne analytics. To, czego nie wymienisz,
|
||||
zostanie zablokowane.
|
||||
|
||||
### WDRAŻAJ CSP OSTROŻNIE — najpierw Report-Only
|
||||
|
||||
CSP za ścisły **psuje stronę** (blokuje skrypty/style/obrazy). NIGDY nie wdrażaj
|
||||
enforcing CSP na ślepo. Metoda bezpieczna:
|
||||
|
||||
1. **Najpierw raportowanie** — użyj klucza `Content-Security-Policy-Report-Only`
|
||||
(nie `Content-Security-Policy`). Przeglądarka RAPORTUJE naruszenia w konsoli,
|
||||
ale NIE blokuje — strona działa normalnie.
|
||||
```ts
|
||||
additional: [{ key: 'Content-Security-Policy-Report-Only', value: csp }]
|
||||
```
|
||||
2. **Otwórz stronę** → DevTools → Console → szukaj „Content Security Policy"
|
||||
violations. Każde naruszenie = brakująca domena. Dodaj ją do odpowiedniej
|
||||
dyrektywy CSP.
|
||||
3. **Przejdź przez cały serwis** — strona główna, formularze (Turnstile!),
|
||||
galeria (obrazy R2), strony z mapą/embedami. Zbierz wszystkie naruszenia.
|
||||
4. **Dopiero gdy konsola czysta** → zmień klucz na `Content-Security-Policy`
|
||||
(enforcing). Teraz CSP chroni, nie psując.
|
||||
|
||||
### Weryfikacja nagłówków na produkcji
|
||||
|
||||
```bash
|
||||
# sprawdź, które nagłówki faktycznie wychodzą:
|
||||
curl -sI https://<DOMENA>/pl | grep -i "strict-transport\|content-type-options\|referrer\|content-security\|x-frame"
|
||||
```
|
||||
|
||||
Jeśli HSTS/nosniff/Referrer są, a CSP brak → dodaj CSP (wyżej). Jeśli BRAK
|
||||
wszystkich mimo buildSecurityHeaders w config → sprawdź, czy `headers()` jest
|
||||
wpięte i czy Cloudflare (jeśli przed aplikacją) nie filtruje nagłówków.
|
||||
|
||||
> Uwaga Cloudflare: jeśli CF jest przed aplikacją, może nadpisywać/filtrować
|
||||
> nagłówki. Wtedy ustaw je też w CF (Transform Rules → Modify Response Header)
|
||||
> albo upewnij się, że CF przepuszcza nagłówki z origin.
|
||||
Reference in New Issue
Block a user