Compare commits

...

2 Commits

Author SHA1 Message Date
magdo a837f5ecba authn_z 2026-02-24 01:30:22 +01:00
magdo 31d4479c63 authn_z 2026-02-24 01:29:59 +01:00
11 changed files with 1806 additions and 0 deletions
+205
View File
@@ -0,0 +1,205 @@
\section{Authentikáció}
\begin{frame}{Mi az authentikáció?}
\begin{block}{Definíció}
Folyamat, amely során a rendszer ellenőrzi egy felhasználó identitását.
\end{block}
\begin{itemize}
\item \textbf{Kérdés:} Ki vagy?
\item \textbf{Cél:} Felhasználó identitásának megállapítása
\item \textbf{Eredmény:} Sikeres vagy sikertelen azonosítás
\end{itemize}
\begin{alertblock}{Fontos!}
Authentikáció $\neq$ Autorizáció!
\end{alertblock}
\end{frame}
\begin{frame}{Authentikáció vs. Autorizáció}
\begin{columns}
\begin{column}{0.48\textwidth}
\begin{block}{Authentikáció}
\begin{itemize}
\item Ki vagy?
\item Bejelentkezés
\item Példa: Jelszó ellenőrzés
\end{itemize}
\end{block}
\end{column}
\begin{column}{0.48\textwidth}
\begin{block}{Autorizáció}
\begin{itemize}
\item Mit tehetsz?
\item Jogosultságok
\item Példa: Admin jogosultság
\end{itemize}
\end{block}
\end{column}
\end{columns}
\begin{center}
\texttt{Authentikáció} $\rightarrow$ \texttt{Autorizáció}
\end{center}
\end{frame}
\begin{frame}{Authentikációs módszerek}
\begin{enumerate}
\item \textbf{Tudás alapú}
\begin{itemize}
\item Példa: jelszó, PIN kód
\end{itemize}
\item \textbf{Tulajdon alapú}
\begin{itemize}
\item Példa: okostelefon, hardver token
\end{itemize}
\item \textbf{Inherencia alapú}
\begin{itemize}
\item Példa: ujjlenyomat, arcfelismerés
\end{itemize}
\end{enumerate}
\end{frame}
\begin{frame}{Többfaktoros authentikáció (MFA)}
\begin{block}{Multi-Factor Authentication}
Két vagy több független faktor kombinációja.
\end{block}
\begin{itemize}
\item \textbf{2FA példák:}
\begin{itemize}
\item Jelszó + SMS kód
\item Jelszó + Authenticator app
\item Jelszó + ujjlenyomat
\end{itemize}
\item \textbf{Előnyök:}
\begin{itemize}
\item Magasabb biztonság
\item Védelem jelszó kompromittálódás esetén
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Jelszó alapú authentikáció}
\begin{block}{Leggyakoribb módszer}
Felhasználónév + jelszó párossal történő azonosítás.
\end{block}
\begin{itemize}
\item \textbf{Folyamat:}
\begin{enumerate}
\item Felhasználó megadja username + password
\item Rendszer összehasonlítja a hash-sel
\item Sikeres/sikertelen válasz
\end{enumerate}
\item \textbf{Biztonság:}
\begin{itemize}
\item Soha ne tároljuk plain text-ben!
\item Erős hash (bcrypt, Argon2)
\item Salt minden jelszóhoz
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}{Token alapú authentikáció}
\begin{block}{Modern megközelítés}
Bejelentkezés után szerver tokent generál, kliens minden kéréshez csatolja.
\end{block}
\begin{enumerate}
\item Bejelentkezés (username + password)
\item Szerver ellenőrzi
\item Token generálás
\item Kliens eltárolja (localStorage, cookie)
\item Token csatolása minden kéréshez
\item Szerver validálja
\end{enumerate}
\begin{itemize}
\item \textbf{Típusok:} JWT, OAuth, API keys
\item \textbf{Előnyök:} Stateless, skálázható
\end{itemize}
\end{frame}
\begin{frame}{Session alapú authentikáció}
\begin{block}{Hagyományos megközelítés}
Bejelentkezési információkat a szerver tárolja session-ökben.
\end{block}
\begin{enumerate}
\item Bejelentkezés
\item Szerver session létrehozás
\item Session ID küldése cookie-ban
\item Kliens csatolja minden kéréshez
\item Szerver azonosítja a felhasználót
\end{enumerate}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{Előnyök:}
\begin{itemize}
\item Biztonságosabb
\item Könnyű visszavonás
\end{itemize}
\end{column}
\begin{column}{0.48\textwidth}
\textbf{Hátrányok:}
\begin{itemize}
\item Stateful
\item Nehezebb skálázás
\end{itemize}
\end{column}
\end{columns}
\end{frame}
\begin{frame}{OAuth 2.0 / OpenID Connect}
\begin{block}{Harmadik fél authentikáció}
Bejelentkezés külső szolgáltatókkal (Google, Facebook, GitHub).
\end{block}
\begin{itemize}
\item \textbf{OAuth 2.0:} Autorizációs framework
\item \textbf{OpenID Connect:} Authentikációs réteg
\item \textbf{Előnyök:}
\begin{itemize}
\item Nincs jelszó kezelés
\item Jobb UX
\item Biztonságos protokoll
\end{itemize}
\item \textbf{Használat:}
\begin{itemize}
\item Social login
\item SSO megoldások
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}[shrink=5]{Biztonsági megfontolások}
\begin{alertblock}{Gyakori sebezhetőségek}
\begin{itemize}
\item Gyenge jelszavak
\item Nincs rate limiting
\item Token kiszivárogtatás
\item Man-in-the-middle (nincs HTTPS)
\end{itemize}
\end{alertblock}
\begin{block}{Best Practices}
\begin{itemize}
\item HTTPS mindig
\item Erős jelszó policy
\item Rate limiting
\item MFA
\item Token lejárati idő
\item CSRF védelem
\end{itemize}
\end{block}
\end{frame}
Binary file not shown.
+25
View File
@@ -0,0 +1,25 @@
\documentclass[usenames,dvipsnames,aspectratio=169]{beamer}
\usepackage{../common/webfejl}
\title[Webtechnológia és webalkalmazás-fejlesztés - Auth]{Webtechnológia és webalkalmazás-fejlesztés - Auth}
\subtitle{Authentikáció és autorizáció}
\begin{document}
\begin{frame}[plain]
\titlepage
\logoalul
\end{frame}
\input{authn.tex}
\input{authz.tex}
\input{hash.tex}
\input{cookies.tex}
\input{session.tex}
\input{jwt.tex}
\input{oauth2.tex}
\input{middlewares.tex}
\input{services.tex}
\end{document}
+191
View File
@@ -0,0 +1,191 @@
\section{Autorizáció}
\begin{frame}{Mi az autorizáció?}
\begin{block}{Definíció}
Meghatározza, hogy egy azonosított felhasználó milyen erőforrásokhoz férhet hozzá és milyen műveleteket végezhet.
\end{block}
\begin{itemize}
\item \textbf{Kérdés:} Mit tehetsz?
\item \textbf{Cél:} Jogosultságok szabályozása
\item \textbf{Eredmény:} Engedélyezett vagy tiltott művelet
\end{itemize}
\begin{alertblock}{Fontos!}
Autorizáció az authentikáció után történik.
\end{alertblock}
\end{frame}
\begin{frame}{Autorizációs modelljei}
\begin{enumerate}
\item \textbf{RBAC (Role-Based Access Control)}
\begin{itemize}
\item Szerepkörök alapján
\item Példa: Admin, Editor, User
\end{itemize}
\item \textbf{ABAC (Attribute-Based)}
\begin{itemize}
\item Attribútum alapján (user, resource, context)
\item Példa: "Department = IT és 9-17 között"
\end{itemize}
\item \textbf{ACL (Access Control List)}
\begin{itemize}
\item Erőforrás-szintű lista
\item Példa: fájlrendszer jogosultságok
\end{itemize}
\end{enumerate}
\end{frame}
\begin{frame}{RBAC - Szerepkör alapú}
\begin{block}{Lényege}
Felhasználók szerepköröket kapnak, ez határozza meg a jogosultságokat.
\end{block}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{Előnyök:}
\begin{itemize}
\item Könnyű adminisztráció
\item Átlátható
\item Gyors ellenőrzés
\end{itemize}
\end{column}
\begin{column}{0.48\textwidth}
\textbf{Hátrányok:}
\begin{itemize}
\item Skálázhatóság
\item Kevesebb rugalmasság
\end{itemize}
\end{column}
\end{columns}
\end{frame}
\begin{frame}{ABAC - Attribútum alapú}
\begin{block}{Lényege}
Hozzáférési szabályok attribútumok alapján.
\end{block}
\begin{itemize}
\item \textbf{User:} szerepkör, osztály, beosztás
\item \textbf{Resource:} tulajdonos, típus
\item \textbf{Context:} idő, hely, eszköz
\end{itemize}
\begin{exampleblock}{Példa szabály}
\texttt{(role=Manager) AND (resource.owner = user) AND (time < 18:00)}
\end{exampleblock}
\end{frame}
\begin{frame}{ACL - Access Control List}
\begin{block}{Lényege}
Erőforrásonként tárolt lista a hozzáférési jogokról.
\end{block}
\begin{itemize}
\item \textbf{Példa:} fájlrendszer (read, write, execute)
\item \textbf{Előny:} finém hozzáférés
\item \textbf{Hátrány:} nagy rendszereknelnehéz kezelni
\end{itemize}
\end{frame}
\begin{frame}{Autorizáció webalkalm azásban}
\begin{block}{Tipikus folyamat}
Szerver minden kérésnél ellenőrzi a jogosultságot.
\end{block}
\begin{enumerate}
\item Authnentikáció után szerepkör kiosztás
\item Tokenben vagy session-ben tárolás
\item Middleware ellenőrzi a hozzáférést
\item Nincs jog: \texttt{403 Forbidden}
\end{enumerate}
\begin{alertblock}{HTTP státuszkód}
\texttt{401} = nincs auth, \texttt{403} = nincs jogosultság
\end{alertblock}
\end{frame}
\begin{frame}[fragile,shrink=10]{Autorizációs middleware (RBAC)}
\begin{exampleblock}{Egyszerű szerepkör ellenőrzés}
\tiny
\begin{verbatim}
const authorize = (...roles) => {
return (req, res, next) => {
const { role } = req.user; // pl. JWT-ből
if (!roles.includes(role)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
};
app.get('/admin', auth, authorize('Admin'), (req, res) => {
res.json({ data: 'Admin content' });
});
\end{verbatim}
\end{exampleblock}
\end{frame}
\begin{frame}[fragile,shrink=10]{Policy alapú autorizáció (ABAC)}
\begin{exampleblock}{Szabály központú hozzáférés}
\tiny
\begin{verbatim}
const canAccess = (user, resource) => {
return user.department === resource.department &&
user.level >= resource.requiredLevel &&
new Date().getHours() < 18;
};
app.get('/reports/:id', auth, async (req, res) => {
const report = await getReport(req.params.id);
if (!canAccess(req.user, report)) {
return res.status(403).json({ error: 'Forbidden' });
}
res.json(report);
});
\end{verbatim}
\end{exampleblock}
\end{frame}
\begin{frame}{Legkisebb jogosultság elve}
\begin{block}{Principle of Least Privilege}
Mindenki csak a feladatohoz szükséges minimális jogokat kapja.
\end{block}
\begin{itemize}
\item Csökkenti a kockázatot
\item Korlátozza a hibák hatását
\item Egyszerűbb auditálás
\end{itemize}
\begin{alertblock}{Gyakori hiba}
\textbf{Mindenki admin} = gyors fejlesztés, de veszélyes élesben!
\end{alertblock}
\end{frame}
\begin{frame}{Autorizáció Best Practices}
\begin{itemize}
\item Minden érzékeny végpontot ellenőrizz
\item Middleware vagy policy réteg
\item Role/policy központi kezelés
\item Logolás
\item Admin funkciók külön kezelése
\item RBAC + ABAC kombináció
\end{itemize}
\end{frame}
\begin{frame}{Összefoglalás - Autorizáció}
\begin{itemize}
\item Autorizáció = hozzáférések és jogosultságok kezelése
\item 401 vs 403: authentikáció hiánya vs jogosultság hiánya
\item Fő modellek: RBAC, ABAC, ACL
\item Middleware-ekkel megvalósítható a gyakorlatban
\item Least Privilege elv alkalmazása
\end{itemize}
\vspace{0.5cm}
\end{frame}
+166
View File
@@ -0,0 +1,166 @@
\section{HTTP Cookies}
\begin{frame}[shrink=15]{Mi az a Cookie?}
\begin{block}{HTTP Cookie definíció}
Kis méretű adat (max 4KB), amit szerver küld böngészőnek, automatikusan visszaküldődik.
\end{block}
\begin{itemize}
\item Session kezelés, preferenciák, tracking
\item Beállítható élettartam
\end{itemize}
\end{frame}
\begin{frame}[fragile,shrink=15]{Cookie beállítása Express-ben}
\begin{verbatim}
// Egyszerű cookie
res.cookie('session', 'abc123');
// Opciókkal
res.cookie('user', 'john', {
maxAge: 900000, // 15 perc ms-ban
httpOnly: true, // JS nem fér hozzá
secure: true, // csak HTTPS
sameSite: 'strict' // CSRF védelem
});
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{Cookie attribútumok}
\begin{small}
\begin{itemize}
\item \textbf{Domain}: \texttt{.example.com} - subdomain-ek
\item \textbf{Path}: \texttt{/api} - URL path scope
\item \textbf{Expires/Max-Age}: Lejárat ideje
\item \textbf{HttpOnly}: JS hozzáférés blokkolása (XSS védelem)
\item \textbf{Secure}: Csak HTTPS-en küldve
\item \textbf{SameSite}: \texttt{Strict|Lax|None} - CSRF védelem
\end{itemize}
\end{small}
\end{frame}
\begin{frame}[shrink=15]{Cookie típusok}
\begin{enumerate}
\item \textbf{Session Cookie}: Nincs Expires/Max-Age, böngésző bezáráskor törlődik
\item \textbf{Persistent Cookie}: Van lejárati idő, túléli böngésző bezárást
\item \textbf{Secure Cookie}: Csak HTTPS-en
\item \textbf{HttpOnly Cookie}: JS nem fér hozzá
\item \textbf{SameSite Cookie}: CSRF támadás ellen
\item \textbf{Third-party Cookie}: Más domain-ről
\end{enumerate}
\end{frame}
\begin{frame}[shrink=15]{SameSite Cookie attribútum}
\begin{description}
\item[Strict] Cookie csak saját site kérésekkel küldve. Legjobb CSRF védelem.
\item[Lax] GET kéréseknél küldi cross-site. Default modern böngészőkben.
\item[None] Mindig küldi (Secure kötelező). Third-party használathoz.
\end{description}
\begin{alertblock}{CSRF véd}
SameSite=Strict/Lax megakadályozza cross-site támadásokat.
\end{alertblock}
\end{frame}
\begin{frame}[shrink=15]{Cookie vs localStorage vs sessionStorage}
\begin{tiny}
\begin{tabular}{|l|c|c|c|}
\hline
& \textbf{Cookie} & \textbf{localStorage} & \textbf{sessionStorage} \\
\hline
Kapacitás & 4KB & 5-10MB & 5-10MB \\
Lejárat & Beállítható & Nincs & Tab bezárás \\
HTTP-ben & Igen & Nem & Nem \\
XSS véd & HttpOnly & Nem & Nem \\
\hline
\end{tabular}
\end{tiny}
\begin{exampleblock}{Ajánlás}
\textbf{Érzékeny:} HttpOnly Cookie, \textbf{Publikus:} localStorage
\end{exampleblock}
\end{frame}
\begin{frame}[fragile,shrink=15]{Cookie olvasása Express-ben}
\begin{verbatim}
const cookieParser = require('cookie-parser');
app.use(cookieParser());
app.get('/profile', (req, res) => {
const sessionId = req.cookies.session;
res.json({ sessionId });
});
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=15]{Cookie törlése}
\begin{verbatim}
app.post('/logout', (req, res) => {
res.clearCookie('session');
res.json({ message: 'Logged out' });
});
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=15]{Signed Cookies}
\begin{block}{Integritás védelem}
HMAC aláírással ellátott cookie, megakadályozza manipulációt.
\end{block}
\begin{verbatim}
app.use(cookieParser('secret-key'));
app.get('/set', (req, res) => {
res.cookie('userId', '123', { signed: true });
res.send('OK');
});
app.get('/get', (req, res) => {
const id = req.signedCookies.userId;
res.json({ id });
});
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{XSS vs CSRF}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{XSS (Cross-Site Scripting)}
\begin{itemize}
\item JS injection támadás
\item Cookie lopás \texttt{document.cookie}
\item \textbf{Védelem:} HttpOnly cookie
\end{itemize}
\end{column}
\begin{column}{0.48\textwidth}
\textbf{CSRF (Cross-Site Request Forgery)}
\begin{itemize}
\item Hamis kérés küldés
\item Cookie auto-send kihasználása
\item \textbf{Védelem:} SameSite, CSRF token
\end{itemize}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile,shrink=20]{CSRF Token védelem}
\begin{verbatim}
const csrf = require('csurf');
app.use(csrf({ cookie: true }));
app.get('/form', (req, res) => {
res.render('form', { csrfToken: req.csrfToken() });
});
app.post('/submit', (req, res) => {
res.send('Valid!');
});
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{Cookie Security Best Practices}
\begin{enumerate}
\item \textbf{HttpOnly}: Érzékeny cookie-khoz mindig
\item \textbf{Secure}: Éles környezetben HTTPS-el
\item \textbf{SameSite}: Strict vagy Lax CSRF ellen
\item \textbf{Short expiration}: Session token-ekhez rövid lejárat
\item \textbf{Domain scope}: Csak szükséges domain-hez
\item \textbf{Signed cookies}: Integritás ellenőrzéshez
\end{enumerate}
\end{frame}
+153
View File
@@ -0,0 +1,153 @@
\section{Hash}
\begin{frame}{Mi az a hash?}
\begin{block}{Definíció}
Tetszőleges hosszúságú bemenetet rögzített méretű lenyomattá alakít.
\end{block}
\begin{itemize}
\item Egyirányű függvény (nem visszafejthető)
\item Gyorsan számolható
\item Kis változás teljesen más hasht eredményez
\end{itemize}
\begin{alertblock}{Fontos}
Hash $\neq$ titkosítás: nem visszafejthető!
\end{alertblock}
\end{frame}
\begin{frame}{Hash tulajdonságok}
\begin{itemize}
\item \textbf{Deterministic}: azonos bemenet = azonos kimenet
\item \textbf{Preimage resistance}: nehéz visszafejteni
\item \textbf{Second preimage}: nehéz másik bemenetet találni
\item \textbf{Collision resistance}: nehéz két különböző bemenetet találni azonos hash-sel
\end{itemize}
\begin{exampleblock}{Példa}
\texttt{hash("jelszo") = 5f4dcc3b5aa765d61d8327deb882cf99}
\end{exampleblock}
\end{frame}
\begin{frame}{Gyenge vs. erős hash}
\begin{columns}
\begin{column}{0.48\textwidth}
\begin{block}{Gyenge hash}
\begin{itemize}
\item MD5, SHA1 (elavult)
\item Gyors → brute force könnyebb
\item Ütközések ismertek
\end{itemize}
\end{block}
\end{column}
\begin{column}{0.48\textwidth}
\begin{block}{Erős hash}
\begin{itemize}
\item bcrypt, Argon2, scrypt
\item Lassú, konfigurálható
\item Salt + work factor támogatás
\end{itemize}
\end{block}
\end{column}
\end{columns}
\vspace{0.4cm}
\begin{alertblock}{Jelszavakhoz}
Soha ne használj általános hash-t (MD5, SHA1) jelszavak tárolásához!
\end{alertblock}
\end{frame}
\begin{frame}{Salt és Pepper}
\begin{block}{Miért fontos?}
\textbf{Salt:} véletlen érték, amit a jelszóhoz adunk hash előtt.
\end{block}
\begin{itemize}
\item Védelem rainbow table ellen
\item Minden jelszónál egyedi salt
\item Salt-et tárolhatjuk adatbázisban
\end{itemize}
\begin{exampleblock}{Pepper}
Közös titkos kulcs, szerver konfigban tárolva.
\end{exampleblock}
\end{frame}
\begin{frame}{Password hashing algoritmusok}
\begin{itemize}
\item \textbf{bcrypt}
\begin{itemize}
\item Beépített salt és work factor
\end{itemize}
\item \textbf{scrypt}
\begin{itemize}
\item Memória-igényes → GPU támadások ellen jobb
\end{itemize}
\item \textbf{Argon2}
\begin{itemize}
\item Modern szabvány (PHC winner)
\item Paraméterezhető (time, memory, parallelism)
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}[fragile,shrink=10]{bcrypt használat (Node.js)}
\begin{exampleblock}{Hash készítés}
\tiny
\begin{verbatim}
const bcrypt = require('bcrypt');
const saltRounds = 12;
const hashPassword = async (password) => {
const salt = await bcrypt.genSalt(saltRounds);
return bcrypt.hash(password, salt);
};
\end{verbatim}
\end{exampleblock}
\begin{exampleblock}{Ellenőrzés}
\tiny
\begin{verbatim}
const isValid = await bcrypt.compare(password, storedHash);
\end{verbatim}
\end{exampleblock}
\end{frame}
\begin{frame}{Hash-elés felhasználása}
\begin{itemize}
\item Jelszó tárolás
\item Fájl integritás ellenőrzés
\item Digitális aláírások
\item Cache kulcsok
\end{itemize}
\begin{alertblock}{Megjegyzés}
Authentikációban: jelszó soha ne legyen visszaolvasható.
\end{alertblock}
\end{frame}
\begin{frame}{Hash Best Practices}
\begin{itemize}
\item Jelszhoz \textbf{bcrypt/Argon2/scrypt}
\item Egyedi salt minden jelszóhoz
\item Work factor beállítása (pl. bcrypt 10-12)
\item Soha ne plain text
\item Rate limiting + lockout
\end{itemize}
\end{frame}
\begin{frame}{Összefoglalás - Hash}
\begin{itemize}
\item Hash = egyirányú lenyomat
\item Jelszavakhoz speciális algoritmus kell
\item Salt és pepper növeli a biztonságot
\item Argon2 a legajánlottabb modern választás
\item Hash nem titkosítás!
\end{itemize}
\vspace{0.5cm}
\end{frame}
+194
View File
@@ -0,0 +1,194 @@
\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}
+205
View File
@@ -0,0 +1,205 @@
\section{Middleware}
\begin{frame}[shrink=15]{Mi az a middleware?}
\begin{block}{Definíció}
Függvény HTTP kérés-válasz között, hozzáfér \texttt{req}, \texttt{res}, \texttt{next}-hez.
\end{block}
\begin{itemize}
\item Láncolható
\item Kérés előfeldolgozás, válasz utófeldolgozás
\item Kérés megszakítható
\end{itemize}
\end{frame}
\begin{frame}[shrink=15]{Middleware működése}
\begin{center}
\begin{tikzpicture}[node distance=1.4cm, auto]
\node (browser) [rectangle, draw, text width=1.5cm, text centered] {Browser};
\node (mw1) [rectangle, draw, right of=browser, xshift=1cm, text width=2cm, text centered] {MW 1\\Logger};
\node (mw2) [rectangle, draw, right of=mw1, xshift=1.5cm, text width=2cm, text centered] {MW 2\\Auth};
\node (route) [rectangle, draw, right of=mw2, xshift=1.5cm, text width=1.5cm, text centered] {Route};
\draw[->, thick] (browser) -- node[above] {Req} (mw1);
\draw[->, thick] (mw1) -- node[above] {\tiny next()} (mw2);
\draw[->, thick] (mw2) -- node[above] {\tiny next()} (route);
\draw[->, thick, dashed] (route) -- node[below] {Res} (browser);
\end{tikzpicture}
\end{center}
\begin{alertblock}{Fontos}
\texttt{next()} nélkül kérés megáll!
\end{alertblock}
\end{frame}
\begin{frame}[shrink=15]{Middleware típusok}
\begin{enumerate}
\item \textbf{Application-level}: \texttt{app.use()}
\item \textbf{Router-level}: \texttt{router.use()}
\item \textbf{Error-handling}: \texttt{(err, req, res, next)}
\item \textbf{Built-in}: \texttt{express.json()}, \texttt{express.static()}
\item \textbf{Third-party}: \texttt{cors}, \texttt{helmet}, \texttt{morgan}
\end{enumerate}
\end{frame}
\begin{frame}[fragile,shrink=20]{Logger middleware}
\begin{verbatim}
const logger = (req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
};
app.use(logger);
app.get('/', (req, res) => {
res.json({ msg: 'Hello' });
});
// Kimenet:
// [2026-02-24T10:30:15.000Z] GET /
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{Request timing middleware}
\begin{verbatim}
const timer = (req, res, next) => {
req.startTime = Date.now();
res.on('finish', () => {
const duration = Date.now() - req.startTime;
console.log(`${req.method} ${req.url} - ${duration}ms`);
});
next();
};
app.use(timer);
// GET /api/users - 145ms
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{Validation middleware}
\begin{verbatim}
const validateEmail = (req, res, next) => {
const { email } = req.body;
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!email || !re.test(email)) {
return res.status(400).json({ error: 'Invalid email' });
}
next();
};
app.post('/register', validateEmail, (req, res) => {
res.json({ success: true });
});
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{Auth middleware}
\begin{verbatim}
const auth = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Token required' });
}
try {
const decoded = jwt.verify(token, SECRET);
req.user = decoded;
next();
} catch (err) {
res.status(403).json({ error: 'Invalid token' });
}
};
app.get('/protected', auth, (req, res) => {
res.json({ user: req.user });
});
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{Role-based middleware}
\begin{verbatim}
const requireRole = (role) => {
return (req, res, next) => {
if (req.user.role !== role) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
};
app.delete('/user/:id', auth, requireRole('admin'), (req, res) => {
res.json({ deleted: true });
});
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{Error handling middleware}
\begin{verbatim}
// Mindig utolsóként!
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: err.message || 'Internal Server Error'
});
});
// Használat
app.get('/error', (req, res, next) => {
const err = new Error('Something broke!');
err.status = 500;
next(err);
});
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{CORS middleware}
\begin{verbatim}
const cors = require('cors');
// Minden origin engedélyezése
app.use(cors());
// Specifikus beállítás
app.use(cors({
origin: 'https://frontend.com',
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE']
}));
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{Built-in middleware}
\begin{itemize}
\item \texttt{express.json()}: JSON body parsing
\item \texttt{express.urlencoded()}: URL-encoded body parsing
\item \texttt{express.static()}: Static fájlok kiszolgálása
\end{itemize}
\begin{exampleblock}{Használat}
\texttt{app.use(express.json());}\\
\texttt{app.use(express.static('public'));}
\end{exampleblock}
\end{frame}
\begin{frame}[shrink=15]{Third-party middleware}
\begin{description}
\item[helmet] HTTP security headers
\item[morgan] HTTP request logger
\item[compression] Response compression (gzip)
\item[cookie-parser] Cookie parsing
\item[express-session] Session kezelés
\item[passport] Authentication
\end{description}
\end{frame}
\begin{frame}[shrink=15]{Middleware best practices}
\begin{enumerate}
\item Mindig hívd meg \texttt{next()}-et (vagy küldjél választ)
\item Error middleware utolsóként
\item Sorrendiség számít!
\item Global middleware-ek előre (\texttt{cors}, \texttt{helmet})
\item Route-specifikus middleware-ek közvetlenül route-hoz
\item Async middleware-eknél használj try-catch-et
\end{enumerate}
\end{frame}
+154
View File
@@ -0,0 +1,154 @@
\section{OAuth 2.0}
\begin{frame}[shrink=15]{Mi az OAuth 2.0?}
\begin{block}{Definíció}
Autorizációs protokoll - korlátozott hozzáférés jelszó megosztása nélkül.
\end{block}
\begin{itemize}
\item RFC 6749 (2012)
\item Google, Facebook, GitHub használja
\item Példa: App hozzáfér Google Drive-hoz jelszó nélkül
\end{itemize}
\end{frame}
\begin{frame}[shrink=15]{OAuth 2.0 szerepkörök}
\begin{enumerate}
\item \textbf{Resource Owner}: Felhasználó (birtokolja erőforrást)
\item \textbf{Client}: Alkalmazás (hozzáférést kér)
\item \textbf{Authorization Server}: Token kiállító
\item \textbf{Resource Server}: Védett erőforrás tároló
\end{enumerate}
\end{frame}
\begin{frame}[shrink=15]{OAuth 2.0 Flow}
\begin{center}
\begin{tikzpicture}[node distance=1.8cm, auto]
\node (ro) [rectangle, draw, text width=1.8cm, text centered] {Resource Owner};
\node (client) [rectangle, draw, below of=ro, text width=1.8cm, text centered] {Client};
\node (auth) [rectangle, draw, right of=client, xshift=2.5cm, text width=2cm, text centered] {Auth Server};
\node (res) [rectangle, draw, below of=auth, text width=2cm, text centered] {Resource Server};
\draw[->, thick] (client) -- node[left] {1. Kérés} (ro);
\draw[->, thick] (ro) -- node[above] {2. OK} (auth);
\draw[->, thick] (auth) -- node[right] {3. Token} (client);
\draw[->, thick] (client) -- node[above] {4. API} (res);
\draw[->, thick] (res) -- node[below] {5. Data} (client);
\end{tikzpicture}
\end{center}
\end{frame}
\begin{frame}[shrink=15]{Grant Types}
\begin{enumerate}
\item \textbf{Authorization Code}: Szerver app, legbiztonságosabb
\item \textbf{Implicit}: \textcolor{red}{Elavult!}
\item \textbf{Resource Owner Password}: Közvetlen jelszó, megbízható app
\item \textbf{Client Credentials}: Machine-to-machine
\item \textbf{PKCE}: Modern mobil/SPA
\end{enumerate}
\end{frame}
\begin{frame}[shrink=20]{Authorization Code Flow lépések}
\begin{enumerate}
\item Kliens átirányít: \texttt{/authorize?client\_id=\&redirect\_uri=\&scope=}
\item Felhasználó bejelentkezik és hozzájárul
\item Auth Server visszairányít: \texttt{redirect\_uri?code=AUTH\_CODE}
\item Kliens kicseréli code-ot: POST \texttt{/token}
\item Auth Server ad access token-t (+ refresh)
\item Kliens használja tokent: \texttt{Authorization: Bearer <token>}
\end{enumerate}
\end{frame}
\begin{frame}[fragile,shrink=20]{Authorization Code - Auth kérés}
\begin{verbatim}
GET /oauth/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https://app.com/callback&
scope=read write&
state=xyz123
\end{verbatim}
\begin{verbatim}
// Callback
GET https://app.com/callback?
code=AUTH_CODE&
state=xyz123
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{Authorization Code - Token csere}
\begin{verbatim}
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=https://app.com/callback&
client_id=YOUR_ID&
client_secret=YOUR_SECRET
\end{verbatim}
\begin{verbatim}
// Válasz
{
"access_token": "eyJ...",
"expires_in": 3600,
"refresh_token": "tGzv..."
}
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{PKCE (Proof Key for Code Exchange)}
\begin{block}{Miért?}
Authorization Code Flow biztonságosabbá tétele mobil/SPA app-okhoz.
\end{block}
\begin{enumerate}
\item Kliens generál \texttt{code\_verifier} (random string)
\item Hash: \texttt{code\_challenge = SHA256(code\_verifier)}
\item Auth kéréshez csatol: \texttt{code\_challenge}
\item Token kérésnél küldi: \texttt{code\_verifier}
\item Server validálja: \texttt{SHA256(verifier) == challenge}
\end{enumerate}
\begin{alertblock}{Védelem}
Megakadályozza authorization code ellopását.
\end{alertblock}
\end{frame}
\begin{frame}[shrink=15]{Scope és Permission}
\begin{block}{Scope}
Jogosultság amit app kér. Példa: \texttt{read:user write:repo}
\end{block}
\begin{itemize}
\item Felhasználó látja mit kér az app
\item Csak kért scope-okat kapja meg
\item Token tartalmazza scope-okat
\end{itemize}
\begin{exampleblock}{GitHub példa}
\texttt{repo, user, gist, notifications}
\end{exampleblock}
\end{frame}
\begin{frame}[fragile,shrink=20]{Access Token használata}
\begin{verbatim}
// API kérés Bearer token-nel
GET /api/user/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
\end{verbatim}
\begin{verbatim}
// Express validálás
app.get('/api/user', (req, res) => {
const token = req.headers.authorization?.split(' ')[1];
// Token validálás...
res.json({ user: userData });
});
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{OAuth 2.0 Security}
\begin{enumerate}
\item \textbf{HTTPS kötelező}: Minden kommunikáció
\item \textbf{State parameter}: CSRF védelem
\item \textbf{Redirect URI validation}: Előre regisztrált URI
\item \textbf{Short token lifetime}: Access token max 1 óra
\item \textbf{PKCE használata}: Mobil/SPA app-okhoz
\item \textbf{Scope limitation}: Csak szükséges jogok
\end{enumerate}
\end{frame}
+233
View File
@@ -0,0 +1,233 @@
\section{Service Layer}
\begin{frame}[shrink=15]{Mi az a Service Layer?}
\begin{block}{Definíció}
Tervezési minta - üzleti logika elválasztása controller-ektől és data layer-től.
\end{block}
\begin{itemize}
\item Separation of Concerns
\item Reusability (újrafelhasználható logika)
\item Testability (könnyebb tesztelés)
\item Maintainability
\end{itemize}
\begin{exampleblock}{Architektúra}
Controller → Service → Repository → Database
\end{exampleblock}
\end{frame}
\begin{frame}[shrink=15]{Háromrétegű architektúra}
\begin{columns}
\begin{column}{0.32\textwidth}
\begin{block}{Presentation}
\begin{small}
Controllers, Routes\\
HTTP req/res\\
Validáció
\end{small}
\end{block}
\end{column}
\begin{column}{0.32\textwidth}
\begin{block}{Business Logic}
\begin{small}
\textbf{Services}\\
Üzleti szabályok\\
Orchestration
\end{small}
\end{block}
\end{column}
\begin{column}{0.32\textwidth}
\begin{block}{Data Access}
\begin{small}
Repository\\
ORM\\
Database
\end{small}
\end{block}
\end{column}
\end{columns}
\begin{alertblock}{Fontos}
Controller \textbf{NEM} tartalmaz üzleti logikát, csak delegál!
\end{alertblock}
\end{frame}
\begin{frame}[shrink=15]{Service Layer előnyei}
\begin{enumerate}
\item \textbf{Separation}: Tiszta felelősségi körök
\item \textbf{Reusability}: Több controller használhatja
\item \textbf{Testability}: Könnyen unit tesztelhető
\item \textbf{Maintainability}: Változások izoláltak
\end{enumerate}
\end{frame}
\begin{frame}[fragile,shrink=20]{AuthService - Interface}
\begin{verbatim}
class AuthService {
async register(userData) { ... }
async login(email, password) { ... }
async logout(userId) { ... }
async refreshToken(refreshToken) { ... }
async verifyToken(token) { ... }
async resetPassword(email) { ... }
}
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{AuthService - Register}
\begin{verbatim}
class AuthService {
async register(userData) {
const exists = await this.userRepo.findByEmail(userData.email);
if (exists) throw new Error('User exists');
const hashed = await bcrypt.hash(userData.password, 10);
const user = await this.userRepo.create({
...userData,
password: hashed
});
return { id: user.id, email: user.email };
}
}
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{AuthService - Login}
\begin{verbatim}
async login(email, password) {
const user = await this.userRepo.findByEmail(email);
if (!user) throw new Error('Invalid credentials');
const valid = await bcrypt.compare(password, user.password);
if (!valid) throw new Error('Invalid credentials');
const token = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
return { token, user: { id: user.id, email: user.email } };
}
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{Controller használja Service-t}
\begin{verbatim}
class AuthController {
constructor(authService) {
this.authService = authService;
}
async register(req, res) {
try {
const user = await this.authService.register(req.body);
res.status(201).json(user);
} catch (err) {
res.status(400).json({ error: err.message });
}
}
async login(req, res) {
try {
const result = await this.authService.login(req.body.email, req.body.password);
res.json(result);
} catch (err) {
res.status(401).json({ error: err.message });
}
}
}
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{UserService példa}
\begin{verbatim}
class UserService {
constructor(userRepo) {
this.userRepo = userRepo;
}
async getById(id) {
const user = await this.userRepo.findById(id);
if (!user) throw new Error('User not found');
return user;
}
async update(id, data) {
const user = await this.getById(id);
return await this.userRepo.update(id, data);
}
async delete(id) {
await this.getById(id);
return await this.userRepo.delete(id);
}
}
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=20]{Dependency Injection}
\begin{verbatim}
// Repository
class UserRepository {
async findById(id) { /* DB query */ }
async create(data) { /* DB insert */ }
}
// Service
class UserService {
constructor(userRepository) {
this.userRepo = userRepository;
}
// ...
}
// DI container
const userRepo = new UserRepository();
const userService = new UserService(userRepo);
const userController = new UserController(userService);
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{Service Layer Best Practices}
\begin{enumerate}
\item Service-ek ne dependáljanak controller-ektől
\item Egy service = egy domain (User, Auth, Order)
\item Dependency Injection használata
\item Service-ek ne ismerjék HTTP-t (req, res)
\item Hibakezelés service-ben (throw Error)
\item Transaction logika service-ben
\item Async/await következetes használata
\end{enumerate}
\end{frame}
\begin{frame}[fragile,shrink=20]{Transaction példa Service-ben}
\begin{verbatim}
class OrderService {
async createOrder(userId, items) {
const transaction = await db.transaction();
try {
const order = await this.orderRepo.create({ userId }, transaction);
for (const item of items) {
await this.orderItemRepo.create({ orderId: order.id, ...item }, transaction);
}
await transaction.commit();
return order;
} catch (err) {
await transaction.rollback();
throw err;
}
}
}
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{Testing Service Layer}
\begin{itemize}
\item Service-ek unit tesztelése mock repository-val
\item Ne kelljen DB a unit teszthez
\item Integration teszt valódi DB-vel
\end{itemize}
\end{frame}
+280
View File
@@ -0,0 +1,280 @@
\section{Session}
\begin{frame}{Mi az a session?}
\begin{block}{Definíció}
Szerver-oldali állapot, amely felhasználói adatokat tárol bejelentkezés után.
\end{block}
\begin{itemize}
\item \textbf{Stateful} megközelítés
\item Kliens csak \textbf{session ID}-t tárol (cookie)
\item Tartalom a szerveren (memória/DB/Redis)
\end{itemize}
\begin{alertblock}{Fontos}
Session auth nem token-alapú, szerver kezeli az állapotot.
\end{alertblock}
\end{frame}
\begin{frame}{Session vs Token}
\begin{columns}
\begin{column}{0.48\textwidth}
\begin{block}{Session}
\begin{itemize}
\item Szerver tárolja
\item Cookie-ban ID
\item Könnyű visszavonás
\item Nehezebb skálázás
\end{itemize}
\end{block}
\end{column}
\begin{column}{0.48\textwidth}
\begin{block}{Token (JWT)}
\begin{itemize}
\item Stateless
\item Kliens tárolja
\item Nehezebb visszavonás
\item Könnyebb skálázás
\end{itemize}
\end{block}
\end{column}
\end{columns}
\begin{center}
Session $\leftrightarrow$ JWT: kontroll vs skálázhatóság
\end{center}
\end{frame}
\begin{frame}{Session folyamat}
\begin{enumerate}
\item Bejelentkezés (username + password)
\item Adatok ellenőrzése
\item \textbf{Session} létrehozás
\item Session ID cookie-ban
\item Kliens csatolja minden kéréshez
\item Szerver ID alapján azonosít
\end{enumerate}
\begin{alertblock}{Megjegyzés}
HTTPS kötelező, különben session ID elliopható!
\end{alertblock}
\end{frame}
\begin{frame}{Session tárolás}
\begin{block}{Hol tároljuk?}
Session adatokat szerveren, több lehetőség:
\end{block}
\begin{itemize}
\item \textbf{In-memory} - gyors, nem skálázható
\item \textbf{Redis} - gyors, skálázható, TTL
\item \textbf{DB} - tartós, lassabb
\item \textbf{Distributed cache} - nagy rendszerekhez
\end{itemize}
\begin{alertblock}{Best Practice}
Élesben ne használj in-memory store-t!
\end{alertblock}
\end{frame}
\begin{frame}[fragile,shrink=15]{Redis Session Store - Telepítés}
\begin{block}{Redis előnyei session tároláshoz}
Gyors, skálázható, beépített TTL (Time To Live) támogatás
\end{block}
\begin{verbatim}
npm install express-session connect-redis redis
// Redis kliens és session store
const session = require('express-session');
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');
const redisClient = createClient({
host: 'localhost',
port: 6379
});
redisClient.connect();
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=15]{Redis Session - Konfiguráció}
\begin{verbatim}
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: true, // HTTPS
maxAge: 1000 * 60 * 60 * 24 // 1 nap
}
}));
app.post('/login', async (req, res) => {
const user = await authenticateUser(req.body);
req.session.userId = user.id;
req.session.role = user.role;
res.json({ success: true });
});
\end{verbatim}
\end{frame}
\begin{frame}[fragile,shrink=15]{Redis Session - Műveletek}
\begin{verbatim}
// Session olvasása
app.get('/profile', (req, res) => {
if (!req.session.userId) {
return res.status(401).json({ error: 'Not logged in' });
}
res.json({ userId: req.session.userId });
});
// Session módosítása
app.post('/settings', (req, res) => {
req.session.theme = req.body.theme;
res.json({ success: true });
});
// Session törlése (logout)
app.post('/logout', (req, res) => {
req.session.destroy((err) => {
if (err) return res.status(500).send('Error');
res.clearCookie('connect.sid');
res.json({ message: 'Logged out' });
});
});
\end{verbatim}
\end{frame}
\begin{frame}[shrink=15]{Redis Session előnyei}
\begin{columns}
\begin{column}{0.48\textwidth}
\textbf{Előnyök:}
\begin{itemize}
\item Villámgyors (in-memory)
\item Automatikus TTL támogatás
\item Skálázható (cluster mode)
\item Persistence opcionális
\item Pub/Sub támogatás
\end{itemize}
\end{column}
\begin{column}{0.48\textwidth}
\textbf{Használati esetek:}
\begin{itemize}
\item Session store
\item Rate limiting
\item Real-time analytics
\item Cache layer
\item Message queue
\end{itemize}
\end{column}
\end{columns}
\end{frame}
\begin{frame}{Session élettartam}
\begin{block}{Session Timeout}
Session-ök lejárnak idő vagy inaktivitás után.
\end{block}
\begin{itemize}
\item \textbf{Absolute:} fix lejárat (pl. 24h)
\item \textbf{Idle:} aktivitás hiánya
\item \textbf{Sliding:} aktivitás meghosszabbítja
\end{itemize}
\begin{exampleblock}{Példa}
Online bank: 5 perc inaktivitás $\to$ kiléptetés.
\end{exampleblock}
\end{frame}
\begin{frame}[fragile,shrink=10]{Express session példa}
\begin{exampleblock}{express-session használata}
\tiny
\begin{verbatim}
const session = require('express-session');
app.use(session({
secret: 'super-secret-key',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: true,
maxAge: 1000 * 60 * 60 // 1 óra
}
}));
app.post('/login', (req, res) => {
req.session.userId = user.id;
res.json({ message: 'Logged in' });
});
\end{verbatim}
\end{exampleblock}
\end{frame}
\begin{frame}{Cookie biztonság}
\begin{block}{Mitől biztonságos?}
Session ID cookie biztonságos beállításokkal.
\end{block}
\begin{itemize}
\item \textbf{HttpOnly}: JS nem fér hozzá
\item \textbf{Secure}: csak HTTPS
\item \textbf{SameSite}: CSRF védelem
\item \textbf{Rotálás}: ID frissítés (fixation ellen)
\end{itemize}
\begin{alertblock}{Session Fixation}
Támadó előre beállított ID-t "ráerőltet" a felhasználóra.
\end{alertblock}
\end{frame}
\begin{frame}[shrink=5]{Session alapú autorizáció}
\begin{block}{Jogosultságok session-ben}
A session tárolhatja a felhasználó szerepköreit és jogosultságait.
\end{block}
\begin{itemize}
\item \textbf{Példa:} \texttt{req.session.role = 'Admin'}
\item Middleware ellenőrzi a role-t
\item Ha nincs jogosultság: \texttt{403 Forbidden}
\end{itemize}
\vspace{0.4cm}
\begin{exampleblock}{Minta ellenőrzés}
\texttt{if (req.session.role !== 'Admin') return res.status(403);}
\end{exampleblock}
\end{frame}
\begin{frame}{Session Best Practices}
\begin{itemize}
\item HTTPS használata mindenhol
\item HttpOnly + Secure + SameSite cookie beállítások
\item Session store: Redis vagy DB
\item Rövid idle timeout érzékeny rendszereknél
\item Session ID rotálás bejelentkezéskor
\item Rate limiting és brute force védelem
\end{itemize}
\vspace{0.5cm}
\end{frame}
\begin{frame}{Összefoglalás - Session}
\begin{itemize}
\item Session = szerver-oldali állapot (cookie csak ID)
\item Kényelmes, de skálázásnál kihívás
\item Cookie biztonsági beállítások kritikusak
\item \textbf{Redis a leggyakoribb session store} - gyors, skálázható
\item Timeout és rotáció védelem session támadások ellen
\item Redis TTL automatikus session lejárathoz
\end{itemize}
\begin{exampleblock}{Produkciós környezet}
Redis cluster + persistence + backup = megbízható session kezelés
\end{exampleblock}
\end{frame}