mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
1187 lines
35 KiB
Markdown
1187 lines
35 KiB
Markdown
# NextJS
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|
|
|
|
## Opšta arhitektura Next.js aplikacije
|
|
|
|
### Tipična struktura fajlova
|
|
|
|
Standardni Next.js projekat prati specifičnu strukturu fajlova i direktorijuma koja olakšava njegove funkcije kao što su rutiranje, API krajnje tačke i upravljanje statičkim resursima. Evo tipičnog rasporeda:
|
|
```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
|
|
|
|
```
|
|
### Osnovne Direktorije i Fajlovi
|
|
|
|
- **public/:** Sadrži statičke resurse kao što su slike, fontovi i drugi fajlovi. Fajlovi ovde su dostupni na korenskom putu (`/`).
|
|
- **app/:** Centralna direktorija za stranice, rasporede, komponente i API rute vaše aplikacije. Obuhvata **App Router** paradigmu, omogućavajući napredne funkcije rutiranja i razdvajanje server-klijent komponenti.
|
|
- **app/layout.tsx:** Definiše osnovni raspored za vašu aplikaciju, obavijajući sve stranice i pružajući dosledne UI elemente kao što su zaglavlja, podnožja i navigacione trake.
|
|
- **app/page.tsx:** Služi kao ulazna tačka za korensku rutu `/`, renderujući početnu stranicu.
|
|
- **app/\[route]/page.tsx:** Rukuje statičnim i dinamičnim rutama. Svaka fascikla unutar `app/` predstavlja segment rute, a `page.tsx` unutar tih fascikli odgovara komponenti rute.
|
|
- **app/api/:** Sadrži API rute, omogućavajući vam da kreirate serverless funkcije koje obrađuju HTTP zahteve. Ove rute zamenjuju tradicionalnu `pages/api` direktoriju.
|
|
- **app/components/:** Sadrži ponovo upotrebljive React komponente koje se mogu koristiti na različitim stranicama i rasporedima.
|
|
- **app/styles/:** Sadrži globalne CSS fajlove i CSS Module za stilizovanje ograničeno na komponente.
|
|
- **app/utils/:** Uključuje pomoćne funkcije, module i drugu logiku koja nije vezana za UI, a koja se može deliti širom aplikacije.
|
|
- **.env.local:** Čuva promenljive okruženja specifične za lokalno razvojno okruženje. Ove promenljive **nisu** uključene u kontrolu verzija.
|
|
- **next.config.js:** Prilagođava ponašanje Next.js, uključujući webpack konfiguracije, promenljive okruženja i bezbednosne postavke.
|
|
- **tsconfig.json:** Konfiguriše TypeScript postavke za projekat, omogućavajući proveru tipova i druge TypeScript funkcije.
|
|
- **package.json:** Upravljanje zavisnostima projekta, skriptama i metapodacima.
|
|
- **README.md:** Pruža dokumentaciju i informacije o projektu, uključujući uputstva za postavljanje, smernice za korišćenje i druge relevantne detalje.
|
|
- **yarn.lock / package-lock.json:** Zaključava zavisnosti projekta na specifične verzije, osiguravajući dosledne instalacije širom različitih okruženja.
|
|
|
|
## Klijentska Strana u Next.js
|
|
|
|
### Rutiranje na Bazi Fajlova u `app` Direktoriji
|
|
|
|
Direktorija `app` je kamen temeljac rutiranja u najnovijim verzijama Next.js. Ona koristi fajl sistem za definisanje ruta, čineći upravljanje rutama intuitivnim i skalabilnim.
|
|
|
|
<details>
|
|
|
|
<summary>Rukovanje Korenskim Putem /</summary>
|
|
|
|
**Struktura Fajlova:**
|
|
```arduino
|
|
my-nextjs-app/
|
|
├── app/
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Ključne datoteke:**
|
|
|
|
- **`app/page.tsx`**: Obradjuje zahteve za korenski put `/`.
|
|
- **`app/layout.tsx`**: Definiše raspored za aplikaciju, obavijajući sve stranice.
|
|
|
|
**Implementacija:**
|
|
```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>
|
|
);
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Definicija Rute:** Datoteka `page.tsx` direktno ispod `app` direktorijuma odgovara `/` ruti.
|
|
- **Renderovanje:** Ova komponenta renderuje sadržaj za početnu stranu.
|
|
- **Integracija Rasporeda:** `HomePage` komponenta je obavijena `layout.tsx`, koja može uključivati zaglavlja, podnožja i druge zajedničke elemente.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Obrada Ostalih Statickih Putanja</summary>
|
|
|
|
**Primer: `/about` Ruta**
|
|
|
|
**Struktura Datoteka:**
|
|
```arduino
|
|
arduinoCopy codemy-nextjs-app/
|
|
├── app/
|
|
│ ├── about/
|
|
│ │ └── page.tsx
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Implementacija:**
|
|
```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>
|
|
)
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Definicija Rute:** Datoteka `page.tsx` unutar `about` foldera odgovara ruti `/about`.
|
|
- **Renderovanje:** Ova komponenta renderuje sadržaj za stranicu o nama.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Dinamičke Rute</summary>
|
|
|
|
Dinamičke rute omogućavaju rukovanje putanjama sa promenljivim segmentima, omogućavajući aplikacijama da prikazuju sadržaj na osnovu parametara kao što su ID-ovi, slugovi, itd.
|
|
|
|
**Primer: `/posts/[id]` Ruta**
|
|
|
|
**Struktura Datoteka:**
|
|
```arduino
|
|
arduinoCopy codemy-nextjs-app/
|
|
├── app/
|
|
│ ├── posts/
|
|
│ │ └── [id]/
|
|
│ │ └── page.tsx
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Implementacija:**
|
|
```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>
|
|
);
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Dinamički Segment:** `[id]` označava dinamički segment u ruti, hvatajući `id` parametar iz URL-a.
|
|
- **Pristup Parametrima:** `params` objekat sadrži dinamičke parametre, dostupne unutar komponente.
|
|
- **Usklađivanje Ruta:** Svaka putanja koja odgovara `/posts/*`, kao što su `/posts/1`, `/posts/abc`, itd., biće obrađena od strane ove komponente.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Ugnježdene Rute</summary>
|
|
|
|
Next.js podržava ugnježdene rute, omogućavajući hijerarhijske strukture ruta koje odražavaju raspored direktorijuma.
|
|
|
|
**Primer: `/dashboard/settings/profile` Ruta**
|
|
|
|
**Struktura Fajlova:**
|
|
```arduino
|
|
arduinoCopy codemy-nextjs-app/
|
|
├── app/
|
|
│ ├── dashboard/
|
|
│ │ ├── settings/
|
|
│ │ │ └── profile/
|
|
│ │ │ └── page.tsx
|
|
│ │ └── page.tsx
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Implementacija:**
|
|
```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>
|
|
);
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Duboko Ugnježdenje:** Datoteka `page.tsx` unutar `dashboard/settings/profile/` odgovara ruti `/dashboard/settings/profile`.
|
|
- **Refleksija Hijerarhije:** Struktura direktorijuma odražava URL putanju, poboljšavajući održivost i jasnoću.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Catch-All Rute</summary>
|
|
|
|
Catch-all rute obrađuju više ugnježdenih segmenata ili nepoznatih putanja, pružajući fleksibilnost u obradi ruta.
|
|
|
|
**Primer: `/*` Ruta**
|
|
|
|
**Struktura Datoteka:**
|
|
```arduino
|
|
my-nextjs-app/
|
|
├── app/
|
|
│ ├── [..slug]/
|
|
│ │ └── page.tsx
|
|
│ ├── layout.tsx
|
|
│ └── page.tsx
|
|
├── public/
|
|
├── next.config.js
|
|
└── ...
|
|
```
|
|
**Implementacija:**
|
|
```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>
|
|
)
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Catch-All Segment:** `[...slug]` hvata sve preostale delove putanje kao niz.
|
|
- **Upotreba:** Korisno za rukovanje dinamičkim rutiranjem kao što su putanje koje generišu korisnici, ugnježdene kategorije, itd.
|
|
- **Usklađivanje Ruta:** Putanje kao što su `/anything/here`, `/foo/bar/baz`, itd., se obrađuju ovim komponentom.
|
|
|
|
</details>
|
|
|
|
### Potencijalne Ranljivosti na Klijentskoj Strani
|
|
|
|
Dok Next.js pruža sigurnu osnovu, nepravilne prakse kodiranja mogu uvesti ranjivosti. Ključne ranjivosti na klijentskoj strani uključuju:
|
|
|
|
<details>
|
|
|
|
<summary>Cross-Site Scripting (XSS)</summary>
|
|
|
|
XSS napadi se dešavaju kada se zlonamerni skripti ubacuju u pouzdane veb sajtove. Napadači mogu izvršavati skripte u pregledačima korisnika, kradući podatke ili obavljajući radnje u ime korisnika.
|
|
|
|
**Primer Ranjivog Koda:**
|
|
```jsx
|
|
// Dangerous: Injecting user input directly into HTML
|
|
function Comment({ userInput }) {
|
|
return <div dangerouslySetInnerHTML={{ __html: userInput }} />
|
|
}
|
|
```
|
|
**Zašto je ranjivo:** Korišćenje `dangerouslySetInnerHTML` sa nepouzdanim ulazima omogućava napadačima da ubace zlonamerne skripte.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Injekcija Šablona na Klijentskoj Strani</summary>
|
|
|
|
Događa se kada se korisnički unosi nepravilno obrađuju u šablonima, omogućavajući napadačima da ubace i izvrše šablone ili izraze.
|
|
|
|
**Primer ranjivog koda:**
|
|
```jsx
|
|
import React from "react"
|
|
import ejs from "ejs"
|
|
|
|
function RenderTemplate({ template, data }) {
|
|
const html = ejs.render(template, data)
|
|
return <div dangerouslySetInnerHTML={{ __html: html }} />
|
|
}
|
|
```
|
|
**Zašto je ranjiv:** Ako `template` ili `data` sadrže zlonamerni sadržaj, to može dovesti do izvršenja nepredviđenog koda.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Klijent Path Traversal</summary>
|
|
|
|
To je ranjivost koja omogućava napadačima da manipulišu putanjama na klijentskoj strani kako bi izvršili nepredviđene radnje, kao što je Cross-Site Request Forgery (CSRF). Za razliku od server-side path traversal, koja cilja na datotečni sistem servera, CSPT se fokusira na iskorišćavanje mehanizama na klijentskoj strani kako bi preusmerio legitimne API zahteve na zlonamerne krajnje tačke.
|
|
|
|
**Primer ranjivog koda:**
|
|
|
|
Next.js aplikacija omogućava korisnicima da otpremaju i preuzimaju datoteke. Funkcija preuzimanja je implementirana na klijentskoj strani, gde korisnici mogu da navedu putanju datoteke za preuzimanje.
|
|
```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>
|
|
)
|
|
}
|
|
```
|
|
#### Napadni Scenarijo
|
|
|
|
1. **Cilj Napadača**: Izvršiti CSRF napad da obriše kritičnu datoteku (npr., `admin/config.json`) manipulišući `filePath`.
|
|
2. **Iskorišćavanje CSPT**:
|
|
- **Zlonamerni Unos**: Napadač kreira URL sa manipulisanom `filePath` kao što je `../deleteFile/config.json`.
|
|
- **Rezultantni API Poziv**: Klijentski kod šalje zahtev na `/api/files/../deleteFile/config.json`.
|
|
- **Rukovanje Servera**: Ako server ne validira `filePath`, obrađuje zahtev, potencijalno brišući ili izlažući osetljive datoteke.
|
|
3. **Izvršavanje CSRF**:
|
|
- **Kreirana Veza**: Napadač šalje žrtvi vezu ili ugrađuje zlonamerni skript koji pokreće zahtev za preuzimanje sa manipulisanom `filePath`.
|
|
- **Ishod**: Žrtva nesvesno izvršava akciju, što dovodi do neovlašćenog pristupa ili brisanja datoteka.
|
|
|
|
#### Zašto je Ranjiv
|
|
|
|
- **Nedostatak Validacije Unosa**: Klijentska strana dozvoljava proizvoljne `filePath` unose, omogućavajući prelazak putanje.
|
|
- **Verovanje Klijentskim Unosima**: Server-side API veruje i obrađuje `filePath` bez sanitizacije.
|
|
- **Potencijalne API Akcije**: Ako API krajnja tačka izvršava akcije koje menjaju stanje (npr., brisanje, modifikovanje datoteka), može se iskoristiti putem CSPT.
|
|
|
|
</details>
|
|
|
|
## Server-Side u Next.js
|
|
|
|
### Server-Side Rendering (SSR)
|
|
|
|
Stranice se renderuju na serveru pri svakom zahtevu, osiguravajući da korisnik dobije potpuno renderovani HTML. U ovom slučaju treba da kreirate svoj prilagođeni server za obradu zahteva.
|
|
|
|
**Upotrebe:**
|
|
|
|
- Dinamički sadržaj koji se često menja.
|
|
- SEO optimizacija, jer pretraživači mogu da indeksiraju potpuno renderovanu stranicu.
|
|
|
|
**Implementacija:**
|
|
```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)
|
|
|
|
Stranice se prethodno renderuju u vreme izgradnje, što rezultira bržim vremenima učitavanja i smanjenim opterećenjem servera.
|
|
|
|
**Upotreba:**
|
|
|
|
- Sadržaj koji se ne menja često.
|
|
- Blogovi, dokumentacija, marketinške stranice.
|
|
|
|
**Implementacija:**
|
|
```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
|
|
```
|
|
### Serverless Functions (API Routes)
|
|
|
|
Next.js omogućava kreiranje API krajnjih tačaka kao serverless funkcije. Ove funkcije se izvršavaju na zahtev bez potrebe za posvećenim serverom.
|
|
|
|
**Upotrebe:**
|
|
|
|
- Obrada slanja obrazaca.
|
|
- Interakcija sa bazama podataka.
|
|
- Obrada podataka ili integracija sa API-jem trećih strana.
|
|
|
|
**Implementacija:**
|
|
|
|
Sa uvođenjem `app` direktorijuma u Next.js 13, rutiranje i rukovanje API-jem su postali fleksibilniji i moćniji. Ovaj moderni pristup se blisko usklađuje sa sistemom rutiranja zasnovanim na datotekama, ali uvodi poboljšane mogućnosti, uključujući podršku za server i klijentske komponente.
|
|
|
|
#### Basic Route Handler
|
|
|
|
**Struktura datoteka:**
|
|
```go
|
|
my-nextjs-app/
|
|
├── app/
|
|
│ └── api/
|
|
│ └── hello/
|
|
│ └── route.js
|
|
├── package.json
|
|
└── ...
|
|
```
|
|
**Implementacija:**
|
|
```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))
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Lokacija:** API rute se nalaze u `app/api/` direktorijumu.
|
|
- **Naziv fajlova:** Svaki API endpoint se nalazi u svojoj fascikli koja sadrži `route.js` ili `route.ts` fajl.
|
|
- **Izvezene funkcije:** Umesto jednog podrazumevanog izvoza, specifične funkcije HTTP metoda (npr., `GET`, `POST`) se izvoze.
|
|
- **Obrada odgovora:** Koristite `Response` konstruktor za vraćanje odgovora, omogućavajući veću kontrolu nad header-ima i status kodovima.
|
|
|
|
#### Kako obraditi druge putanje i metode:
|
|
|
|
<details>
|
|
|
|
<summary>Obrada specifičnih HTTP metoda</summary>
|
|
|
|
Next.js 13+ omogućava vam da definišete handler-e za specifične HTTP metode unutar istog `route.js` ili `route.ts` fajla, promovišući jasniji i organizovaniji kod.
|
|
|
|
**Primer:**
|
|
```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" },
|
|
})
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Višestruki Izvozi:** Svaka HTTP metoda (`GET`, `PUT`, `DELETE`) ima svoju funkciju za izvoz.
|
|
- **Parametri:** Drugi argument omogućava pristup parametrima rute putem `params`.
|
|
- **Poboljšani Odgovori:** Veća kontrola nad objektima odgovora, omogućavajući precizno upravljanje zaglavljem i statusnim kodom.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Catch-All i Ugnježdene Rute</summary>
|
|
|
|
Next.js 13+ podržava napredne funkcije usmeravanja kao što su catch-all rute i ugnježdene API rute, omogućavajući dinamičnije i skalabilnije API strukture.
|
|
|
|
**Primer Catch-All Rute:**
|
|
```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" },
|
|
})
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Sintaksa:** `[...]` označava segment koji obuhvata sve, hvatajući sve ugnježdene putanje.
|
|
- **Upotreba:** Korisno za API-je koji treba da obrade različite dubine ruta ili dinamičke segmente.
|
|
|
|
**Primer ugnježdenih ruta:**
|
|
```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" },
|
|
}
|
|
)
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Duboko Ugnježdenje:** Omogućava hijerarhijske API strukture, odražavajući odnose resursa.
|
|
- **Pristup Parametrima:** Lako pristupite više parametara rute putem `params` objekta.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Upravljanje API rutama u Next.js 12 i ranije</summary>
|
|
|
|
## API Rute u `pages` direktorijumu (Next.js 12 i ranije)
|
|
|
|
Pre nego što je Next.js 13 uveo `app` direktorijum i poboljšane mogućnosti rutiranja, API rute su se prvenstveno definisale unutar `pages` direktorijuma. Ovaj pristup se i dalje široko koristi i podržava u Next.js 12 i ranijim verzijama.
|
|
|
|
#### Osnovna API Ruta
|
|
|
|
**Struktura Fajlova:**
|
|
```go
|
|
goCopy codemy-nextjs-app/
|
|
├── pages/
|
|
│ └── api/
|
|
│ └── hello.js
|
|
├── package.json
|
|
└── ...
|
|
```
|
|
**Implementacija:**
|
|
```javascript
|
|
javascriptCopy code// pages/api/hello.js
|
|
|
|
export default function handler(req, res) {
|
|
res.status(200).json({ message: 'Hello, World!' });
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Lokacija:** API rute se nalaze u `pages/api/` direktorijumu.
|
|
- **Izvoz:** Koristite `export default` da definišete funkciju handler.
|
|
- **Potpis funkcije:** Handler prima `req` (HTTP zahtev) i `res` (HTTP odgovor) objekte.
|
|
- **Ruting:** Ime fajla (`hello.js`) se mapira na krajnju tačku `/api/hello`.
|
|
|
|
#### Dinamičke API Rute
|
|
|
|
**Struktura fajla:**
|
|
```bash
|
|
bashCopy codemy-nextjs-app/
|
|
├── pages/
|
|
│ └── api/
|
|
│ └── users/
|
|
│ └── [id].js
|
|
├── package.json
|
|
└── ...
|
|
```
|
|
**Implementacija:**
|
|
```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`);
|
|
}
|
|
}
|
|
```
|
|
**Objašnjenje:**
|
|
|
|
- **Dinamički segmenti:** Kvadratne zagrade (`[id].js`) označavaju dinamičke delove rute.
|
|
- **Pristup parametrima:** Koristite `req.query.id` za pristup dinamičkom parametru.
|
|
- **Rukovanje metodama:** Iskoristite uslovnu logiku za rukovanje različitim HTTP metodama (`GET`, `PUT`, `DELETE`, itd.).
|
|
|
|
#### Rukovanje različitim HTTP metodama
|
|
|
|
Dok osnovni primer API rute obrađuje sve HTTP metode unutar jedne funkcije, možete strukturirati svoj kod da obrađuje svaku metodu eksplicitno radi bolje jasnoće i održivosti.
|
|
|
|
**Primer:**
|
|
```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`);
|
|
}
|
|
}
|
|
```
|
|
**Najbolje Prakse:**
|
|
|
|
- **Razdvajanje Odgovornosti:** Jasno razdvojiti logiku za različite HTTP metode.
|
|
- **Doslednost Odgovora:** Osigurati dosledne strukture odgovora radi lakšeg rukovanja na klijentskoj strani.
|
|
- **Rukovanje Greškama:** Elegantno obraditi nepodržane metode i neočekivane greške.
|
|
|
|
</details>
|
|
|
|
### CORS Konfiguracija
|
|
|
|
Kontrolisati koje izvore mogu pristupiti vašim API rutama, smanjujući ranjivosti vezane za deljenje resursa između različitih izvora (CORS).
|
|
|
|
**Primer Loše Konfiguracije:**
|
|
```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",
|
|
},
|
|
})
|
|
}
|
|
```
|
|
Napomena da **CORS može biti konfigurisano u svim API rutama** unutar **`middleware.ts`** fajla:
|
|
```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: '*'`:** Dozvoljava bilo kojoj veb stranici da pristupi API-ju, potencijalno omogućavajući zlonamernim sajtovima da komuniciraju sa vašim API-jem bez ograničenja.
|
|
- **Široka dozvola metoda:** Dozvoljavanje svih metoda može omogućiti napadačima da izvrše neželjene radnje.
|
|
|
|
**Kako napadači to koriste:**
|
|
|
|
Napadači mogu kreirati zlonamerne veb stranice koje šalju zahteve vašem API-ju, potencijalno zloupotrebljavajući funkcionalnosti kao što su preuzimanje podataka, manipulacija podacima ili pokretanje neželjenih radnji u ime autentifikovanih korisnika.
|
|
|
|
{{#ref}}
|
|
../../pentesting-web/cors-bypass.md
|
|
{{#endref}}
|
|
|
|
### Izloženost server koda na klijentskoj strani
|
|
|
|
Lako je **koristiti kod koji koristi server takođe u kodu koji je izložen i koristi se na klijentskoj strani**, najbolji način da se osigura da datoteka koda nikada nije izložena na klijentskoj strani je korišćenje ovog uvoza na početku datoteke:
|
|
```js
|
|
import "server-only"
|
|
```
|
|
## Ključne datoteke i njihove uloge
|
|
|
|
### `middleware.ts` / `middleware.js`
|
|
|
|
**Lokacija:** Korenski deo projekta ili unutar `src/`.
|
|
|
|
**Svrha:** Izvršava kod u serverless funkciji na serverskoj strani pre nego što se zahtev obradi, omogućavajući zadatke kao što su autentifikacija, preusmeravanja ili modifikovanje odgovora.
|
|
|
|
**Tok izvršenja:**
|
|
|
|
1. **Dolazni zahtev:** Middleware presreće zahtev.
|
|
2. **Obrada:** Izvršava operacije na osnovu zahteva (npr., provera autentifikacije).
|
|
3. **Modifikacija odgovora:** Može izmeniti odgovor ili preneti kontrolu sledećem handleru.
|
|
|
|
**Primeri korišćenja:**
|
|
|
|
- Preusmeravanje neautentifikovanih korisnika.
|
|
- Dodavanje prilagođenih zaglavlja.
|
|
- Zapisivanje zahteva.
|
|
|
|
**Primer konfiguracije:**
|
|
```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`
|
|
|
|
**Lokacija:** Korenski direktorijum projekta.
|
|
|
|
**Svrha:** Konfiguriše ponašanje Next.js, omogućavajući ili onemogućavajući funkcije, prilagođavajući webpack konfiguracije, postavljajući promenljive okruženja i konfigurišući nekoliko bezbednosnih funkcija.
|
|
|
|
**Ključne bezbednosne konfiguracije:**
|
|
|
|
<details>
|
|
|
|
<summary>Bezbednosni zaglavlja</summary>
|
|
|
|
Bezbednosna zaglavlja poboljšavaju bezbednost vaše aplikacije tako što upućuju pretraživače kako da rukuju sadržajem. Pomažu u ublažavanju raznih napada kao što su Cross-Site Scripting (XSS), Clickjacking i MIME type sniffing:
|
|
|
|
- Content Security Policy (CSP)
|
|
- X-Frame-Options
|
|
- X-Content-Type-Options
|
|
- Strict-Transport-Security (HSTS)
|
|
- Referrer Policy
|
|
|
|
**Primeri:**
|
|
```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>Podešavanja optimizacije slika</summary>
|
|
|
|
Next.js optimizuje slike za performanse, ali pogrešna podešavanja mogu dovesti do sigurnosnih ranjivosti, kao što je omogućavanje nepouzdanih izvora da ubace zlonamerni sadržaj.
|
|
|
|
**Primer lošeg podešavanja:**
|
|
```javascript
|
|
// next.config.js
|
|
|
|
module.exports = {
|
|
images: {
|
|
domains: ["*"], // Allows images from any domain
|
|
},
|
|
}
|
|
```
|
|
**Problem:**
|
|
|
|
- **`'*'`:** Dozvoljava učitavanje slika sa bilo kog spoljnog izvora, uključujući nepouzdane ili zlonamerne domene. Napadači mogu hostovati slike koje sadrže zlonamerne payload-e ili sadržaj koji obmanjuje korisnike.
|
|
- Drugi problem može biti dozvoliti domenu **gde bilo ko može da otpremi sliku** (kao što je `raw.githubusercontent.com`)
|
|
|
|
**Kako napadači to zloupotrebljavaju:**
|
|
|
|
Ubacivanjem slika iz zlonamernih izvora, napadači mogu izvesti phishing napade, prikazati obmanjujuće informacije ili iskoristiti ranjivosti u bibliotekama za renderovanje slika.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Izloženost promenljivih okruženja</summary>
|
|
|
|
Upravljajte osetljivim informacijama kao što su API ključevi i kredencijali baze podataka na siguran način bez izlaganja klijentu.
|
|
|
|
#### a. Izlaganje osetljivih promenljivih
|
|
|
|
**Loš primer konfiguracije:**
|
|
```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 `NEXT_PUBLIC_` prefiksa, Next.js ne izlaže varijable klijentu. Međutim, ako se greškom doda prefiks (npr., `NEXT_PUBLIC_SECRET_API_KEY`), postaje dostupno na strani klijenta.
|
|
|
|
**Kako napadači to zloupotrebljavaju:**
|
|
|
|
Ako su osetljive varijable izložene klijentu, napadači ih mogu preuzeti inspekcijom koda na strani klijenta ili mrežnih zahteva, stičući neovlašćen pristup API-ima, bazama podataka ili drugim uslugama.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Redirects</summary>
|
|
|
|
Upravljajte URL preusmeravanjima i prepisivanjima unutar vaše aplikacije, osiguravajući da su korisnici pravilno usmereni bez uvođenja ranjivosti otvorenog preusmeravanja.
|
|
|
|
#### a. Open Redirect Vulnerability
|
|
|
|
**Primer loše konfiguracije:**
|
|
```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:**
|
|
|
|
- **Dinamička destinacija:** Omogućava korisnicima da navedu bilo koju URL adresu, što omogućava napade otvorenog preusmeravanja.
|
|
- **Verovanje korisničkom unosu:** Preusmeravanje na URL adrese koje su pružili korisnici bez validacije može dovesti do fišinga, distribucije malvera ili krađe akreditiva.
|
|
|
|
**Kako napadači to zloupotrebljavaju:**
|
|
|
|
Napadači mogu kreirati URL adrese koje izgledaju kao da potiču sa vaše domene, ali preusmeravaju korisnike na zlonamerne sajtove. Na primer:
|
|
```bash
|
|
https://yourdomain.com/redirect?url=https://malicious-site.com
|
|
```
|
|
Korisnici koji veruju originalnoj domeni mogu nesvesno navigirati do štetnih veb sajtova.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Webpack Konfiguracija</summary>
|
|
|
|
Prilagodite Webpack konfiguracije za vašu Next.js aplikaciju, koje mogu nenamerno uvesti sigurnosne ranjivosti ako se ne rukuje pažljivo.
|
|
|
|
#### a. Izlaganje Osetljivih Modula
|
|
|
|
**Loš Primer Konfiguracije:**
|
|
```javascript
|
|
// next.config.js
|
|
|
|
module.exports = {
|
|
webpack: (config, { isServer }) => {
|
|
if (!isServer) {
|
|
config.resolve.alias["@sensitive"] = path.join(__dirname, "secret-folder")
|
|
}
|
|
return config
|
|
},
|
|
}
|
|
```
|
|
**Problem:**
|
|
|
|
- **Izlaganje osetljivih putanja:** Aliasiranje osetljivih direktorijuma i omogućavanje pristupa sa klijentske strane može dovesti do curenja poverljivih informacija.
|
|
- **Pakovanje tajni:** Ako su osetljivi fajlovi pakovani za klijenta, njihovi sadržaji postaju dostupni putem izvornih mapa ili inspekcijom koda sa klijentske strane.
|
|
|
|
**Kako napadači to zloupotrebljavaju:**
|
|
|
|
Napadači mogu pristupiti ili rekonstruisati strukturu direktorijuma aplikacije, potencijalno pronalazeći i eksploatišući osetljive fajlove ili podatke.
|
|
|
|
</details>
|
|
|
|
### `pages/_app.js` i `pages/_document.js`
|
|
|
|
#### **`pages/_app.js`**
|
|
|
|
**Svrha:** Preuzima podrazumevanu App komponentu, omogućavajući globalno stanje, stilove i komponente rasporeda.
|
|
|
|
**Upotrebe:**
|
|
|
|
- Umetanje globalnog CSS-a.
|
|
- Dodavanje omotača rasporeda.
|
|
- Integracija biblioteka za upravljanje stanjem.
|
|
|
|
**Primer:**
|
|
```jsx
|
|
// pages/_app.js
|
|
import "../styles/globals.css"
|
|
|
|
function MyApp({ Component, pageProps }) {
|
|
return <Component {...pageProps} />
|
|
}
|
|
|
|
export default MyApp
|
|
```
|
|
#### **`pages/_document.js`**
|
|
|
|
**Svrha:** Zamenjuje podrazumevani dokument, omogućavajući prilagođavanje HTML i Body tagova.
|
|
|
|
**Primeri upotrebe:**
|
|
|
|
- Modifikovanje `<html>` ili `<body>` tagova.
|
|
- Dodavanje meta tagova ili prilagođenih skripti.
|
|
- Integracija fontova trećih strana.
|
|
|
|
**Primer:**
|
|
```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
|
|
```
|
|
### Prilagođeni Server (Opcionalno)
|
|
|
|
**Svrha:** Dok Next.js dolazi sa ugrađenim serverom, možete kreirati prilagođeni server za napredne slučajeve korišćenja kao što su prilagođeno usmeravanje ili integracija sa postojećim backend uslugama.
|
|
|
|
**Napomena:** Korišćenje prilagođenog servera može ograničiti opcije implementacije, posebno na platformama kao što je Vercel koje optimizuju za ugrađeni server Next.js.
|
|
|
|
**Primer:**
|
|
```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")
|
|
})
|
|
})
|
|
```
|
|
---
|
|
|
|
## Dodatne Arhitektonske i Bezbednosne Razmatranja
|
|
|
|
### Promenljive Okruženja i Konfiguracija
|
|
|
|
**Svrha:** Upravljanje osetljivim informacijama i podešavanjima konfiguracije van koda.
|
|
|
|
**Najbolje Prakse:**
|
|
|
|
- **Koristite `.env` Fajlove:** Čuvajte promenljive kao što su API ključevi u `.env.local` (isključeno iz kontrole verzija).
|
|
- **Pristupite Promenljivim Sigurno:** Koristite `process.env.VARIABLE_NAME` za pristup promenljivim okruženja.
|
|
- **Nikada ne Izlažite Tajne na Klijentu:** Osigurajte da se osetljive promenljive koriste samo na serverskoj strani.
|
|
|
|
**Primer:**
|
|
```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
|
|
},
|
|
}
|
|
```
|
|
**Napomena:** Da biste ograničili promenljive samo na serversku stranu, izostavite ih iz `env` objekta ili ih prefiksirajte sa `NEXT_PUBLIC_` za izlaganje klijentu.
|
|
|
|
### Autentifikacija i Autorizacija
|
|
|
|
**Pristup:**
|
|
|
|
- **Autentifikacija zasnovana na sesiji:** Koristite kolačiće za upravljanje korisničkim sesijama.
|
|
- **Autentifikacija zasnovana na tokenima:** Implementirajte JWT-ove za stateless autentifikaciju.
|
|
- **Treće strane:** Integracija sa OAuth provajderima (npr., Google, GitHub) koristeći biblioteke kao što je `next-auth`.
|
|
|
|
**Prakse bezbednosti:**
|
|
|
|
- **Sigurni kolačići:** Postavite atribute `HttpOnly`, `Secure` i `SameSite`.
|
|
- **Hashovanje lozinki:** Uvek hashujte lozinke pre nego što ih sačuvate.
|
|
- **Validacija unosa:** Sprečite napade injekcijom validacijom i sanitizacijom unosa.
|
|
|
|
**Primer:**
|
|
```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" })
|
|
}
|
|
}
|
|
```
|
|
### Optimizacija Performansi
|
|
|
|
**Strategije:**
|
|
|
|
- **Optimizacija Slika:** Koristite Next.js-ov `next/image` komponent za automatsku optimizaciju slika.
|
|
- **Deljenje Koda:** Iskoristite dinamičke uvoze za deljenje koda i smanjenje vremena učitavanja.
|
|
- **Keširanje:** Implementirajte strategije keširanja za API odgovore i statičke resurse.
|
|
- **Lenjo Učitavanje:** Učitajte komponente ili resurse samo kada su potrebni.
|
|
|
|
**Primer:**
|
|
```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}}
|