Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds

Strategie uwierzytelniania

W poprzednich częściach omówiliśmy podstawy uwierzytelniania oraz zaimplementowaliśmy prostą autoryzację z użyciem JWT. Teraz zagłębimy się w różne strategie uwierzytelniania, które możesz zastosować w swoich aplikacjach.

Uwierzytelnianie oparte na tokenach vs. sesyjne

Dwa główne podejścia do uwierzytelniania to:

1. Uwierzytelnianie sesyjne (Session-based Authentication)

W tym podejściu serwer utrzymuje stan sesji dla każdego zalogowanego użytkownika:

1// Przykład konfiguracji sesji w Express
2import express from 'express';
3import session from 'express-session';
4
5const app = express();
6
7app.use(session({
8  secret: 'tajny-klucz-sesji',
9  resave: false,
10  saveUninitialized: false,
11  cookie: { secure: true, maxAge: 3600000 } // 1 godzina
12}));
13
14app.post('/login', (req, res) => {
15  // Po pomyślnym uwierzytelnieniu
16  req.session.authenticated = true;
17  req.session.userId = user.id;
18  res.send({ success: true });
19});
20
21app.get('/protected', (req, res) => {
22  if (req.session.authenticated) {
23    // Użytkownik ma ważną sesję
24    res.send('Dane chronione');
25  } else {
26    res.status(401).send('Brak dostępu');
27  }
28});

Zalety:

  • Łatwość implementacji i utrzymania
  • Możliwość natychmiastowego unieważnienia sesji
  • Nie wymaga dodatkowego przetwarzania po stronie klienta

Wady:

  • Obciążenie serwera (przechowywanie stanu)
  • Problemy ze skalowalnością w architekturze rozproszonej
  • Trudności w implementacji dla aplikacji mobilnych

2. Uwierzytelnianie oparte na tokenach (Token-based Authentication)

W tym podejściu serwer generuje token, który klient przechowuje i przesyła z każdym żądaniem:

1// Przykład implementacji JWT w Express
2import express from 'express';
3import jwt from 'jsonwebtoken';
4
5const app = express();
6const JWT_SECRET = 'tajny-klucz-jwt';
7
8app.post('/login', (req, res) => {
9  // Po pomyślnym uwierzytelnieniu
10  const token = jwt.sign(
11    { userId: user.id, email: user.email },
12    JWT_SECRET,
13    { expiresIn: '1h' }
14  );
15  
16  res.send({ token });
17});
18
19// Middleware weryfikujący token
20const verifyToken = (req, res, next) => {
21  const token = req.headers.authorization?.split(' ')[1];
22  
23  if (!token) {
24    return res.status(401).send('Brak tokenu autoryzacji');
25  }
26  
27  try {
28    const decoded = jwt.verify(token, JWT_SECRET);
29    req.user = decoded;
30    next();
31  } catch (error) {
32    return res.status(401).send('Nieprawidłowy token');
33  }
34};
35
36app.get('/protected', verifyToken, (req, res) => {
37  res.send('Dane chronione');
38});

Zalety:

  • Bezstanowość (stateless) - łatwiejsze skalowanie
  • Działa dobrze w aplikacjach mobilnych i SPA
  • Możliwość przechowywania dodatkowych informacji w tokenie

Wady:

  • Trudniejsze unieważnienie tokenu przed wygaśnięciem
  • Podatność na kradzież (jeśli nie zastosowano odpowiednich zabezpieczeń)
  • Większe tokeny mogą zwiększyć obciążenie sieci

OAuth 2.0 i uwierzytelnianie społecznościowe

OAuth 2.0 to standard protokołu autoryzacji, który umożliwia aplikacjom dostęp do zasobów użytkownika na innym serwerze bez konieczności dzielenia się danymi uwierzytelniającymi.

Implementacja uwierzytelniania przez Google

1// Implementacja OAuth z Google w Express i Passport
2import express from 'express';
3import passport from 'passport';
4import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
5
6const app = express();
7
8// Konfiguracja Passport
9passport.use(new GoogleStrategy({
10    clientID: 'TWOJE_GOOGLE_CLIENT_ID',
11    clientSecret: 'TWOJE_GOOGLE_CLIENT_SECRET',
12    callbackURL: 'http://localhost:3000/auth/google/callback'
13  },
14  function(accessToken, refreshToken, profile, done) {
15    // Znajdź lub utwórz użytkownika w bazie danych
16    User.findOrCreate({ googleId: profile.id }, function (err, user) {
17      return done(err, user);
18    });
19  }
20));
21
22// Trasy uwierzytelniania
23app.get('/auth/google',
24  passport.authenticate('google', { scope: ['profile', 'email'] }));
25
26app.get('/auth/google/callback', 
27  passport.authenticate('google', { failureRedirect: '/login' }),
28  (req, res) => {
29    // Przekierowanie po pomyślnym uwierzytelnieniu
30    res.redirect('/dashboard');
31  }
32);

Uwierzytelnianie wieloskładnikowe (MFA)

Uwierzytelnianie wieloskładnikowe (Multi-Factor Authentication) zwiększa bezpieczeństwo, wymagając od użytkownika dostarczenia dwóch lub więcej dowodów tożsamości.

Przykład implementacji MFA z użyciem TOTP (Time-based One-Time Password)

1// Implementacja 2FA z TOTP w Node.js
2import express from 'express';
3import speakeasy from 'speakeasy';
4import QRCode from 'qrcode';
5
6const app = express();
7app.use(express.json());
8
9// Generowanie tajnego klucza dla użytkownika
10app.post('/generate-2fa', (req, res) => {
11  const secret = speakeasy.generateSecret({
12    name: 'MojaAplikacja:' + req.user.email
13  });
14  
15  // Zapisz secret.base32 w bazie danych dla tego użytkownika
16  saveUserSecret(req.user.id, secret.base32);
17  
18  // Generuj kod QR
19  QRCode.toDataURL(secret.otpauth_url, (err, imageUrl) => {
20    if (err) {
21      return res.status(500).send('Błąd generowania kodu QR');
22    }
23    
24    res.json({
25      secret: secret.base32,
26      qrCode: imageUrl
27    });
28  });
29});
30
31// Weryfikacja kodu jednorazowego
32app.post('/verify-2fa', (req, res) => {
33  const { token } = req.body;
34  
35  // Pobierz secret użytkownika z bazy danych
36  const userSecret = getUserSecret(req.user.id);
37  
38  const verified = speakeasy.totp.verify({
39    secret: userSecret,
40    encoding: 'base32',
41    token: token
42  });
43  
44  if (verified) {
45    // Włącz 2FA dla użytkownika w bazie danych
46    enableUser2FA(req.user.id);
47    res.json({ success: true });
48  } else {
49    res.status(400).json({ success: false, message: 'Nieprawidłowy kod' });
50  }
51});

Single Sign-On (SSO)

Single Sign-On to proces uwierzytelniania, który pozwala użytkownikowi na dostęp do wielu aplikacji po jednorazowym zalogowaniu.

Implementacja SSO z SAML

1// Przykład implementacji SAML SSO w Express
2import express from 'express';
3import passport from 'passport';
4import { Strategy as SAMLStrategy } from 'passport-saml';
5
6const app = express();
7
8passport.use(new SAMLStrategy({
9  path: '/login/callback',
10  entryPoint: 'https://sso.example.com/saml2/idp/SSOService.php',
11  issuer: 'moja-aplikacja',
12  cert: 'CERTYFIKAT_DOSTAWCY_TOŻSAMOŚCI'
13}, (profile, done) => {
14  // Znajdź lub utwórz użytkownika w bazie danych
15  return done(null, {
16    id: profile.nameID,
17    email: profile.email,
18    name: profile.displayName
19  });
20}));
21
22app.get('/login',
23  passport.authenticate('saml', { failureRedirect: '/login/fail' }),
24  (req, res) => res.redirect('/')
25);
26
27app.post('/login/callback',
28  passport.authenticate('saml', { failureRedirect: '/login/fail' }),
29  (req, res) => res.redirect('/')
30);

Najlepsze praktyki bezpieczeństwa uwierzytelniania

  1. Bezpieczne hasła

    • Wymagaj mocnych haseł (długość, złożoność)
    • Przechowuj wyłącznie zaszyfrowane hasła (używaj silnych algorytmów jak bcrypt)
    • Implementuj ograniczenia liczby prób logowania
  2. Zabezpieczenie tokenów

    • Przechowuj tokeny JWT bezpiecznie (HttpOnly cookies)
    • Używaj krótkiego czasu ważności tokenów
    • Implementuj rotację i unieważnianie tokenów
  3. Transport

    • Zawsze używaj HTTPS do przesyłania danych uwierzytelniających
    • Implementuj HSTS (HTTP Strict Transport Security)
    • Zabezpiecz ciasteczka flagami Secure i SameSite
  4. Ogólne zasady

    • Regularnie przeprowadzaj audyty bezpieczeństwa
    • Implementuj logowanie i monitorowanie aktywności
    • Zawsze stosuj zasadę najmniejszych uprawnień (principle of least privilege)

Podsumowanie

Wybór odpowiedniej strategii uwierzytelniania zależy od wielu czynników, takich jak:

  • Wymagania bezpieczeństwa aplikacji
  • Docelowa grupa użytkowników
  • Rodzaj aplikacji (mobilna, webowa, hybrydowa)
  • Skalowalność i wydajność

Pamiętaj, że bezpieczeństwo uwierzytelniania to proces ciągły, wymagający regularnej aktualizacji i dostosowywania się do nowych zagrożeń i standardów bezpieczeństwa.

W następnych lekcjach przejdziemy do implementacji zaawansowanych mechanizmów autoryzacji i zarządzania uprawnieniami użytkowników.

Ir a CodeWorlds