Files
2026-02-24 01:29:59 +01:00

195 lines
5.1 KiB
TeX

\section{JWT}
\begin{frame}[shrink=15]{Mi az a JWT?}
\begin{block}{JSON Web Token (RFC 7519)}
Kompakt, önálló token információ biztonságos továbbításához.
\end{block}
\begin{itemize}
\item Digitálisan aláírt, Base64URL kódolt
\item Használat: authentikáció, stateless session
\item \textbf{NEM} titkosított - payload olvasható!
\end{itemize}
\end{frame}
\begin{frame}[fragile,shrink=15]{JWT formátum}
\texttt{\textcolor{red}{HEADER}.\textcolor{purple}{PAYLOAD}.\textcolor{blue}{SIGNATURE}}
\begin{tiny}
\begin{verbatim}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZ
SI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36P
\end{verbatim}
\end{tiny}
\begin{itemize}
\item \textcolor{red}{Header}: Algoritmus + token típus
\item \textcolor{purple}{Payload}: Claims (user adatok)
\item \textcolor{blue}{Signature}: Integritás védelem
\end{itemize}
\end{frame}
\begin{frame}[fragile,shrink=15]{JWT Header \& Payload}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{Header:}
\begin{verbatim}
{
"alg": "HS256",
"typ": "JWT"
}
\end{verbatim}
\end{column}
\begin{column}{0.48\textwidth}
\textbf{Payload:}
\begin{verbatim}
{
"sub": "1234",
"name": "John",
"iat": 1516239022,
"exp": 1516242622
}
\end{verbatim}
\end{column}
\end{columns}
\begin{alertblock}{Fontos}
Ne tároljunk jelszót payload-ban!
\end{alertblock}
\end{frame}
\begin{frame}[fragile,shrink=15]{JWT Signature}
\begin{verbatim}
HMACSHA256(
base64(header) + "." + base64(payload),
secret
)
\end{verbatim}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{HMAC:} Egy kulcs, gyors (HS256)
\end{column}
\begin{column}{0.48\textwidth}
\textbf{RSA:} Privát+publikus, biztonságosabb (RS256)
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile,shrink=20]{JWT generálás Node.js}
\begin{verbatim}
const jwt = require('jsonwebtoken');
const payload = { userId: user.id, role: user.role };
const token = jwt.sign(
payload,
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
res.json({ token });
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{JWT validálás Node.js}
\begin{verbatim}
const token = req.headers.authorization?.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 (err) {
res.status(403).json({ error: 'Invalid' });
}
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{JWT middleware}
\begin{verbatim}
const authJWT = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).send('Token required');
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.status(403).send('Invalid');
req.user = user;
next();
});
};
app.get('/protected', authJWT, (req, res) => {
res.json({ data: 'Secret', user: req.user });
});
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{JWT vs Session}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{JWT:}
\begin{itemize}
\item Stateless
\item Skálázható
\item Cross-domain
\item Nehéz visszavonni
\item Token méret
\end{itemize}
\end{column}
\begin{column}{0.48\textwidth}
\textbf{Session:}
\begin{itemize}
\item Stateful
\item Szerver tárolja
\item Könnyű visszavonás
\item Nehezebb skálázás
\item Kis cookie
\end{itemize}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[shrink=15]{Access \& Refresh Token}
\begin{block}{Két token stratégia}
\textbf{Access token}: Rövid élet (15 perc), API hozzáférés\\
\textbf{Refresh token}: Hosszú élet (7 nap), új access token generálás
\end{block}
\begin{enumerate}
\item Login $\to$ Access + Refresh token
\item API kérés Access token-nel
\item Access lejár $\to$ Refresh-el új Access-t kér
\item Refresh lejár $\to$ Újra login
\end{enumerate}
\end{frame}
\begin{frame}[fragile,shrink=20]{Refresh Token példa}
\begin{verbatim}
app.post('/refresh', (req, res) => {
const { refreshToken } = req.body;
if (!refreshToken) return res.sendStatus(401);
jwt.verify(refreshToken, REFRESH_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
const accessToken = jwt.sign(
{ userId: user.userId },
ACCESS_SECRET,
{ expiresIn: '15m' }
);
res.json({ accessToken });
});
});
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{JWT Security Best Practices}
\begin{enumerate}
\item Rövid lejárat (15-60 perc)
\item Erős secret kulcs (min 256 bit)
\item HTTPS kötelező
\item Ne tároljunk érzékeny adatot payload-ban
\item Validáld mindig az \texttt{exp} és \texttt{iat} claim-eket
\item Használj RS256-ot HS256 helyett production-ben
\item Refresh token rotation
\item Token blacklist megfontolása
\end{enumerate}
\end{frame}