mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
1187 lines
36 KiB
Markdown
1187 lines
36 KiB
Markdown
# NextJS
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|
|
|
|
## Ogólna architektura aplikacji Next.js
|
|
|
|
### Typowa struktura plików
|
|
|
|
Standardowy projekt Next.js przestrzega określonej struktury plików i katalogów, która ułatwia korzystanie z jego funkcji, takich jak routowanie, punkty końcowe API i zarządzanie statycznymi zasobami. Oto typowy układ:
|
|
```lua
|
|
my-nextjs-app/
|
|
├── node_modules/
|
|
├── public/
|
|
│ ├── images/
|
|
│ │ └── logo.png
|
|
│ └── favicon.ico
|
|
├── app/
|
|
│ ├── api/
|
|
│ │ └── hello/
|
|
│ │ └── route.ts
|
|
│ ├── layout.tsx
|
|
│ ├── page.tsx
|
|
│ ├── about/
|
|
│ │ └── page.tsx
|
|
│ ├── dashboard/
|
|
│ │ ├── layout.tsx
|
|
│ │ └── page.tsx
|
|
│ ├── components/
|
|
│ │ ├── Header.tsx
|
|
│ │ └── Footer.tsx
|
|
│ ├── styles/
|
|
│ │ ├── globals.css
|
|
│ │ └── Home.module.css
|
|
│ └── utils/
|
|
│ └── api.ts
|
|
├── .env.local
|
|
├── next.config.js
|
|
├── tsconfig.json
|
|
├── package.json
|
|
├── README.md
|
|
└── yarn.lock / package-lock.json
|
|
|
|
```
|
|
### Główne Katalogi i Pliki
|
|
|
|
- **public/:** Hostuje statyczne zasoby, takie jak obrazy, czcionki i inne pliki. Pliki tutaj są dostępne pod ścieżką główną (`/`).
|
|
- **app/:** Centralny katalog dla stron, układów, komponentów i tras API Twojej aplikacji. Wprowadza paradygmat **App Router**, umożliwiając zaawansowane funkcje routingu i segregację komponentów serwera i klienta.
|
|
- **app/layout.tsx:** Definiuje główny układ dla Twojej aplikacji, otaczając wszystkie strony i zapewniając spójne elementy UI, takie jak nagłówki, stopki i paski nawigacyjne.
|
|
- **app/page.tsx:** Służy jako punkt wejścia dla głównej trasy `/`, renderując stronę główną.
|
|
- **app/\[route]/page.tsx:** Obsługuje statyczne i dynamiczne trasy. Każdy folder w `app/` reprezentuje segment trasy, a `page.tsx` w tych folderach odpowiada komponentowi trasy.
|
|
- **app/api/:** Zawiera trasy API, umożliwiając tworzenie funkcji bezserwerowych, które obsługują żądania HTTP. Te trasy zastępują tradycyjny katalog `pages/api`.
|
|
- **app/components/:** Zawiera wielokrotnego użytku komponenty React, które mogą być wykorzystywane w różnych stronach i układach.
|
|
- **app/styles/:** Zawiera globalne pliki CSS i moduły CSS do stylizacji ograniczonej do komponentów.
|
|
- **app/utils/:** Zawiera funkcje pomocnicze, moduły pomocnicze i inną logikę niezwiązaną z UI, która może być współdzielona w całej aplikacji.
|
|
- **.env.local:** Przechowuje zmienne środowiskowe specyficzne dla lokalnego środowiska deweloperskiego. Te zmienne **nie** są zatwierdzane w systemie kontroli wersji.
|
|
- **next.config.js:** Dostosowuje zachowanie Next.js, w tym konfiguracje webpack, zmienne środowiskowe i ustawienia bezpieczeństwa.
|
|
- **tsconfig.json:** Konfiguruje ustawienia TypeScript dla projektu, umożliwiając sprawdzanie typów i inne funkcje TypeScript.
|
|
- **package.json:** Zarządza zależnościami projektu, skryptami i metadanymi.
|
|
- **README.md:** Dostarcza dokumentację i informacje o projekcie, w tym instrukcje dotyczące konfiguracji, wytyczne dotyczące użytkowania i inne istotne szczegóły.
|
|
- **yarn.lock / package-lock.json:** Zamyka zależności projektu do konkretnych wersji, zapewniając spójne instalacje w różnych środowiskach.
|
|
|
|
## Klient w Next.js
|
|
|
|
### Routing oparty na plikach w katalogu `app`
|
|
|
|
Katalog `app` jest fundamentem routingu w najnowszych wersjach Next.js. Wykorzystuje system plików do definiowania tras, co sprawia, że zarządzanie trasami jest intuicyjne i skalowalne.
|
|
|
|
<details>
|
|
|
|
<summary>Obsługa ścieżki głównej /</summary>
|
|
|
|
**Struktura plików:**
|
|
```arduino
|
|
my-nextjs-app/
|
|
├── app/
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Kluczowe pliki:**
|
|
|
|
- **`app/page.tsx`**: Obsługuje żądania do ścieżki głównej `/`.
|
|
- **`app/layout.tsx`**: Definiuje układ aplikacji, otaczając wszystkie strony.
|
|
|
|
**Implementacja:**
|
|
```tsx
|
|
tsxCopy code// app/page.tsx
|
|
|
|
export default function HomePage() {
|
|
return (
|
|
<div>
|
|
<h1>Welcome to the Home Page!</h1>
|
|
<p>This is the root route.</p>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Definicja trasy:** Plik `page.tsx` bezpośrednio pod katalogiem `app` odpowiada trasie `/`.
|
|
- **Renderowanie:** Ten komponent renderuje zawartość strony głównej.
|
|
- **Integracja układu:** Komponent `HomePage` jest otoczony przez `layout.tsx`, który może zawierać nagłówki, stopki i inne wspólne elementy.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Obsługa innych statycznych ścieżek</summary>
|
|
|
|
**Przykład: Trasa `/about`**
|
|
|
|
**Struktura plików:**
|
|
```arduino
|
|
arduinoCopy codemy-nextjs-app/
|
|
├── app/
|
|
│ ├── about/
|
|
│ │ └── page.tsx
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Wdrożenie:**
|
|
```tsx
|
|
// app/about/page.tsx
|
|
|
|
export default function AboutPage() {
|
|
return (
|
|
<div>
|
|
<h1>About Us</h1>
|
|
<p>Learn more about our mission and values.</p>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Definicja trasy:** Plik `page.tsx` w folderze `about` odpowiada trasie `/about`.
|
|
- **Renderowanie:** Ten komponent renderuje zawartość strony o nas.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Dynamiczne trasy</summary>
|
|
|
|
Dynamiczne trasy umożliwiają obsługę ścieżek z zmiennymi segmentami, co pozwala aplikacjom na wyświetlanie zawartości na podstawie parametrów, takich jak identyfikatory, slugi itp.
|
|
|
|
**Przykład: Trasa `/posts/[id]`**
|
|
|
|
**Struktura plików:**
|
|
```arduino
|
|
arduinoCopy codemy-nextjs-app/
|
|
├── app/
|
|
│ ├── posts/
|
|
│ │ └── [id]/
|
|
│ │ └── page.tsx
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Wdrożenie:**
|
|
```tsx
|
|
tsxCopy code// app/posts/[id]/page.tsx
|
|
|
|
import { useRouter } from 'next/navigation';
|
|
|
|
interface PostProps {
|
|
params: { id: string };
|
|
}
|
|
|
|
export default function PostPage({ params }: PostProps) {
|
|
const { id } = params;
|
|
// Fetch post data based on 'id'
|
|
|
|
return (
|
|
<div>
|
|
<h1>Post #{id}</h1>
|
|
<p>This is the content of post {id}.</p>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Dynamiczny segment:** `[id]` oznacza dynamiczny segment w trasie, przechwytując parametr `id` z URL.
|
|
- **Dostęp do parametrów:** Obiekt `params` zawiera dynamiczne parametry, dostępne w komponencie.
|
|
- **Dopasowywanie tras:** Każda ścieżka pasująca do `/posts/*`, taka jak `/posts/1`, `/posts/abc` itp., będzie obsługiwana przez ten komponent.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Zagnieżdżone trasy</summary>
|
|
|
|
Next.js obsługuje zagnieżdżone trasowanie, umożliwiając hierarchiczne struktury tras, które odzwierciedlają układ katalogów.
|
|
|
|
**Przykład: `/dashboard/settings/profile` Trasa**
|
|
|
|
**Struktura plików:**
|
|
```arduino
|
|
arduinoCopy codemy-nextjs-app/
|
|
├── app/
|
|
│ ├── dashboard/
|
|
│ │ ├── settings/
|
|
│ │ │ └── profile/
|
|
│ │ │ └── page.tsx
|
|
│ │ └── page.tsx
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Wdrożenie:**
|
|
```tsx
|
|
tsxCopy code// app/dashboard/settings/profile/page.tsx
|
|
|
|
export default function ProfileSettingsPage() {
|
|
return (
|
|
<div>
|
|
<h1>Profile Settings</h1>
|
|
<p>Manage your profile information here.</p>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Głębokie zagnieżdżenie:** Plik `page.tsx` wewnątrz `dashboard/settings/profile/` odpowiada trasie `/dashboard/settings/profile`.
|
|
- **Odbicie hierarchii:** Struktura katalogów odzwierciedla ścieżkę URL, co zwiększa łatwość utrzymania i przejrzystość.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Trasy Catch-All</summary>
|
|
|
|
Trasy catch-all obsługują wiele zagnieżdżonych segmentów lub nieznane ścieżki, zapewniając elastyczność w obsłudze tras.
|
|
|
|
**Przykład: trasa `/*`**
|
|
|
|
**Struktura plików:**
|
|
```arduino
|
|
my-nextjs-app/
|
|
├── app/
|
|
│ ├── [..slug]/
|
|
│ │ └── page.tsx
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Wdrożenie:**
|
|
```tsx
|
|
// app/[...slug]/page.tsx
|
|
|
|
interface CatchAllProps {
|
|
params: { slug: string[] }
|
|
}
|
|
|
|
export default function CatchAllPage({ params }: CatchAllProps) {
|
|
const { slug } = params
|
|
const fullPath = `/${slug.join("/")}`
|
|
|
|
return (
|
|
<div>
|
|
<h1>Catch-All Route</h1>
|
|
<p>You have navigated to: {fullPath}</p>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Segment Catch-All:** `[...slug]` przechwytuje wszystkie pozostałe segmenty ścieżki jako tablicę.
|
|
- **Zastosowanie:** Przydatne do obsługi dynamicznych scenariuszy routingu, takich jak ścieżki generowane przez użytkowników, zagnieżdżone kategorie itp.
|
|
- **Dopasowywanie tras:** Ścieżki takie jak `/anything/here`, `/foo/bar/baz` itp. są obsługiwane przez ten komponent.
|
|
|
|
</details>
|
|
|
|
### Potencjalne luki w zabezpieczeniach po stronie klienta
|
|
|
|
Chociaż Next.js zapewnia bezpieczną podstawę, niewłaściwe praktyki kodowania mogą wprowadzać luki. Kluczowe luki po stronie klienta obejmują:
|
|
|
|
<details>
|
|
|
|
<summary>Cross-Site Scripting (XSS)</summary>
|
|
|
|
Ataki XSS występują, gdy złośliwe skrypty są wstrzykiwane do zaufanych stron internetowych. Napastnicy mogą wykonywać skrypty w przeglądarkach użytkowników, kradnąc dane lub wykonując działania w imieniu użytkownika.
|
|
|
|
**Przykład podatnego kodu:**
|
|
```jsx
|
|
// Dangerous: Injecting user input directly into HTML
|
|
function Comment({ userInput }) {
|
|
return <div dangerouslySetInnerHTML={{ __html: userInput }} />
|
|
}
|
|
```
|
|
**Dlaczego jest podatne:** Użycie `dangerouslySetInnerHTML` z nieufnym wejściem pozwala atakującym na wstrzykiwanie złośliwych skryptów.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Wstrzykiwanie szablonów po stronie klienta</summary>
|
|
|
|
Występuje, gdy dane wejściowe użytkownika są niewłaściwie obsługiwane w szablonach, co pozwala atakującym na wstrzykiwanie i wykonywanie szablonów lub wyrażeń.
|
|
|
|
**Przykład podatnego kodu:**
|
|
```jsx
|
|
import React from "react"
|
|
import ejs from "ejs"
|
|
|
|
function RenderTemplate({ template, data }) {
|
|
const html = ejs.render(template, data)
|
|
return <div dangerouslySetInnerHTML={{ __html: html }} />
|
|
}
|
|
```
|
|
**Dlaczego jest podatne:** Jeśli `template` lub `data` zawiera złośliwą treść, może to prowadzić do wykonania niezamierzonego kodu.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Przechodzenie po ścieżkach po stronie klienta</summary>
|
|
|
|
To podatność, która pozwala atakującym manipulować ścieżkami po stronie klienta, aby wykonać niezamierzone działania, takie jak Cross-Site Request Forgery (CSRF). W przeciwieństwie do przechodzenia po ścieżkach po stronie serwera, które celuje w system plików serwera, CSPT koncentruje się na wykorzystywaniu mechanizmów po stronie klienta do przekierowywania legalnych żądań API do złośliwych punktów końcowych.
|
|
|
|
**Przykład podatnego kodu:**
|
|
|
|
Aplikacja Next.js pozwala użytkownikom na przesyłanie i pobieranie plików. Funkcja pobierania jest zaimplementowana po stronie klienta, gdzie użytkownicy mogą określić ścieżkę pliku do pobrania.
|
|
```jsx
|
|
// pages/download.js
|
|
import { useState } from "react"
|
|
|
|
export default function DownloadPage() {
|
|
const [filePath, setFilePath] = useState("")
|
|
|
|
const handleDownload = () => {
|
|
fetch(`/api/files/${filePath}`)
|
|
.then((response) => response.blob())
|
|
.then((blob) => {
|
|
const url = window.URL.createObjectURL(blob)
|
|
const a = document.createElement("a")
|
|
a.href = url
|
|
a.download = filePath
|
|
a.click()
|
|
})
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<h1>Download File</h1>
|
|
<input
|
|
type="text"
|
|
value={filePath}
|
|
onChange={(e) => setFilePath(e.target.value)}
|
|
placeholder="Enter file path"
|
|
/>
|
|
<button onClick={handleDownload}>Download</button>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
#### Scenariusz Ataku
|
|
|
|
1. **Cel Atakującego**: Wykonanie ataku CSRF w celu usunięcia krytycznego pliku (np. `admin/config.json`) poprzez manipulację `filePath`.
|
|
2. **Wykorzystanie CSPT**:
|
|
- **Złośliwy Wkład**: Atakujący tworzy URL z manipulowanym `filePath`, takim jak `../deleteFile/config.json`.
|
|
- **Wynikowe Wywołanie API**: Kod po stronie klienta wysyła żądanie do `/api/files/../deleteFile/config.json`.
|
|
- **Obsługa przez Serwer**: Jeśli serwer nie weryfikuje `filePath`, przetwarza żądanie, potencjalnie usuwając lub ujawniając wrażliwe pliki.
|
|
3. **Wykonanie CSRF**:
|
|
- **Stworzony Link**: Atakujący wysyła ofierze link lub osadza złośliwy skrypt, który wywołuje żądanie pobrania z manipulowanym `filePath`.
|
|
- **Wynik**: Ofiara nieświadomie wykonuje akcję, co prowadzi do nieautoryzowanego dostępu do plików lub ich usunięcia.
|
|
|
|
#### Dlaczego Jest To Wrażliwe
|
|
|
|
- **Brak Weryfikacji Wkładu**: Po stronie klienta dozwolone są dowolne wkłady `filePath`, co umożliwia przejście przez ścieżki.
|
|
- **Zaufanie do Wkładów Klienta**: API po stronie serwera ufa i przetwarza `filePath` bez sanitizacji.
|
|
- **Potencjalne Akcje API**: Jeśli punkt końcowy API wykonuje akcje zmieniające stan (np. usuwanie, modyfikowanie plików), może być wykorzystywany za pomocą CSPT.
|
|
|
|
</details>
|
|
|
|
## Po Stronie Serwera w Next.js
|
|
|
|
### Renderowanie Po Stronie Serwera (SSR)
|
|
|
|
Strony są renderowane na serwerze przy każdym żądaniu, zapewniając, że użytkownik otrzymuje w pełni renderowany HTML. W tym przypadku powinieneś stworzyć własny niestandardowy serwer do przetwarzania żądań.
|
|
|
|
**Przykłady Zastosowania:**
|
|
|
|
- Dynamiczna treść, która często się zmienia.
|
|
- Optymalizacja SEO, ponieważ wyszukiwarki mogą indeksować w pełni renderowaną stronę.
|
|
|
|
**Implementacja:**
|
|
```jsx
|
|
// pages/index.js
|
|
export async function getServerSideProps(context) {
|
|
const res = await fetch("https://api.example.com/data")
|
|
const data = await res.json()
|
|
return { props: { data } }
|
|
}
|
|
|
|
function HomePage({ data }) {
|
|
return <div>{data.title}</div>
|
|
}
|
|
|
|
export default HomePage
|
|
```
|
|
### Static Site Generation (SSG)
|
|
|
|
Strony są wstępnie renderowane w czasie budowy, co skutkuje szybszym czasem ładowania i zmniejszonym obciążeniem serwera.
|
|
|
|
**Use Cases:**
|
|
|
|
- Treści, które nie zmieniają się często.
|
|
- Blogi, dokumentacja, strony marketingowe.
|
|
|
|
**Implementation:**
|
|
```jsx
|
|
// pages/index.js
|
|
export async function getStaticProps() {
|
|
const res = await fetch("https://api.example.com/data")
|
|
const data = await res.json()
|
|
return { props: { data }, revalidate: 60 } // Revalidate every 60 seconds
|
|
}
|
|
|
|
function HomePage({ data }) {
|
|
return <div>{data.title}</div>
|
|
}
|
|
|
|
export default HomePage
|
|
```
|
|
### Funkcje bezserwerowe (Trasy API)
|
|
|
|
Next.js umożliwia tworzenie punktów końcowych API jako funkcji bezserwerowych. Te funkcje działają na żądanie bez potrzeby posiadania dedykowanego serwera.
|
|
|
|
**Przykłady użycia:**
|
|
|
|
- Obsługa przesyłania formularzy.
|
|
- Interakcja z bazami danych.
|
|
- Przetwarzanie danych lub integracja z zewnętrznymi API.
|
|
|
|
**Implementacja:**
|
|
|
|
Wraz z wprowadzeniem katalogu `app` w Next.js 13, routowanie i obsługa API stały się bardziej elastyczne i potężne. To nowoczesne podejście ściśle współpracuje z systemem routingu opartym na plikach, ale wprowadza ulepszone możliwości, w tym wsparcie dla komponentów serwerowych i klienckich.
|
|
|
|
#### Podstawowy obsługiwacz tras
|
|
|
|
**Struktura plików:**
|
|
```go
|
|
my-nextjs-app/
|
|
├── app/
|
|
│ └── api/
|
|
│ └── hello/
|
|
│ └── route.js
|
|
├── package.json
|
|
└── ...
|
|
```
|
|
**Wdrożenie:**
|
|
```javascript
|
|
// app/api/hello/route.js
|
|
|
|
export async function POST(request) {
|
|
return new Response(JSON.stringify({ message: "Hello from App Router!" }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
})
|
|
}
|
|
|
|
// Client-side fetch to access the API endpoint
|
|
fetch("/api/submit", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ name: "John Doe" }),
|
|
})
|
|
.then((res) => res.json())
|
|
.then((data) => console.log(data))
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Lokalizacja:** Trasy API znajdują się w katalogu `app/api/`.
|
|
- **Nazewnictwo plików:** Każdy punkt końcowy API znajduje się w swoim własnym folderze zawierającym plik `route.js` lub `route.ts`.
|
|
- **Eksportowane funkcje:** Zamiast pojedynczego domyślnego eksportu, eksportowane są specyficzne funkcje metod HTTP (np. `GET`, `POST`).
|
|
- **Obsługa odpowiedzi:** Użyj konstruktora `Response`, aby zwracać odpowiedzi, co pozwala na większą kontrolę nad nagłówkami i kodami statusu.
|
|
|
|
#### Jak obsługiwać inne ścieżki i metody:
|
|
|
|
<details>
|
|
|
|
<summary>Obsługa specyficznych metod HTTP</summary>
|
|
|
|
Next.js 13+ pozwala na definiowanie handlerów dla specyficznych metod HTTP w tym samym pliku `route.js` lub `route.ts`, co promuje jaśniejszy i bardziej zorganizowany kod.
|
|
|
|
**Przykład:**
|
|
```javascript
|
|
// app/api/users/[id]/route.js
|
|
|
|
export async function GET(request, { params }) {
|
|
const { id } = params
|
|
// Fetch user data based on 'id'
|
|
return new Response(JSON.stringify({ userId: id, name: "Jane Doe" }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
})
|
|
}
|
|
|
|
export async function PUT(request, { params }) {
|
|
const { id } = params
|
|
// Update user data based on 'id'
|
|
return new Response(JSON.stringify({ message: `User ${id} updated.` }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
})
|
|
}
|
|
|
|
export async function DELETE(request, { params }) {
|
|
const { id } = params
|
|
// Delete user based on 'id'
|
|
return new Response(JSON.stringify({ message: `User ${id} deleted.` }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
})
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Wielokrotne Eksporty:** Każda metoda HTTP (`GET`, `PUT`, `DELETE`) ma swoją własną funkcję eksportowaną.
|
|
- **Parametry:** Drugi argument zapewnia dostęp do parametrów trasy za pomocą `params`.
|
|
- **Ulepszone Odpowiedzi:** Większa kontrola nad obiektami odpowiedzi, umożliwiająca precyzyjne zarządzanie nagłówkami i kodami statusu.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Trasy Catch-All i Zagnieżdżone</summary>
|
|
|
|
Next.js 13+ obsługuje zaawansowane funkcje routingu, takie jak trasy catch-all i zagnieżdżone trasy API, co pozwala na bardziej dynamiczne i skalowalne struktury API.
|
|
|
|
**Przykład Trasy Catch-All:**
|
|
```javascript
|
|
// app/api/[...slug]/route.js
|
|
|
|
export async function GET(request, { params }) {
|
|
const { slug } = params
|
|
// Handle dynamic nested routes
|
|
return new Response(JSON.stringify({ slug }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
})
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Składnia:** `[...]` oznacza segment przechwytujący, który uchwyca wszystkie zagnieżdżone ścieżki.
|
|
- **Zastosowanie:** Przydatne dla API, które muszą obsługiwać różne głębokości tras lub dynamiczne segmenty.
|
|
|
|
**Przykład zagnieżdżonych tras:**
|
|
```javascript
|
|
// app/api/posts/[postId]/comments/[commentId]/route.js
|
|
|
|
export async function GET(request, { params }) {
|
|
const { postId, commentId } = params
|
|
// Fetch specific comment for a post
|
|
return new Response(
|
|
JSON.stringify({ postId, commentId, comment: "Great post!" }),
|
|
{
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
}
|
|
)
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Głębokie zagnieżdżenie:** Umożliwia hierarchiczne struktury API, odzwierciedlające relacje zasobów.
|
|
- **Dostęp do parametrów:** Łatwy dostęp do wielu parametrów trasy za pomocą obiektu `params`.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Obsługa tras API w Next.js 12 i wcześniejszych wersjach</summary>
|
|
|
|
## Trasy API w katalogu `pages` (Next.js 12 i wcześniejsze)
|
|
|
|
Zanim Next.js 13 wprowadził katalog `app` i ulepszone możliwości routingu, trasy API były głównie definiowane w katalogu `pages`. To podejście jest nadal szeroko stosowane i wspierane w Next.js 12 i wcześniejszych wersjach.
|
|
|
|
#### Podstawowa trasa API
|
|
|
|
**Struktura plików:**
|
|
```go
|
|
goCopy codemy-nextjs-app/
|
|
├── pages/
|
|
│ └── api/
|
|
│ └── hello.js
|
|
├── package.json
|
|
└── ...
|
|
```
|
|
**Wdrożenie:**
|
|
```javascript
|
|
javascriptCopy code// pages/api/hello.js
|
|
|
|
export default function handler(req, res) {
|
|
res.status(200).json({ message: 'Hello, World!' });
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Lokalizacja:** Trasy API znajdują się w katalogu `pages/api/`.
|
|
- **Eksport:** Użyj `export default`, aby zdefiniować funkcję obsługi.
|
|
- **Podpis funkcji:** Funkcja obsługi otrzymuje obiekty `req` (żądanie HTTP) i `res` (odpowiedź HTTP).
|
|
- **Routing:** Nazwa pliku (`hello.js`) odpowiada punktowi końcowemu `/api/hello`.
|
|
|
|
#### Dynamiczne trasy API
|
|
|
|
**Struktura plików:**
|
|
```bash
|
|
bashCopy codemy-nextjs-app/
|
|
├── pages/
|
|
│ └── api/
|
|
│ └── users/
|
|
│ └── [id].js
|
|
├── package.json
|
|
└── ...
|
|
```
|
|
**Wdrożenie:**
|
|
```javascript
|
|
javascriptCopy code// pages/api/users/[id].js
|
|
|
|
export default function handler(req, res) {
|
|
const {
|
|
query: { id },
|
|
method,
|
|
} = req;
|
|
|
|
switch (method) {
|
|
case 'GET':
|
|
// Fetch user data based on 'id'
|
|
res.status(200).json({ userId: id, name: 'John Doe' });
|
|
break;
|
|
case 'PUT':
|
|
// Update user data based on 'id'
|
|
res.status(200).json({ message: `User ${id} updated.` });
|
|
break;
|
|
case 'DELETE':
|
|
// Delete user based on 'id'
|
|
res.status(200).json({ message: `User ${id} deleted.` });
|
|
break;
|
|
default:
|
|
res.setHeader('Allow', ['GET', 'PUT', 'DELETE']);
|
|
res.status(405).end(`Method ${method} Not Allowed`);
|
|
}
|
|
}
|
|
```
|
|
**Wyjaśnienie:**
|
|
|
|
- **Dynamiczne segmenty:** Kwadratowe nawiasy (`[id].js`) oznaczają dynamiczne segmenty trasy.
|
|
- **Dostęp do parametrów:** Użyj `req.query.id`, aby uzyskać dostęp do dynamicznego parametru.
|
|
- **Obsługa metod:** Wykorzystaj logikę warunkową do obsługi różnych metod HTTP (`GET`, `PUT`, `DELETE` itd.).
|
|
|
|
#### Obsługa różnych metod HTTP
|
|
|
|
Podczas gdy podstawowy przykład trasy API obsługuje wszystkie metody HTTP w jednej funkcji, możesz zorganizować swój kod, aby obsługiwał każdą metodę wyraźnie dla lepszej przejrzystości i łatwości utrzymania.
|
|
|
|
**Przykład:**
|
|
```javascript
|
|
javascriptCopy code// pages/api/posts.js
|
|
|
|
export default async function handler(req, res) {
|
|
const { method } = req;
|
|
|
|
switch (method) {
|
|
case 'GET':
|
|
// Handle GET request
|
|
res.status(200).json({ message: 'Fetching posts.' });
|
|
break;
|
|
case 'POST':
|
|
// Handle POST request
|
|
res.status(201).json({ message: 'Post created.' });
|
|
break;
|
|
default:
|
|
res.setHeader('Allow', ['GET', 'POST']);
|
|
res.status(405).end(`Method ${method} Not Allowed`);
|
|
}
|
|
}
|
|
```
|
|
**Najlepsze praktyki:**
|
|
|
|
- **Separacja obowiązków:** Wyraźnie oddziel logikę dla różnych metod HTTP.
|
|
- **Spójność odpowiedzi:** Zapewnij spójne struktury odpowiedzi dla łatwiejszego przetwarzania po stronie klienta.
|
|
- **Obsługa błędów:** Elegancko obsługuj nieobsługiwane metody i nieoczekiwane błędy.
|
|
|
|
</details>
|
|
|
|
### Konfiguracja CORS
|
|
|
|
Kontroluj, które źródła mogą uzyskiwać dostęp do twoich tras API, łagodząc podatności na Cross-Origin Resource Sharing (CORS).
|
|
|
|
**Zły przykład konfiguracji:**
|
|
```javascript
|
|
// app/api/data/route.js
|
|
|
|
export async function GET(request) {
|
|
return new Response(JSON.stringify({ data: "Public Data" }), {
|
|
status: 200,
|
|
headers: {
|
|
"Access-Control-Allow-Origin": "*", // Allows any origin
|
|
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
|
|
},
|
|
})
|
|
}
|
|
```
|
|
Zauważ, że **CORS można również skonfigurować we wszystkich trasach API** w pliku **`middleware.ts`**:
|
|
```javascript
|
|
// app/middleware.ts
|
|
|
|
import { NextResponse } from "next/server"
|
|
import type { NextRequest } from "next/server"
|
|
|
|
export function middleware(request: NextRequest) {
|
|
const allowedOrigins = [
|
|
"https://yourdomain.com",
|
|
"https://sub.yourdomain.com",
|
|
]
|
|
const origin = request.headers.get("Origin")
|
|
|
|
const response = NextResponse.next()
|
|
|
|
if (allowedOrigins.includes(origin || "")) {
|
|
response.headers.set("Access-Control-Allow-Origin", origin || "")
|
|
response.headers.set(
|
|
"Access-Control-Allow-Methods",
|
|
"GET, POST, PUT, DELETE, OPTIONS"
|
|
)
|
|
response.headers.set(
|
|
"Access-Control-Allow-Headers",
|
|
"Content-Type, Authorization"
|
|
)
|
|
// If credentials are needed:
|
|
// response.headers.set('Access-Control-Allow-Credentials', 'true');
|
|
}
|
|
|
|
// Handle preflight requests
|
|
if (request.method === "OPTIONS") {
|
|
return new Response(null, {
|
|
status: 204,
|
|
headers: response.headers,
|
|
})
|
|
}
|
|
|
|
return response
|
|
}
|
|
|
|
export const config = {
|
|
matcher: "/api/:path*", // Apply to all API routes
|
|
}
|
|
```
|
|
**Problem:**
|
|
|
|
- **`Access-Control-Allow-Origin: '*'`:** Zezwala każdej stronie na dostęp do API, co potencjalnie umożliwia złośliwym stronom interakcję z Twoim API bez ograniczeń.
|
|
- **Szerokie zezwolenie na metody:** Zezwolenie na wszystkie metody może umożliwić atakującym wykonywanie niepożądanych działań.
|
|
|
|
**Jak atakujący to wykorzystują:**
|
|
|
|
Atakujący mogą tworzyć złośliwe strony, które wysyłają żądania do Twojego API, potencjalnie nadużywając funkcji takich jak pobieranie danych, manipulacja danymi lub wywoływanie niepożądanych działań w imieniu uwierzytelnionych użytkowników.
|
|
|
|
{{#ref}}
|
|
../../pentesting-web/cors-bypass.md
|
|
{{#endref}}
|
|
|
|
### Ekspozycja kodu serwera po stronie klienta
|
|
|
|
Łatwo jest **używać kodu używanego przez serwer również w kodzie eksponowanym i używanym przez stronę klienta**, najlepszym sposobem na zapewnienie, że plik kodu nigdy nie jest eksponowany po stronie klienta, jest użycie tego importu na początku pliku:
|
|
```js
|
|
import "server-only"
|
|
```
|
|
## Kluczowe pliki i ich role
|
|
|
|
### `middleware.ts` / `middleware.js`
|
|
|
|
**Lokalizacja:** W katalogu głównym projektu lub w `src/`.
|
|
|
|
**Cel:** Wykonuje kod w funkcji serverless po stronie serwera przed przetworzeniem żądania, umożliwiając takie zadania jak uwierzytelnianie, przekierowania lub modyfikowanie odpowiedzi.
|
|
|
|
**Przebieg wykonania:**
|
|
|
|
1. **Przychodzące żądanie:** Middleware przechwytuje żądanie.
|
|
2. **Przetwarzanie:** Wykonuje operacje na podstawie żądania (np. sprawdzenie uwierzytelnienia).
|
|
3. **Modyfikacja odpowiedzi:** Może zmieniać odpowiedź lub przekazać kontrolę do następnego handlera.
|
|
|
|
**Przykłady zastosowań:**
|
|
|
|
- Przekierowywanie nieautoryzowanych użytkowników.
|
|
- Dodawanie niestandardowych nagłówków.
|
|
- Rejestrowanie żądań.
|
|
|
|
**Przykładowa konfiguracja:**
|
|
```typescript
|
|
// middleware.ts
|
|
import { NextResponse } from "next/server"
|
|
import type { NextRequest } from "next/server"
|
|
|
|
export function middleware(req: NextRequest) {
|
|
const url = req.nextUrl.clone()
|
|
if (!req.cookies.has("token")) {
|
|
url.pathname = "/login"
|
|
return NextResponse.redirect(url)
|
|
}
|
|
return NextResponse.next()
|
|
}
|
|
|
|
export const config = {
|
|
matcher: ["/protected/:path*"],
|
|
}
|
|
```
|
|
### `next.config.js`
|
|
|
|
**Lokalizacja:** Korzeń projektu.
|
|
|
|
**Cel:** Konfiguruje zachowanie Next.js, włączając lub wyłączając funkcje, dostosowując konfiguracje webpack, ustawiając zmienne środowiskowe i konfigurowanie kilku funkcji zabezpieczeń.
|
|
|
|
**Kluczowe konfiguracje zabezpieczeń:**
|
|
|
|
<details>
|
|
|
|
<summary>Nagłówki zabezpieczeń</summary>
|
|
|
|
Nagłówki zabezpieczeń zwiększają bezpieczeństwo Twojej aplikacji, instruując przeglądarki, jak obsługiwać treści. Pomagają w łagodzeniu różnych ataków, takich jak Cross-Site Scripting (XSS), Clickjacking i sniffing typu MIME:
|
|
|
|
- Content Security Policy (CSP)
|
|
- X-Frame-Options
|
|
- X-Content-Type-Options
|
|
- Strict-Transport-Security (HSTS)
|
|
- Referrer Policy
|
|
|
|
**Przykłady:**
|
|
```javascript
|
|
// next.config.js
|
|
|
|
module.exports = {
|
|
async headers() {
|
|
return [
|
|
{
|
|
source: "/(.*)", // Apply to all routes
|
|
headers: [
|
|
{
|
|
key: "X-Frame-Options",
|
|
value: "DENY",
|
|
},
|
|
{
|
|
key: "Content-Security-Policy",
|
|
value:
|
|
"default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval';",
|
|
},
|
|
{
|
|
key: "X-Content-Type-Options",
|
|
value: "nosniff",
|
|
},
|
|
{
|
|
key: "Strict-Transport-Security",
|
|
value: "max-age=63072000; includeSubDomains; preload", // Enforces HTTPS
|
|
},
|
|
{
|
|
key: "Referrer-Policy",
|
|
value: "no-referrer", // Completely hides referrer
|
|
},
|
|
// Additional headers...
|
|
],
|
|
},
|
|
]
|
|
},
|
|
}
|
|
```
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Ustawienia optymalizacji obrazów</summary>
|
|
|
|
Next.js optymalizuje obrazy pod kątem wydajności, ale błędne konfiguracje mogą prowadzić do luk w zabezpieczeniach, takich jak umożliwienie nieufnym źródłom wstrzykiwania złośliwej treści.
|
|
|
|
**Zły przykład konfiguracji:**
|
|
```javascript
|
|
// next.config.js
|
|
|
|
module.exports = {
|
|
images: {
|
|
domains: ["*"], // Allows images from any domain
|
|
},
|
|
}
|
|
```
|
|
**Problem:**
|
|
|
|
- **`'*'`:** Zezwala na ładowanie obrazów z dowolnego zewnętrznego źródła, w tym z nieufnych lub złośliwych domen. Napastnicy mogą hostować obrazy zawierające złośliwe ładunki lub treści, które wprowadzają użytkowników w błąd.
|
|
- Innym problemem może być zezwolenie na domenę **gdzie ktokolwiek może przesłać obraz** (jak `raw.githubusercontent.com`)
|
|
|
|
**Jak napastnicy to wykorzystują:**
|
|
|
|
Poprzez wstrzykiwanie obrazów z złośliwych źródeł, napastnicy mogą przeprowadzać ataki phishingowe, wyświetlać wprowadzające w błąd informacje lub wykorzystywać luki w bibliotekach renderujących obrazy.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Ekspozycja Zmiennych Środowiskowych</summary>
|
|
|
|
Zarządzaj wrażliwymi informacjami, takimi jak klucze API i dane uwierzytelniające do bazy danych, w sposób bezpieczny, nie ujawniając ich klientowi.
|
|
|
|
#### a. Ekspozycja Wrażliwych Zmiennych
|
|
|
|
**Zły Przykład Konfiguracji:**
|
|
```javascript
|
|
// next.config.js
|
|
|
|
module.exports = {
|
|
env: {
|
|
SECRET_API_KEY: process.env.SECRET_API_KEY, // Exposed to the client
|
|
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, // Correctly prefixed for client
|
|
},
|
|
}
|
|
```
|
|
**Problem:**
|
|
|
|
- **`SECRET_API_KEY`:** Bez prefiksu `NEXT_PUBLIC_`, Next.js nie udostępnia zmiennych klientowi. Jednak, jeśli przez pomyłkę zostanie dodany prefiks (np. `NEXT_PUBLIC_SECRET_API_KEY`), staje się dostępny po stronie klienta.
|
|
|
|
**How attackers abuse it:**
|
|
|
|
Jeśli wrażliwe zmienne są udostępnione klientowi, atakujący mogą je odzyskać, przeglądając kod po stronie klienta lub żądania sieciowe, uzyskując nieautoryzowany dostęp do API, baz danych lub innych usług.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Redirects</summary>
|
|
|
|
Zarządzaj przekierowaniami URL i przepisywaniem w swojej aplikacji, zapewniając, że użytkownicy są odpowiednio kierowani, nie wprowadzając podatności na otwarte przekierowania.
|
|
|
|
#### a. Open Redirect Vulnerability
|
|
|
|
**Bad Configuration Example:**
|
|
```javascript
|
|
// next.config.js
|
|
|
|
module.exports = {
|
|
async redirects() {
|
|
return [
|
|
{
|
|
source: "/redirect",
|
|
destination: (req) => req.query.url, // Dynamically redirects based on query parameter
|
|
permanent: false,
|
|
},
|
|
]
|
|
},
|
|
}
|
|
```
|
|
**Problem:**
|
|
|
|
- **Dynamic Destination:** Umożliwia użytkownikom określenie dowolnego URL, co pozwala na ataki typu open redirect.
|
|
- **Trusting User Input:** Przekierowania do URL podanych przez użytkowników bez walidacji mogą prowadzić do phishingu, dystrybucji złośliwego oprogramowania lub kradzieży poświadczeń.
|
|
|
|
**How attackers abuse it:**
|
|
|
|
Atakujący mogą tworzyć URL, które wydają się pochodzić z twojej domeny, ale przekierowują użytkowników na złośliwe strony. Na przykład:
|
|
```bash
|
|
https://yourdomain.com/redirect?url=https://malicious-site.com
|
|
```
|
|
Użytkownicy ufający oryginalnej domenie mogą nieświadomie przechodzić do szkodliwych stron internetowych.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Konfiguracja Webpack</summary>
|
|
|
|
Dostosuj konfiguracje Webpack dla swojej aplikacji Next.js, które mogą nieumyślnie wprowadzać luki w zabezpieczeniach, jeśli nie są obsługiwane ostrożnie.
|
|
|
|
#### a. Ujawnianie wrażliwych modułów
|
|
|
|
**Zły przykład konfiguracji:**
|
|
```javascript
|
|
// next.config.js
|
|
|
|
module.exports = {
|
|
webpack: (config, { isServer }) => {
|
|
if (!isServer) {
|
|
config.resolve.alias["@sensitive"] = path.join(__dirname, "secret-folder")
|
|
}
|
|
return config
|
|
},
|
|
}
|
|
```
|
|
**Problem:**
|
|
|
|
- **Eksponowanie wrażliwych ścieżek:** Aliasowanie wrażliwych katalogów i umożliwienie dostępu po stronie klienta może prowadzić do wycieku poufnych informacji.
|
|
- **Pakowanie sekretów:** Jeśli wrażliwe pliki są pakowane dla klienta, ich zawartość staje się dostępna poprzez mapy źródłowe lub inspekcję kodu po stronie klienta.
|
|
|
|
**Jak atakujący to wykorzystują:**
|
|
|
|
Atakujący mogą uzyskać dostęp do struktury katalogów aplikacji lub ją odtworzyć, potencjalnie znajdując i wykorzystując wrażliwe pliki lub dane.
|
|
|
|
</details>
|
|
|
|
### `pages/_app.js` i `pages/_document.js`
|
|
|
|
#### **`pages/_app.js`**
|
|
|
|
**Cel:** Nadpisuje domyślny komponent App, umożliwiając globalny stan, style i komponenty układu.
|
|
|
|
**Przykłady użycia:**
|
|
|
|
- Wstrzykiwanie globalnego CSS.
|
|
- Dodawanie opakowań układu.
|
|
- Integracja bibliotek zarządzania stanem.
|
|
|
|
**Przykład:**
|
|
```jsx
|
|
// pages/_app.js
|
|
import "../styles/globals.css"
|
|
|
|
function MyApp({ Component, pageProps }) {
|
|
return <Component {...pageProps} />
|
|
}
|
|
|
|
export default MyApp
|
|
```
|
|
#### **`pages/_document.js`**
|
|
|
|
**Cel:** Nadpisuje domyślny dokument, umożliwiając dostosowanie tagów HTML i Body.
|
|
|
|
**Przykłady użycia:**
|
|
|
|
- Modyfikacja tagów `<html>` lub `<body>`.
|
|
- Dodawanie tagów meta lub niestandardowych skryptów.
|
|
- Integracja czcionek zewnętrznych.
|
|
|
|
**Przykład:**
|
|
```jsx
|
|
// pages/_document.js
|
|
import Document, { Html, Head, Main, NextScript } from "next/document"
|
|
|
|
class MyDocument extends Document {
|
|
render() {
|
|
return (
|
|
<Html lang="en">
|
|
<Head>{/* Custom fonts or meta tags */}</Head>
|
|
<body>
|
|
<Main />
|
|
<NextScript />
|
|
</body>
|
|
</Html>
|
|
)
|
|
}
|
|
}
|
|
|
|
export default MyDocument
|
|
```
|
|
### Custom Server (Opcjonalnie)
|
|
|
|
**Cel:** Chociaż Next.js ma wbudowany serwer, możesz stworzyć własny serwer do zaawansowanych przypadków użycia, takich jak niestandardowe routowanie lub integracja z istniejącymi usługami backendowymi.
|
|
|
|
**Uwaga:** Użycie niestandardowego serwera może ograniczyć opcje wdrożenia, szczególnie na platformach takich jak Vercel, które optymalizują wbudowany serwer Next.js.
|
|
|
|
**Przykład:**
|
|
```javascript
|
|
// server.js
|
|
const express = require("express")
|
|
const next = require("next")
|
|
|
|
const dev = process.env.NODE_ENV !== "production"
|
|
const app = next({ dev })
|
|
const handle = app.getRequestHandler()
|
|
|
|
app.prepare().then(() => {
|
|
const server = express()
|
|
|
|
// Custom route
|
|
server.get("/a", (req, res) => {
|
|
return app.render(req, res, "/a")
|
|
})
|
|
|
|
// Default handler
|
|
server.all("*", (req, res) => {
|
|
return handle(req, res)
|
|
})
|
|
|
|
server.listen(3000, (err) => {
|
|
if (err) throw err
|
|
console.log("> Ready on http://localhost:3000")
|
|
})
|
|
})
|
|
```
|
|
---
|
|
|
|
## Dodatkowe rozważania architektoniczne i bezpieczeństwa
|
|
|
|
### Zmienne środowiskowe i konfiguracja
|
|
|
|
**Cel:** Zarządzanie wrażliwymi informacjami i ustawieniami konfiguracyjnymi poza kodem źródłowym.
|
|
|
|
**Najlepsze praktyki:**
|
|
|
|
- **Używaj plików `.env`:** Przechowuj zmienne, takie jak klucze API, w `.env.local` (wyłączone z kontroli wersji).
|
|
- **Bezpieczny dostęp do zmiennych:** Używaj `process.env.VARIABLE_NAME`, aby uzyskać dostęp do zmiennych środowiskowych.
|
|
- **Nigdy nie ujawniaj sekretów po stronie klienta:** Upewnij się, że wrażliwe zmienne są używane tylko po stronie serwera.
|
|
|
|
**Przykład:**
|
|
```javascript
|
|
// next.config.js
|
|
module.exports = {
|
|
env: {
|
|
API_KEY: process.env.API_KEY, // Accessible on both client and server
|
|
SECRET_KEY: process.env.SECRET_KEY, // Be cautious if accessible on the client
|
|
},
|
|
}
|
|
```
|
|
**Uwaga:** Aby ograniczyć zmienne tylko do serwera, pomiń je w obiekcie `env` lub poprzedź je prefiksem `NEXT_PUBLIC_` dla ekspozycji po stronie klienta.
|
|
|
|
### Uwierzytelnianie i autoryzacja
|
|
|
|
**Podejście:**
|
|
|
|
- **Uwierzytelnianie oparte na sesji:** Użyj ciasteczek do zarządzania sesjami użytkowników.
|
|
- **Uwierzytelnianie oparte na tokenach:** Wdrażaj JWT do stateless authentication.
|
|
- **Dostawcy zewnętrzni:** Integruj się z dostawcami OAuth (np. Google, GitHub) za pomocą bibliotek takich jak `next-auth`.
|
|
|
|
**Praktyki bezpieczeństwa:**
|
|
|
|
- **Bezpieczne ciasteczka:** Ustaw atrybuty `HttpOnly`, `Secure` i `SameSite`.
|
|
- **Hashowanie haseł:** Zawsze haszuj hasła przed ich przechowywaniem.
|
|
- **Walidacja danych wejściowych:** Zapobiegaj atakom typu injection poprzez walidację i sanitizację danych wejściowych.
|
|
|
|
**Przykład:**
|
|
```javascript
|
|
// pages/api/login.js
|
|
import { sign } from "jsonwebtoken"
|
|
import { serialize } from "cookie"
|
|
|
|
export default async function handler(req, res) {
|
|
const { username, password } = req.body
|
|
|
|
// Validate user credentials
|
|
if (username === "admin" && password === "password") {
|
|
const token = sign({ username }, process.env.JWT_SECRET, {
|
|
expiresIn: "1h",
|
|
})
|
|
res.setHeader(
|
|
"Set-Cookie",
|
|
serialize("auth", token, {
|
|
path: "/",
|
|
httpOnly: true,
|
|
secure: true,
|
|
sameSite: "strict",
|
|
})
|
|
)
|
|
res.status(200).json({ message: "Logged in" })
|
|
} else {
|
|
res.status(401).json({ error: "Invalid credentials" })
|
|
}
|
|
}
|
|
```
|
|
### Optymalizacja Wydajności
|
|
|
|
**Strategie:**
|
|
|
|
- **Optymalizacja Obrazów:** Użyj komponentu `next/image` w Next.js do automatycznej optymalizacji obrazów.
|
|
- **Podział Kodu:** Wykorzystaj dynamiczne importy do podziału kodu i zmniejszenia czasów ładowania początkowego.
|
|
- **Cache:** Wdroż strategie cache dla odpowiedzi API i statycznych zasobów.
|
|
- **Ładowanie na Żądanie:** Ładuj komponenty lub zasoby tylko wtedy, gdy są potrzebne.
|
|
|
|
**Przykład:**
|
|
```jsx
|
|
// Dynamic Import with Code Splitting
|
|
import dynamic from "next/dynamic"
|
|
|
|
const HeavyComponent = dynamic(() => import("../components/HeavyComponent"), {
|
|
loading: () => <p>Loading...</p>,
|
|
})
|
|
```
|
|
{{#include ../../banners/hacktricks-training.md}}
|