Files
GKNB_MSTM071/Backend_ppt/authn_z/jwt_old.tex
T
2026-02-24 01:29:59 +01:00

550 lines
15 KiB
TeX

\section{JWT}
\begin{frame}{Mi az a JWT?}
\begin{block}{JSON Web Token (RFC 7519)}
Nyílt szabványú, kompakt és önálló módszer információ biztonságos továbbítására.
\end{block}
\begin{itemize}
\item \textbf{Kompakt:} Kis méret, URL/header-ben is
\item \textbf{Önálló:} Minden információt tartalmaz
\item \textbf{Biztonságos:} Digitálisan aláírt
\item \textbf{Használat:}
\begin{itemize}
\item Authentikáció
\item Információ csere
\item Stateless session
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}[fragile,shrink=10]{JWT formátum}
\begin{block}{Három részből áll, ponttal elválasztva}
\texttt{\textcolor{red}{HEADER}.\textcolor{purple}{PAYLOAD}.\textcolor{blue}{SIGNATURE}}
\end{block}
\begin{exampleblock}{Példa JWT}
\tiny
\begin{verbatim}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZ
SI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36P
OkmLXOUqhfKJ4
\end{verbatim}
\end{exampleblock}
\begin{itemize}
\item \textcolor{red}{\textbf{Header:}} Token típusa és algoritmus
\item \textcolor{purple}{\textbf{Payload:}} Claims (állítások) - felhasználói adatok
\item \textcolor{blue}{\textbf{Signature:}} Aláírás - integritás ellenőrzés
\end{itemize}
\begin{alertblock}{Fontos!}
A JWT Base64URL kódolású, \textbf{NEM} titkosított! A payload tartalma olvasható!
\end{alertblock}
\end{frame}
\begin{frame}[fragile]{JWT Header}
\begin{block}{Token metaadatok}
Token típusa és aláírási algoritmus.
\end{block}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{JSON:}
\begin{verbatim}
{
"alg": "HS256",
"typ": "JWT"
}
\end{verbatim}
\begin{itemize}
\item \texttt{alg}: Algoritmus
\item \texttt{typ}: Token típus
\end{itemize}
\end{column}
\begin{column}{0.48\textwidth}
\textbf{Kódolt:}
\begin{verbatim}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
\end{verbatim}
\textbf{Algoritmusok:}
\begin{itemize}
\item HS256 - HMAC
\item RS256 - RSA
\item ES256 - ECDSA
\end{itemize}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile,shrink=5]{JWT Payload (Claims)}
\begin{block}{Felhasználói adatok és meta}
Claims (allítoltak) a felhasználóról és tokenről.
\end{block}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{Registered:}
\begin{itemize}
\item \texttt{iss} - Kibocsátó
\item \texttt{sub} - Tárgy/user ID
\item \texttt{aud} - Címzett
\item \texttt{exp} - Lejárat
\item \texttt{iat} - Kiállítás
\end{itemize}
\end{column}
\begin{column}{0.48\textwidth}
\textbf{Példa:}
\small
\begin{verbatim}
{
"sub": "1234567890",
"name": "John Doe",
"role": "admin",
"iat": 1516239022,
"exp": 1516242622
}
\end{verbatim}
\end{column}
\end{columns}
\begin{alertblock}{Figyelem!}
Ne tároljunk érzékeny adatokat (jelszó) payload-ban!
\end{alertblock}
\end{frame}
\begin{frame}[fragile,shrink=5]{JWT Signature}
\begin{block}{Digitális aláírás}
Biztosítja a token integritását és hitelességét.
\end{block}
\textbf{Signature (HMAC SHA256):}
\begin{verbatim}
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
\end{verbatim}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{HMAC (Symmetric):}
\begin{itemize}
\item Egy kulcs
\item Gyorsabb
\item HS256
\end{itemize}
\end{column}
\begin{column}{0.48\textwidth}
\textbf{RSA (Asymmetric):}
\begin{itemize}
\item Privát + publikus
\item Biztonságosabb
\item RS256
\end{itemize}
\end{column}
\end{columns}
\end{frame}
\begin{frame}{JWT működése}
\begin enumerate}
\item \textbf{Bejelentkezés:}
\begin{itemize}
\item Username + password
\item Szerver validál
\end{itemize}
\item \textbf{Token generálás:}
\begin{itemize}
\item JWT létrehozás user adatokkal
\item Aláírás titkos kulccsal
\end{itemize}
\item \textbf{Tárolás:}
\begin{itemize}
\item localStorage / cookie
\end{itemize}
\item \textbf{API kérések:}
\begin{itemize}
\item \texttt{Authorization: Bearer <token>}
\item Szerver validálja
\end{itemize}
\end{enumerate}
\end{frame}
\begin{frame}[fragile,shrink=10]{JWT generálás Node.js-ben}
\begin{block}{jsonwebtoken könyvtár használata}
\small
\begin{verbatim}
const jwt = require('jsonwebtoken');
const payload = {
userId: user.id,
email: user.email,
role: user.role
};
const token = jwt.sign(
payload,
process.env.JWT_SECRET,
{ expiresIn: '1h', issuer: 'myapp' }
);
res.json({ token, expiresIn: 3600 });
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile,shrink=10]{JWT validálás Node.js-ben}
\begin{block}{Token ellenőrzés}
\small
\begin{verbatim}
const authHeader = req.headers.authorization;
const token = authHeader?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(403).json({ error: 'Invalid' });
}
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile,shrink=10]{JWT middleware Express-ben}
\begin{block}{Védett route-ok}
\small
\begin{verbatim}
const authenticateJWT = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Token required' });
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.status(403).json({ error: 'Invalid token' });
req.user = user;
next();
});
};
app.get('/api/protected', authenticateJWT, (req, res) => {
res.json({ message: 'Protected', user: req.user });
});
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}{JWT vs Session}
\begin{columns}
\begin{column}{0.48\textwidth}
\begin{block}{JWT (Stateless)}
\textbf{Előnyök:}
\begin{itemize}
\item Skálázható
\item Nincs szerver-oldali tárolás
\item Cross-domain működés
\item Mobile-friendly
\end{itemize}
\vspace{0.3cm}
\textbf{Hátrányok:}
\begin{itemize}
\item Nehéz visszavonni
\item Token méret
\item XSS sebezhetőség (localStorage)
\end{itemize}
\end{block}
\end{column}
\begin{column}{0.48\textwidth}
\begin{block}{Session (Stateful)}
\textbf{Előnyök:}
\begin{itemize}
\item Azonnali visszavonás
\item Kis cookie méret
\item Biztonságosabb token tárolás
\end{itemize}
\vspace{0.3cm}
\textbf{Hátrányok:}
\begin{itemize}
\item Szerver-oldali memória
\item Nehezebb skálázás
\item CORS problémák
\item Session store szükséges
\end{itemize}
\end{block}
\end{column}
\end{columns}
\vspace{0.5cm}
\begin{alertblock}{Melyiket válasszuk?}
Függ az alkalmazás követelményeitől: méret, skálázhatóság, biztonság, komplexitás.
\end{alertblock}
\end{frame}
\begin{frame}{Token tárolás a kliens oldalon}
\begin{columns}
\begin{column}{0.48\textwidth}
\begin{block}{localStorage}
\begin{itemize}
\item Egyszerű
\item JS hozzáférés
\item Megosztott
\end{itemize}
\textcolor{red}{\textbf{XSS!}}
\begin{itemize}
\item \textcolor{red}{JS hozzáférhet}
\end{itemize}
\end{block}
\end{column}
\begin{column}{0.48\textwidth}
\begin{block}{HttpOnly Cookie}
\begin{itemize}
\item JS NEM fér hozzá
\item Automatikus
\item XSS védett
\end{itemize}
\textcolor{red}{\textbf{CSRF}}
\begin{itemize}
\item \textcolor{red}{Védelem kell}
\end{itemize}
\end{block}
\end{column}
\end{columns}
\begin{exampleblock}{Ajánlás}
HttpOnly, Secure, SameSite cookie a legbiztonságosabb.
\end{exampleblock}
\end{frame}
\begin{frame}[fragile]{JWT tárolás HttpOnly Cookie-ban}
\begin{block}{Token beállítás cookie-ban}
\small
\begin{verbatim}
// Login endpoint
app.post('/api/login', (req, res) => {
// ... authentikáció logika ...
const token = jwt.sign(payload, secret, { expiresIn: '1h' });
res.cookie('token', token, {
httpOnly: true, // JavaScript nem férhet hozzá
secure: true, // Csak HTTPS-en keresztül
sameSite: 'strict',// CSRF védelem
maxAge: 3600000 // 1 óra milliszekundumban
});
res.json({ success: true, message: 'Logged in' });
});
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{JWT olvasás Cookie-ból}
\begin{block}{Cookie-parser middleware}
\small
\begin{verbatim}
const cookieParser = require('cookie-parser');
app.use(cookieParser());
const authenticateJWT = (req, res, next) => {
// Token a cookie-ból
const token = req.cookies.token;
if (!token) {
return res.status(401).json({ error: 'Not authenticated' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(403).json({ error: 'Invalid token' });
}
};
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[shrink=5]{Refresh Token stratégia}
\begin{block}{Miért szükséges?}
Access tokenek rövidek (15 perc). Refresh tokennel új access token kérhető.
\end{block}
\begin{itemize}
\item \textbf{Access Token:}
\begin{itemize}
\item Rövid (15-60 perc)
\item API kérésekhez
\end{itemize}
\item \textbf{Refresh Token:}
\begin{itemize}
\item Hosszú (7-30 nap)
\item Új access tokenhez
\item HttpOnly cookie-ban
\item DB-ben tárolva
\end{itemize}
\end{itemize}
\begin{alertblock}{Best Practice}
Refresh token rotation: minden refresh-nél új refresh token is.
\end{alertblock}
\end{frame}
\begin{frame}[fragile]{Refresh Token implementáció}
\begin{block}{Token refresh endpoint}
\small
\begin{verbatim}
app.post('/api/refresh', (req, res) => {
const refreshToken = req.cookies.refreshToken;
if (!refreshToken) {
return res.status(401).json({ error: 'No refresh token' });
}
try {
// Refresh token validálás
const decoded = jwt.verify(refreshToken, process.env.REFRESH_SECRET);
// Ellenőrizzük az adatbázisban
const storedToken = await RefreshToken.findOne({
token: refreshToken,
userId: decoded.userId
});
if (!storedToken) {
return res.status(403).json({ error: 'Invalid refresh token' });
}
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Refresh Token implementáció (folyt.)}
\begin{block}{Új tokenek generálása}
\small
\begin{verbatim}
// Új access token
const accessToken = jwt.sign(
{ userId: decoded.userId, role: decoded.role },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
// Új refresh token (rotation)
const newRefreshToken = jwt.sign(
{ userId: decoded.userId },
process.env.REFRESH_SECRET,
{ expiresIn: '7d' }
);
// Régi token törlése, új mentése az adatbázisba
await RefreshToken.deleteOne({ token: refreshToken });
await RefreshToken.create({ token: newRefreshToken, userId: decoded.userId });
res.cookie('refreshToken', newRefreshToken, { httpOnly: true, ... });
res.json({ accessToken });
} catch (error) {
res.status(403).json({ error: 'Invalid refresh token' });
}
});
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[shrink=5]{JWT biztonság best practices}
\begin{alertblock}{Kritikus pontok}
\begin{itemize}
\item \textbf{Titkos kulcs:} Erős, random, env-ben
\item \textbf{HTTPS:} Mindig!
\item \textbf{Lejárat:} Max 1 óra
\item \textbf{Érzeky adatok:} Ne JWT-ben
\item \textbf{Algoritmus:} Ellenőrizd (ne 'none')
\end{itemize}
\end{alertblock}
\begin{block}{További ajánlások}
\begin{itemize}
\item HttpOnly cookie
\item Refresh token rotation
\item Rate limiting
\item Aud és Iss validálás
\end{itemize}
\end{block}
\end{frame}
\begin{frame}{Gyakori JWT hibák és támadások}
\begin{alertblock}{Gyakori sebezhetőségek}
\begin{enumerate}
\item \textbf{None algoritmus támadás}
\begin{itemize}
\item Header: \texttt{"alg": "none"} - aláírás nélküli token
\item Védelem: Mindig ellenőrizzük az algoritmust
\end{itemize}
\item \textbf{Gyenge titkos kulcs}
\begin{itemize}
\item Rövid vagy közismert kulcs
\item Védelem: Min. 256-bit random kulcs
\end{itemize}
\item \textbf{Token kiszivárogtatás}
\begin{itemize}
\item XSS támadás localStorage-ból
\item Védelem: HttpOnly cookie használata
\end{itemize}
\item \textbf{Algoritmus konfúzió}
\begin{itemize}
\item RS256 publikus kulcs HMAC secret-ként használva
\item Védelem: Explicit algoritmus megadása validáláskor
\end{itemize}
\end{enumerate}
\end{alertblock}
\end{frame}
\begin{frame}{Összefoglalás}
\begin{itemize}
\item \textbf{JWT} = Kompakt, önálló, biztonságos token formátum
\item \textbf{Struktúra:} Header.Payload.Signature
\item \textbf{Előnyök:} Stateless, skálázható, cross-domain
\item \textbf{Claims:} Registered (exp, iat, sub) és Custom (role, email)
\item \textbf{Tárolás:} HttpOnly cookie a legbiztonságosabb
\item \textbf{Refresh token:} Új access token kéréshez hosszú élettartammal
\item \textbf{Biztonság:} HTTPS, erős secret, rövid lejárat, validálás
\end{itemize}
\vspace{0.5cm}
\begin{exampleblock}{Mikor használjuk a JWT-t?}
\begin{itemize}
\item RESTful API authentikáció
\item Microservice architektúra
\item Mobile alkalmazások
\item Single Page Applications (SPA)
\item Stateless session kezelés
\end{itemize}
\end{exampleblock}
\end{frame}