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}}