Testy penetracyjne
Naucz się technik ethical hackingu
Twoja platforma e-commerce właśnie nie przeszła audytu bezpieczeństwa. Raport ujawnia podatności SQL injection, wystawione klucze API, słabe uwierzytelnianie, podatności CSRF i wrażliwe dane w logach. Z terminem zgodności PCI zbliżającym się i danymi klientów w niebezpieczeństwie, musisz natychmiast zaimplementować kompleksowe poprawki bezpieczeństwa.
Po ukończeniu tej lekcji opanujesz:
Zabezpiecz aplikację przez:
Zacznij od pełnego audytu bezpieczeństwa:
@src"Przeprowadź kompleksowy audyt bezpieczeństwa:- Sprawdź podatności SQL injection- Znajdź wystawione sekrety i klucze API- Zidentyfikuj słabości uwierzytelniania- Wykryj podatności CSRF- Znajdź wektory ataków XSS- Sprawdź niebezpieczne zależnościKategoryzuj według ważności i dostarcz poprawki"
"Przeanalizuj package.json i pliki lock pod kątem:- Znanych podatności w zależnościach- Przestarzałych pakietów z problemami bezpieczeństwa- Problemów zgodności licencji- Ryzyk łańcucha dostawStwórz plan aktualizacji z analizą breaking changes"
Przełącz się na tryb Agent:
@src"Przeanalizuj kod pod kątem anti-wzorców bezpieczeństwa:- Hardkodowane sekrety- Niebezpieczne regex (ReDoS)- Podatności path traversal- Ryzyko command injection- Niebezpieczna deserializacja- Brakująca walidacja wejściaWygeneruj raport bezpieczeństwa z przykładami"
Przykład raportu podatności:
export interface SecurityVulnerability { severity: 'critical' | 'high' | 'medium' | 'low'; type: string; file: string; line: number; description: string; impact: string; recommendation: string; example?: string;}
// Przykład ustaleń:const vulnerabilities: SecurityVulnerability[] = [ { severity: 'critical', type: 'SQL Injection', file: 'src/api/users.ts', line: 45, description: 'Wejście użytkownika bezpośrednio konkatenowane w zapytaniu SQL', impact: 'Atakujący może odczytać/zmodyfikować/usunąć całą bazę danych', recommendation: 'Użyj sparametryzowanych zapytań', example: ` // Podatny: const query = \`SELECT * FROM users WHERE id = \${userId}\`;
// Naprawiony: const query = 'SELECT * FROM users WHERE id = ?'; db.query(query, [userId]); ` }, { severity: 'high', type: 'Wystawiony sekret', file: 'src/config.ts', line: 12, description: 'Klucz API hardkodowany w źródle', impact: 'Atakujący może uzyskać dostęp do usług trzecich', recommendation: 'Użyj zmiennych środowiskowych', example: ` // Podatny: const API_KEY = 'sk_live_abcd1234';
// Naprawiony: const API_KEY = process.env.API_KEY; ` }];
"Implementuj bezpieczny system uwierzytelniania:- JWT z właściwym wygaśnięciem- Rotacja refresh tokenów- Uwierzytelnianie wieloskładnikowe- Rate limiting na logowanie- Mechanizm blokady konta- Bezpieczny przepływ resetowania hasłaPrzestrzegaj wytycznych OWASP"
Przykład bezpiecznej implementacji auth:
import bcrypt from 'bcrypt';import jwt from 'jsonwebtoken';import speakeasy from 'speakeasy';import { RateLimiter } from './rate-limiter';
export class SecureAuthService { private readonly saltRounds = 12; private readonly loginLimiter = new RateLimiter({ windowMs: 15 * 60 * 1000, // 15 minut max: 5, // 5 prób skipSuccessfulRequests: true });
async register(email: string, password: string) { // Waliduj siłę hasła this.validatePasswordStrength(password);
// Sprawdź skompromitowane hasła await this.checkPwnedPassword(password);
// Hashuj hasło z bcrypt const hashedPassword = await bcrypt.hash(password, this.saltRounds);
// Wygeneruj sekret 2FA const secret = speakeasy.generateSecret();
// Zapisz użytkownika z hashowanym hasłem const user = await db.user.create({ data: { email, password: hashedPassword, totpSecret: this.encrypt(secret.base32), isEmailVerified: false, createdAt: new Date() } });
// Wyślij email weryfikacyjny await this.sendVerificationEmail(user);
return { userId: user.id, qrCode: secret.otpauth_url }; }
async login(email: string, password: string, totpToken?: string, ip?: string) { // Sprawdź rate limit await this.loginLimiter.check(email, ip);
try { // Pobierz użytkownika z timing-safe porównaniem const user = await this.getUserByEmail(email);
if (!user || !(await bcrypt.compare(password, user.password))) { // Ten sam błąd dla obu przypadków (zapobiega enumeracji użytkowników) await this.loginLimiter.penalty(email, ip); throw new AuthError('Nieprawidłowe dane uwierzytelniające'); }
// Sprawdź status konta if (user.lockedUntil && user.lockedUntil > new Date()) { throw new AuthError('Konto tymczasowo zablokowane'); }
// Weryfikuj 2FA jeśli włączone if (user.totpSecret) { if (!totpToken) { throw new AuthError('Wymagany token 2FA'); }
const secret = this.decrypt(user.totpSecret); const verified = speakeasy.totp.verify({ secret, encoding: 'base32', token: totpToken, window: 2 });
if (!verified) { await this.loginLimiter.penalty(email, ip); throw new AuthError('Nieprawidłowy token 2FA'); } }
// Wygeneruj tokeny const { accessToken, refreshToken } = await this.generateTokens(user);
// Zaloguj udane logowanie await this.logSecurityEvent({ type: 'login_success', userId: user.id, ip, userAgent: req.headers['user-agent'] });
return { accessToken, refreshToken, expiresIn: 900 // 15 minut }; } catch (error) { // Zaloguj nieudaną próbę await this.logSecurityEvent({ type: 'login_failed', email, ip, reason: error.message });
throw error; } }
private async generateTokens(user: User) { const tokenId = crypto.randomUUID();
// Krótkotrwały access token const accessToken = jwt.sign( { sub: user.id, email: user.email, jti: tokenId, type: 'access' }, process.env.JWT_SECRET, { expiresIn: '15m', issuer: 'myapp.com', audience: 'myapp.com' } );
// Długotrwały refresh token z rotacją const refreshToken = jwt.sign( { sub: user.id, jti: crypto.randomUUID(), type: 'refresh', family: crypto.randomUUID() // Rodzina tokenów dla rotacji }, process.env.JWT_REFRESH_SECRET, { expiresIn: '30d' } );
// Zapisz refresh token (hashowany) await db.refreshToken.create({ data: { hashedToken: await this.hashToken(refreshToken), userId: user.id, family: tokenFamily, expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) } });
return { accessToken, refreshToken }; }}
"Stwórz kontrolę dostępu opartą na rolach (RBAC):- Zdefiniuj role i uprawnienia- Implementuj middleware do ochrony tras- Dodaj uprawnienia na poziomie zasobów- Stwórz narzędzia sprawdzania uprawnień- Implementuj kontrolę dostępu opartą na atrybutach- Dodaj logowanie audytu dla dostępu"
"Implementuj bezpieczne zarządzanie sesjami:- Bezpieczne przechowywanie sesji- Zapobieganie fiksacji sesji- Limity równoczesnych sesji- Obsługa timeout sesji- Śledzenie urządzeń- Wylogowanie ze wszystkich urządzeń"
@src/api"Dodaj walidację wejścia do wszystkich endpointów:- Walidacja treści żądania- Walidacja parametrów zapytania- Walidacja przesyłania plików- Walidacja nagłówków- Zapobieganie atakom injectionUżyj biblioteki walidacji schematów"
Przykład implementacji walidacji:
import { z } from 'zod';import DOMPurify from 'isomorphic-dompurify';import validator from 'validator';
// Niestandardowe walidatoryconst safeString = z.string().transform((val) => { // Usuń null bytes val = val.replace(/\0/g, '');
// Sanityzuj HTML val = DOMPurify.sanitize(val, { ALLOWED_TAGS: [] });
return val.trim();});
const email = z.string().email().refine( (val) => validator.isEmail(val, { allow_utf8_local_part: false, require_tld: true }), 'Nieprawidłowy format email');
const password = z.string() .min(12, 'Hasło musi mieć co najmniej 12 znaków') .refine( (val) => /[A-Z]/.test(val) && /[a-z]/.test(val) && /[0-9]/.test(val) && /[^A-Za-z0-9]/.test(val), 'Hasło musi zawierać wielką literę, małą literę, cyfrę i znak specjalny' );
// Schemat rejestracji użytkownikaexport const userRegistrationSchema = z.object({ email, password, name: safeString.min(2).max(100), acceptTerms: z.boolean().refine((val) => val === true, 'Musisz zaakceptować warunki')});
// Zapobieganie SQL injectionexport const searchQuerySchema = z.object({ q: safeString .max(100) .refine( (val) => !/(union|select|insert|update|delete|drop|script|exec)/i.test(val), 'Nieprawidłowe zapytanie wyszukiwania' ), page: z.coerce.number().int().positive().default(1), limit: z.coerce.number().int().min(1).max(100).default(20)});
// Walidacja przesyłania plikówexport const fileUploadSchema = z.object({ file: z.custom<File>() .refine((file) => file.size <= 5 * 1024 * 1024, 'Plik za duży') .refine( (file) => ['image/jpeg', 'image/png', 'image/webp'].includes(file.type), 'Nieprawidłowy typ pliku' ) .refine( async (file) => { // Weryfikuj że zawartość pliku pasuje do typu MIME const buffer = await file.arrayBuffer(); const header = new Uint8Array(buffer).slice(0, 4);
// Sprawdź magic numbers const jpg = header[0] === 0xFF && header[1] === 0xD8; const png = header[0] === 0x89 && header[1] === 0x50; const webp = header[0] === 0x52 && header[1] === 0x49;
return jpg || png || webp; }, 'Zawartość pliku nie pasuje do typu' )});
// Middleware do walidacjiexport function validateRequest(schema: z.ZodSchema) { return async (req: Request, res: Response, next: NextFunction) => { try { const validated = await schema.parseAsync({ ...req.body, ...req.query, ...req.params });
// Zastąp dane żądania zwalidowanymi/zsanityzowanymi danymi req.body = validated; next(); } catch (error) { if (error instanceof z.ZodError) { res.status(400).json({ error: 'Walidacja nie powiodła się', details: error.errors.map(e => ({ field: e.path.join('.'), message: e.message })) }); } else { next(error); } } };}
"Implementuj kodowanie wyjścia:- Kodowanie encji HTML- Kodowanie JSON- Kodowanie URL- Escapowanie identyfikatorów SQL- Escapowanie linii komend- Zapobieganie atakom XSS"
"Implementuj nagłówki CSP:- Zdefiniuj allowlisty źródeł- Zapobiegaj inline scripts- Blokuj niebezpieczne eval- Raportuj naruszenia- Implementuj CSP oparte na nonce- Dodaj upgrade-insecure-requests"
"Implementuj szyfrowanie danych:- Szyfruj wrażliwe dane w spoczynku- Implementuj szyfrowanie na poziomie pól- Bezpieczne zarządzanie kluczami- Szyfruj dane w tranzycie- Implementuj najlepsze praktyki krypto- Dodaj rotację kluczy szyfrowania"
Przykład usługi szyfrowania:
import crypto from 'crypto';import { KeyManagementService } from './kms';
export class EncryptionService { private readonly algorithm = 'aes-256-gcm'; private readonly kms = new KeyManagementService();
async encryptField(plaintext: string, context?: string): Promise<EncryptedData> { // Pobierz lub wygeneruj klucz szyfrowania danych const dataKey = await this.kms.generateDataKey();
// Wygeneruj IV const iv = crypto.randomBytes(16);
// Stwórz cipher const cipher = crypto.createCipheriv( this.algorithm, dataKey.plaintext, iv );
// Dodaj uwierzytelnione dane jeśli podane if (context) { cipher.setAAD(Buffer.from(context, 'utf8')); }
// Szyfruj const encrypted = Buffer.concat([ cipher.update(plaintext, 'utf8'), cipher.final() ]);
// Pobierz tag uwierzytelniania const authTag = cipher.getAuthTag();
return { ciphertext: encrypted.toString('base64'), iv: iv.toString('base64'), authTag: authTag.toString('base64'), keyId: dataKey.keyId, algorithm: this.algorithm, context }; }
async decryptField(encryptedData: EncryptedData): Promise<string> { // Pobierz klucz deszyfrowania const dataKey = await this.kms.decryptDataKey( encryptedData.keyId, encryptedData.encryptedKey );
// Stwórz decipher const decipher = crypto.createDecipheriv( encryptedData.algorithm, dataKey, Buffer.from(encryptedData.iv, 'base64') );
// Ustaw tag uwierzytelniania decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'base64'));
// Dodaj uwierzytelnione dane jeśli obecne if (encryptedData.context) { decipher.setAAD(Buffer.from(encryptedData.context, 'utf8')); }
// Deszyfruj const decrypted = Buffer.concat([ decipher.update(Buffer.from(encryptedData.ciphertext, 'base64')), decipher.final() ]);
return decrypted.toString('utf8'); }
// Szyfrowanie przeszukiwalne dla zapytań bazy danych async encryptSearchable(plaintext: string): Promise<SearchableEncrypted> { const encrypted = await this.encryptField(plaintext);
// Wygeneruj blind index do wyszukiwania const blindIndex = crypto .createHmac('sha256', await this.kms.getBlindIndexKey()) .update(plaintext.toLowerCase()) .digest('hex');
return { ...encrypted, blindIndex }; }}
// Middleware Prisma dla automatycznego szyfrowaniaexport function encryptionMiddleware() { return async (params, next) => { // Szyfruj przy create/update if (params.action === 'create' || params.action === 'update') { if (params.args.data?.ssn) { params.args.data.ssn = await encryptionService.encryptField( params.args.data.ssn ); } }
const result = await next(params);
// Deszyfruj przy odczycie if (params.action === 'findUnique' || params.action === 'findFirst') { if (result?.ssn) { result.ssn = await encryptionService.decryptField(result.ssn); } }
return result; };}
"Implementuj bezpieczne przechowywanie danych:- Oddziel PII od innych danych- Implementuj polityki retencji danych- Bezpieczne procedury backup- Anonimizacja danych- Audit trail dla dostępu do danych- Implementuj prawo do bycia zapomnianym"
"Zabezpiecz całą komunikację:- Wymuś HTTPS wszędzie- Implementuj certificate pinning- Zabezpiecz połączenia WebSocket- Uwierzytelnianie API- Podpisywanie żądań- Zapobiegaj atakom man-in-the-middle"
"Stwórz zestaw testów bezpieczeństwa:- Testy SQL injection- Testy ataków XSS- Testy CSRF- Testy omijania uwierzytelniania- Testy autoryzacji- Testy bezpieczeństwa APIDołącz do pipeline CI/CD"
Przykład testów bezpieczeństwa:
describe('Zapobieganie SQL Injection', () => { const maliciousInputs = [ "'; DROP TABLE users; --", "1' OR '1'='1", "admin'--", "1' UNION SELECT * FROM users--", "1; UPDATE users SET role='admin'--" ];
test.each(maliciousInputs)( 'powinno zapobiec SQL injection z wejściem: %s', async (input) => { const response = await request(app) .get('/api/users/search') .query({ q: input }) .expect(400);
expect(response.body.error).toBe('Walidacja nie powiodła się');
// Weryfikuj że baza danych nie została naruszona const userCount = await db.user.count(); expect(userCount).toBeGreaterThan(0); } );});
describe('Zapobieganie XSS', () => { const xssPayloads = [ '<script>alert("XSS")</script>', '<img src=x onerror=alert("XSS")>', '<svg onload=alert("XSS")>', 'javascript:alert("XSS")', '<iframe src="javascript:alert(\'XSS\')"></iframe>' ];
test.each(xssPayloads)( 'powinno sanityzować payload XSS: %s', async (payload) => { const response = await request(app) .post('/api/comments') .send({ content: payload }) .expect(201);
// Weryfikuj że zapisana zawartość jest zsanityzowana const comment = await db.comment.findUnique({ where: { id: response.body.id } });
expect(comment.content).not.toContain('<script>'); expect(comment.content).not.toContain('javascript:'); expect(comment.content).not.toContain('onerror='); } );});
"Implementuj monitorowanie bezpieczeństwa:- Nieudane próby logowania- Wzorce podejrzanej aktywności- Monitorowanie integralności plików- Skanowanie podatności- Wykrywanie włamań- Alerty w czasie rzeczywistym"
"Stwórz system reagowania na incydenty:- Automatyczne wykrywanie zagrożeń- Klasyfikacja incydentów- Procedury reagowania- Zbieranie dowodów- System powiadamiania użytkowników- Procedury odzyskiwania"
Warstwy kontroli bezpieczeństwa:
// Wiele warstw ochronyasync function secureEndpoint(req, res) { // Warstwa 1: Rate limiting await rateLimiter.check(req);
// Warstwa 2: Uwierzytelnianie const user = await authenticate(req);
// Warstwa 3: Autoryzacja await authorize(user, 'resource:read');
// Warstwa 4: Walidacja wejścia const validated = await validateInput(req.body);
// Warstwa 5: Logika biznesowa ze sprawdzeniami bezpieczeństwa const result = await processRequest(validated, user);
// Warstwa 6: Kodowanie wyjścia res.json(encodeOutput(result));}
Wbuduj bezpieczeństwo od początku:
// Bezpieczne domyślne ustawieniaconst secureConfig = { session: { httpOnly: true, secure: true, sameSite: 'strict', maxAge: 15 * 60 * 1000 // 15 minut }, headers: { 'X-Frame-Options': 'DENY', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Strict-Transport-Security': 'max-age=31536000' }};
Minimalizuj dostęp i uprawnienia:
// Użytkownik bazy danych z minimalnymi uprawnieniamiCREATE USER 'app_user'@'localhost' IDENTIFIED BY 'strong_password';GRANT SELECT, INSERT, UPDATE ON myapp.* TO 'app_user'@'localhost';-- Bez uprawnień DELETE, DROP, CREATE
// Uprawnienia APIconst permissions = { user: ['profile:read', 'profile:update'], admin: ['users:read', 'users:update', 'users:delete'], service: ['data:read'] // Konta serwisowe dostają minimalny dostęp};
Problem: Wejście użytkownika wykonywane jako kod
Rozwiązanie:
// Zawsze używaj sparametryzowanych zapytańconst user = await db.query( 'SELECT * FROM users WHERE email = ?', [email]);
// Waliduj i sanityzuj wszystkie wejściaconst validated = schema.parse(userInput);
// Używaj ORM z wbudowaną ochronąconst user = await prisma.user.findUnique({ where: { email }});
Problem: Słaba implementacja uwierzytelniania
Rozwiązanie:
// Implementuj właściwe polityki hasełconst strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{12,}$/;
// Używaj bezpiecznego zarządzania sesjamireq.session.regenerate(); // Zapobieganie fiksacji
// Implementuj MFAconst verified = speakeasy.totp.verify({ secret: user.totpSecret, token: userToken});
Problem: Nieszyfrowane wrażliwe dane
Rozwiązanie:
// Szyfruj w spoczynkuconst encrypted = await encrypt(sensitiveData);
// Używaj HTTPS wszędzieapp.use(enforceHTTPS());
// Nie loguj wrażliwych danychlogger.info('Logowanie użytkownika', { userId: user.id, // Nie loguj: hasło, PESEL, itd.});
Zaawansowane implementacje bezpieczeństwa:
Architektura zero trust
Zaawansowana ochrona przed zagrożeniami
Automatyzacja zgodności
Twoja implementacja bezpieczeństwa jest udana, gdy:
Zespoły implementujące te praktyki raportują:
Przed wdrożeniem:
Opanowałeś implementację bezpieczeństwa. Gotowy na więcej?
Testy penetracyjne
Naucz się technik ethical hackingu
Architektura bezpieczeństwa
Projektuj bezpieczne systemy od podstaw
Automatyzacja zgodności
Automatyzuj procesy zgodności
Kontynuuj do Generowanie dokumentacji →