Skanowanie bezpieczeństwa
Bezpieczeństwo nie jest opcjonalne - to fundamentalne. Czy obsługujesz dane użytkowników, przetwarzasz płatności, czy po prostu budujesz blog, luki bezpieczeństwa mogą zniszczyć zaufanie i biznes. Claude Code przekształca bezpieczeństwo z ćwiczenia zaznaczonej listy w zintegrowaną praktykę rozwoju, pomagając budować bezpieczne aplikacje od podstaw.
Rewolucja bezpieczeństwa
Dział zatytułowany „Rewolucja bezpieczeństwa”Scenariusz: Twoja aplikacja obsługuje wrażliwe dane tysięcy użytkowników. Jedna luka może ujawnić wszystko - dane uwierzytelniające, informacje osobiste, szczegóły płatności. Tradycyjne podejście: okresowe pentesty, nadzieja na najlepsze. Z Claude Code: ciągła analiza bezpieczeństwa, która łapie luki zanim dotrą do produkcji.
Tradycyjne vs bezpieczeństwo z pomocą AI
Dział zatytułowany „Tradycyjne vs bezpieczeństwo z pomocą AI”Miesiąc 1: Rozwój- Skupienie na funkcjach- Bezpieczeństwo jako dodatek- "Naprawimy to później"
Miesiąc 3: Audit bezpieczeństwa- Zewnętrzny pentest- Długa lista luk- Gorączkowe naprawianie
Miesiąc 4: Naruszenie- Luka wykorzystana- Dane ujawnione- Reputacja zniszczona
Na bieżąco: Tryb reaktywny- Napraw po odkryciu- Miej nadzieję, że nic nie przegapiono- Trzymaj kciuki
Dzień 1: Bezpieczny fundament> Przeanalizuj wymagania bezpieczeństwa> Skonfiguruj framework bezpieczeństwa> Zaimplementuj bezpieczne domyślne
Ciągle: Proaktywne bezpieczeństwo> Skanuj kod w miarę pisania> Naprawiaj luki natychmiast> Aktualizuj zależności automatycznie
Czas rzeczywisty: Zapobieganie zagrożeniom> Wykrywaj podejrzane wzorce> Blokuj wektory ataku> Monitoruj anomalie
Wynik: Pewność bezpieczeństwa> Śpij spokojnie w nocy> Przechodź audity łatwo> Buduj zaufanie użytkowników
Wykrywanie luk
Dział zatytułowany „Wykrywanie luk”Kompleksowa analiza bezpieczeństwa
Dział zatytułowany „Kompleksowa analiza bezpieczeństwa”> Wykonaj kompleksowy audit bezpieczeństwa naszej bazy kodu:> - Luki OWASP Top 10> - Błędy uwierzytelniania i autoryzacji> - Problemy walidacji wejścia> - Słabości kryptograficzne> - Problemy konfiguracji> - Luki zależności
Claude wykonuje głęboką analizę bezpieczeństwa:
-
Wykrywanie SQL Injection
// ZNALEZIONO KOD PODATNYapp.get('/user/:id', async (req, res) => {const userId = req.params.id;// ❌ Bezpośrednia konkatenacja stringów - ryzyko SQL injection!const query = `SELECT * FROM users WHERE id = ${userId}`;const result = await db.query(query);res.json(result);});// BEZPIECZNE ZASTĄPIENIEapp.get('/user/:id', async (req, res) => {const userId = req.params.id;// ✅ Walidacja wejściaif (!/^\d+$/.test(userId)) {return res.status(400).json({ error: 'Invalid user ID' });}// ✅ Zapytanie sparametryzowaneconst query = 'SELECT * FROM users WHERE id = $1';const result = await db.query(query, [userId]);// ✅ Nie ujawniaj wrażliwych pólconst { password_hash, ...safeUser } = result.rows[0] || {};res.json(safeUser);}); -
Zapobieganie Cross-Site Scripting (XSS)
// ZNALEZIONO KOD PODATNYapp.post('/comment', (req, res) => {const comment = req.body.comment;// ❌ Bezpośrednie wstawianie HTML - ryzyko XSS!const html = `<div class="comment">${comment}</div>`;saveCommentHTML(html);});// BEZPIECZNE ZASTĄPIENIEconst DOMPurify = require('isomorphic-dompurify');const { JSDOM } = require('jsdom');app.post('/comment', (req, res) => {const comment = req.body.comment;// ✅ Oczyść wejście HTMLconst window = new JSDOM('').window;const purify = DOMPurify(window);const clean = purify.sanitize(comment, {ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],ALLOWED_ATTR: ['href']});// ✅ Content Security Policyres.setHeader('Content-Security-Policy',"default-src 'self'; script-src 'self' 'nonce-${nonce}'");const html = `<div class="comment">${clean}</div>`;saveCommentHTML(html);}); -
Uwierzytelnianie i autoryzacja
// ZNALEZIONO KOD PODATNYapp.post('/admin/users', (req, res) => {// ❌ Brak sprawdzenia uwierzytelniania!updateUsers(req.body);res.json({ success: true });});// BEZPIECZNE ZASTĄPIENIEconst jwt = require('jsonwebtoken');const bcrypt = require('bcrypt');// Middleware uwierzytelnianiaconst authenticate = async (req, res, next) => {const token = req.headers.authorization?.split(' ')[1];if (!token) {return res.status(401).json({ error: 'No token provided' });}try {const decoded = jwt.verify(token, process.env.JWT_SECRET);req.user = await User.findById(decoded.userId);next();} catch (error) {return res.status(401).json({ error: 'Invalid token' });}};// Middleware autoryzacjiconst authorize = (...roles) => {return (req, res, next) => {if (!roles.includes(req.user.role)) {return res.status(403).json({ error: 'Insufficient permissions' });}next();};};// ✅ Chroniona ścieżka z auth & authzapp.post('/admin/users',authenticate,authorize('admin', 'superadmin'),async (req, res) => {// Dodatkowa walidacjaconst { error } = validateUserUpdate(req.body);if (error) {return res.status(400).json({ error: error.details[0].message });}await updateUsers(req.body);// Logowanie audytuawait auditLog({action: 'UPDATE_USERS',userId: req.user.id,changes: req.body,ip: req.ip});res.json({ success: true });}); -
Bezpieczeństwo kryptograficzne
// ZNALEZIONO KOD PODATNYconst crypto = require('crypto');function hashPassword(password) {// ❌ Słabe haszowanie - MD5 jest złamane!return crypto.createHash('md5').update(password).digest('hex');}function encryptData(data) {// ❌ Hardcoded klucz i słaby algorytmconst key = '1234567890123456';const cipher = crypto.createCipher('aes-128-ecb', key);return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');}// BEZPIECZNE ZASTĄPIENIEconst bcrypt = require('bcrypt');const argon2 = require('argon2');// ✅ Silne haszowanie hasłaasync function hashPassword(password) {// Opcja 1: bcrypt (dobre)const saltRounds = 12;return await bcrypt.hash(password, saltRounds);// Opcja 2: argon2 (lepsze)return await argon2.hash(password, {type: argon2.argon2id,memoryCost: 2 ** 16,timeCost: 3,parallelism: 1,});}// ✅ Bezpieczne szyfrowanieasync function encryptData(data) {const algorithm = 'aes-256-gcm';const key = crypto.scryptSync(process.env.ENCRYPTION_PASSWORD,process.env.ENCRYPTION_SALT,32);const iv = crypto.randomBytes(16);const cipher = crypto.createCipheriv(algorithm, key, iv);let encrypted = cipher.update(data, 'utf8', 'hex');encrypted += cipher.final('hex');const authTag = cipher.getAuthTag();return {encrypted,iv: iv.toString('hex'),authTag: authTag.toString('hex')};}
Walidacja i oczyszczanie wejścia
Dział zatytułowany „Walidacja i oczyszczanie wejścia”> Zaimplementuj kompleksową walidację wejścia:> - Walidacja request body> - Oczyszczanie parametrów zapytania> - Bezpieczeństwo przesyłania plików> - Rate limiting> - Limity rozmiaru żądań
const Joi = require('joi');const rateLimit = require('express-rate-limit');const mongoSanitize = require('express-mongo-sanitize');const hpp = require('hpp');const helmet = require('helmet');
// Walidacja schematówconst schemas = { createUser: Joi.object({ email: Joi.string().email().required(), password: Joi.string() .min(12) .pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/) .required() .messages({ 'string.pattern.base': 'Hasło musi zawierać małe litery, duże litery, cyfrę i znak specjalny' }), username: Joi.string() .alphanum() .min(3) .max(30) .required(), role: Joi.string() .valid('user', 'admin') .default('user') }),
updateProfile: Joi.object({ bio: Joi.string().max(500), website: Joi.string().uri(), phone: Joi.string().pattern(/^\+?[\d\s-()]+$/) })};
// Middleware walidacjiconst validate = (schema) => { return (req, res, next) => { const { error, value } = schema.validate(req.body, { abortEarly: false, stripUnknown: true });
if (error) { const errors = error.details.map(detail => ({ field: detail.path.join('.'), message: detail.message }));
return res.status(400).json({ errors }); }
req.body = value; next(); };};
// Stos middleware bezpieczeństwaconst securityMiddleware = [ // Helmet dla nagłówków bezpieczeństwa helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'", "'nonce-${nonce}'"], styleSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", "data:", "https:"], connectSrc: ["'self'"], fontSrc: ["'self'"], objectSrc: ["'none'"], mediaSrc: ["'self'"], frameSrc: ["'none'"], }, }, hsts: { maxAge: 31536000, includeSubDomains: true, preload: true } }),
// Zapobieganie NoSQL injection mongoSanitize({ replaceWith: '_', onSanitize: ({ req, key }) => { console.warn(`Zablokowano próbę NoSQL injection: ${key}`); } }),
// Zapobieganie zanieczyszczeniu parametrów hpp({ whitelist: ['sort', 'filter'] }),
// Limity rozmiaru żądania express.json({ limit: '10mb' }), express.urlencoded({ extended: true, limit: '10mb' }),
// Rate limiting rateLimit({ windowMs: 15 * 60 * 1000, // 15 minut max: 100, // limit każde IP do 100 żądań na windowMs message: 'Zbyt wiele żądań z tego IP', standardHeaders: true, legacyHeaders: false, })];
// Bezpieczeństwo przesyłania plikówconst multer = require('multer');const path = require('path');
const fileFilter = (req, file, cb) => { // Dozwolone rozszerzenia const allowedExtensions = ['.jpg', '.jpeg', '.png', '.pdf']; const ext = path.extname(file.originalname).toLowerCase();
if (!allowedExtensions.includes(ext)) { return cb(new Error('Nieprawidłowy typ pliku'), false); }
// Sprawdź typ MIME const allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf']; if (!allowedMimeTypes.includes(file.mimetype)) { return cb(new Error('Nieprawidłowy typ MIME'), false); }
// Sprawdź podwójne rozszerzenia const nameWithoutExt = path.basename(file.originalname, ext); if (path.extname(nameWithoutExt)) { return cb(new Error('Podwójne rozszerzenie niedozwolone'), false); }
cb(null, true);};
const upload = multer({ storage: multer.diskStorage({ destination: (req, file, cb) => { cb(null, 'uploads/'); }, filename: (req, file, cb) => { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); cb(null, uniqueSuffix + path.extname(file.originalname)); } }), fileFilter, limits: { fileSize: 5 * 1024 * 1024, // 5MB files: 5 }});
module.exports = { schemas, validate, securityMiddleware, upload};
Skanowanie zależności
Dział zatytułowany „Skanowanie zależności”Automatyczne skanowanie luk
Dział zatytułowany „Automatyczne skanowanie luk”> Skonfiguruj automatyczne skanowanie luk zależności:> - Sprawdź znane CVE> - Zidentyfikuj przestarzałe pakiety> - Zasugeruj bezpieczne alternatywy> - Utwórz strategię aktualizacji
const { execSync } = require('child_process');const fs = require('fs').promises;
class SecurityScanner { async scanDependencies() { console.log('🔍 Skanowanie zależności w poszukiwaniu luk...\n');
const scanners = [ this.npmAudit.bind(this), this.snykScan.bind(this), this.oswScan.bind(this), this.retireScan.bind(this) ];
const results = await Promise.allSettled(scanners.map(scan => scan()));
return this.consolidateResults(results); }
async npmAudit() { try { const output = execSync('npm audit --json', { encoding: 'utf8' }); const audit = JSON.parse(output);
return { scanner: 'npm-audit', vulnerabilities: audit.vulnerabilities, summary: audit.metadata.vulnerabilities }; } catch (error) { // npm audit kończy z kodem błędu jeśli znaleziono luki const audit = JSON.parse(error.stdout); return { scanner: 'npm-audit', vulnerabilities: audit.vulnerabilities, summary: audit.metadata.vulnerabilities }; } }
async snykScan() { try { const output = execSync('snyk test --json', { encoding: 'utf8' }); const result = JSON.parse(output);
return { scanner: 'snyk', vulnerabilities: result.vulnerabilities, summary: { total: result.vulnerabilities.length, high: result.vulnerabilities.filter(v => v.severity === 'high').length, medium: result.vulnerabilities.filter(v => v.severity === 'medium').length, low: result.vulnerabilities.filter(v => v.severity === 'low').length } }; } catch (error) { console.warn('Skanowanie Snyk nie powiodło się:', error.message); return null; } }
async oswScan() { try { // OSV Scanner dla kompleksowej bazy danych luk execSync('osv-scanner --json -o osv-results.json .', { encoding: 'utf8' }); const results = await fs.readFile('osv-results.json', 'utf8'); return { scanner: 'osv', results: JSON.parse(results) }; } catch (error) { console.warn('Skanowanie OSV nie powiodło się:', error.message); return null; } }
async retireScan() { try { // RetireJS dla luk specyficznych dla JavaScript const output = execSync('retire --outputformat json', { encoding: 'utf8' }); return { scanner: 'retirejs', results: JSON.parse(output) }; } catch (error) { console.warn('Skanowanie RetireJS nie powiodło się:', error.message); return null; } }
consolidateResults(results) { const consolidated = { timestamp: new Date().toISOString(), scanners: [], totalVulnerabilities: 0, criticalFindings: [], recommendations: [] };
results.forEach(result => { if (result.status === 'fulfilled' && result.value) { consolidated.scanners.push(result.value.scanner);
// Wyodrębnij krytyczne znaleziska if (result.value.vulnerabilities) { Object.entries(result.value.vulnerabilities).forEach(([pkg, vuln]) => { if (vuln.severity === 'high' || vuln.severity === 'critical') { consolidated.criticalFindings.push({ package: pkg, severity: vuln.severity, title: vuln.title, recommendation: vuln.fixAvailable }); } }); } } });
// Generuj rekomendacje if (consolidated.criticalFindings.length > 0) { consolidated.recommendations.push( 'Wymagane natychmiastowe działanie: Zaktualizuj krytyczne zależności' ); }
return consolidated; }}
// Automatyczne generowanie poprawekclass SecurityFixer { async generateFixes(scanResults) { const fixes = [];
for (const finding of scanResults.criticalFindings) { const fix = await this.generateFix(finding); if (fix) fixes.push(fix); }
return fixes; }
async generateFix(finding) { // Sprawdź czy dostępna jest automatyczna poprawka if (finding.recommendation?.fixAvailable) { return { package: finding.package, command: `npm update ${finding.package}`, description: `Zaktualizuj ${finding.package} aby naprawić ${finding.title}` }; }
// Dla bardziej złożonych poprawek, wygeneruj przewodnik migracji return { package: finding.package, manual: true, steps: [ `Przejrzyj breaking changes dla ${finding.package}`, `Zaktualizuj kod aby obsłużyć zmiany API`, `Przetestuj dokładnie przed wdrożeniem` ] }; }}
// Integracja CI/CDmodule.exports = { SecurityScanner, SecurityFixer,
// Workflow GitHub Action githubAction: `name: Security Scan
on: push: branches: [ main, develop ] pull_request: branches: [ main ] schedule: - cron: '0 0 * * *' # Skanowanie codzienne
jobs: security: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Run Security Scan run: | npm ci npm audit
- name: Upload results uses: github/codeql-action/upload-sarif@v2 with: sarif_file: security-results.sarif `};
Wzorce bezpiecznego kodowania
Dział zatytułowany „Wzorce bezpiecznego kodowania”Wzorce projektowe bezpieczeństwa
Dział zatytułowany „Wzorce projektowe bezpieczeństwa”> Zaimplementuj wzorce bezpiecznego kodowania dla naszej aplikacji:> - Bezpieczne zarządzanie sesjami> - Ochrona CSRF> - Nagłówki bezpieczeństwa> - Bezpieczna obsługa cookies> - Bezpieczeństwo API
const session = require('express-session');const MongoStore = require('connect-mongo');const csrf = require('csurf');const crypto = require('crypto');
// Bezpieczna konfiguracja sesjiconst sessionConfig = { secret: process.env.SESSION_SECRET || crypto.randomBytes(64).toString('hex'), name: 'sessionId', // Nie używaj domyślnego 'connect.sid' resave: false, saveUninitialized: false, store: MongoStore.create({ mongoUrl: process.env.MONGODB_URI, touchAfter: 24 * 3600, // Leniwa aktualizacja sesji crypto: { secret: process.env.SESSION_STORE_SECRET } }), cookie: { secure: process.env.NODE_ENV === 'production', // Tylko HTTPS httpOnly: true, // Brak dostępu JS maxAge: 1000 * 60 * 60 * 24, // 24 godziny sameSite: 'strict' // Ochrona CSRF }};
// Ochrona CSRFconst csrfProtection = csrf({ cookie: { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict' }});
// Middleware bezpieczeństwa APIclass ApiSecurity { static apiKey() { return async (req, res, next) => { const apiKey = req.headers['x-api-key'];
if (!apiKey) { return res.status(401).json({ error: 'Wymagany klucz API' }); }
// Porównanie bezpieczne czasowo const validKey = await ApiKey.findOne({ key: crypto.createHash('sha256').update(apiKey).digest('hex'), active: true });
if (!validKey) { // Rate limit nieudanych prób await this.recordFailedAttempt(req.ip); return res.status(401).json({ error: 'Nieprawidłowy klucz API' }); }
// Sprawdź limity rate dla tego klucza if (await this.isRateLimited(validKey)) { return res.status(429).json({ error: 'Przekroczono limit rate' }); }
req.apiKey = validKey; next(); }; }
static async recordFailedAttempt(ip) { const key = `failed_auth:${ip}`; const attempts = await redis.incr(key);
if (attempts === 1) { await redis.expire(key, 3600); // Okno 1 godziny }
if (attempts > 10) { // Tymczasowo zablokuj IP await redis.setex(`blocked:${ip}`, 3600, '1'); } }
static async isRateLimited(apiKey) { const key = `rate:${apiKey._id}`; const requests = await redis.incr(key);
if (requests === 1) { await redis.expire(key, 60); // Okno 1 minuty }
return requests > apiKey.rateLimit; }}
// Middleware bezpiecznych nagłówkówconst secureHeaders = (req, res, next) => { // Usuń nagłówki fingerprinting res.removeHeader('X-Powered-By');
// Nagłówki bezpieczeństwa res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('X-XSS-Protection', '1; mode=block'); res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin'); res.setHeader('Permissions-Policy', 'geolocation=(), microphone=(), camera=()');
// HSTS if (req.secure) { res.setHeader( 'Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload' ); }
next();};
// Bezpieczny handler błędówconst secureErrorHandler = (err, req, res, next) => { // Loguj szczegóły błędu po stronie serwera console.error('Błąd:', { message: err.message, stack: err.stack, url: req.url, method: req.method, ip: req.ip, user: req.user?.id });
// Nie ujawniaj szczegółów błędu klientowi const isDev = process.env.NODE_ENV === 'development';
res.status(err.status || 500).json({ error: { message: isDev ? err.message : 'Błąd wewnętrzny serwera', code: err.code || 'SERVER_ERROR', ...(isDev && { stack: err.stack }) } });};
// Builder Content Security Policyclass CSPBuilder { constructor() { this.directives = { defaultSrc: ["'self'"], scriptSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", 'data:', 'https:'], connectSrc: ["'self'"], fontSrc: ["'self'"], objectSrc: ["'none'"], mediaSrc: ["'self'"], frameSrc: ["'none'"], baseUri: ["'self'"], formAction: ["'self'"], frameAncestors: ["'none'"], upgradeInsecureRequests: [] }; }
addNonce(req, res, next) { res.locals.nonce = crypto.randomBytes(16).toString('base64'); this.directives.scriptSrc.push(`'nonce-${res.locals.nonce}'`); next(); }
build() { return Object.entries(this.directives) .map(([key, values]) => { const directive = key.replace(/([A-Z])/g, '-$1').toLowerCase(); return `${directive} ${values.join(' ')}`; }) .join('; '); }}
module.exports = { sessionConfig, csrfProtection, ApiSecurity, secureHeaders, secureErrorHandler, CSPBuilder};
Zgodność i standardy
Dział zatytułowany „Zgodność i standardy”Zgodność z OWASP
Dział zatytułowany „Zgodność z OWASP”> Zaimplementuj standardy bezpieczeństwa OWASP:> - Ochrona OWASP Top 10> - Logowanie bezpieczeństwa> - Ścieżki audytu> - Raportowanie zgodności
const winston = require('winston');const { ElasticsearchTransport } = require('winston-elasticsearch');
// Logger zdarzeń bezpieczeństwaclass SecurityLogger { constructor() { this.logger = winston.createLogger({ level: 'info', format: winston.format.json(), defaultMeta: { service: 'security', environment: process.env.NODE_ENV }, transports: [ new winston.transports.File({ filename: 'security.log', level: 'warning' }), new ElasticsearchTransport({ level: 'info', clientOpts: { node: process.env.ELASTICSEARCH_URL, auth: { username: process.env.ELASTIC_USER, password: process.env.ELASTIC_PASSWORD } }, index: 'security-logs' }) ] }); }
logSecurityEvent(event) { const logEntry = { timestamp: new Date().toISOString(), eventType: event.type, severity: event.severity, userId: event.userId, ip: event.ip, userAgent: event.userAgent, resource: event.resource, action: event.action, result: event.result, details: event.details };
this.logger.log(event.severity || 'info', logEntry);
// Alert przy krytycznych zdarzeniach if (event.severity === 'critical') { this.sendAlert(logEntry); } }
async sendAlert(event) { // Wyślij do zespołu bezpieczeństwa await sendEmail({ to: process.env.SECURITY_TEAM_EMAIL, subject: `Krytyczne zdarzenie bezpieczeństwa: ${event.eventType}`, template: 'security-alert', data: event });
// Wyślij na Slack await sendSlackNotification({ channel: '#security-alerts', text: `🚨 Krytyczne zdarzenie bezpieczeństwa: ${event.eventType}`, attachments: [{ color: 'danger', fields: [ { title: 'Użytkownik', value: event.userId, short: true }, { title: 'IP', value: event.ip, short: true }, { title: 'Zasób', value: event.resource }, { title: 'Szczegóły', value: event.details } ] }] }); }}
// Implementacja ścieżki audytuclass AuditTrail { static middleware() { return async (req, res, next) => { const auditEntry = { requestId: req.id, timestamp: new Date(), user: req.user?.id || 'anonymous', method: req.method, path: req.path, query: req.query, ip: req.ip, userAgent: req.get('user-agent') };
// Przechwyć odpowiedź const originalSend = res.send; res.send = function(data) { auditEntry.statusCode = res.statusCode; auditEntry.responseTime = Date.now() - auditEntry.timestamp;
// Loguj wrażliwe operacje if (AuditTrail.isSensitiveOperation(req)) { auditEntry.body = req.body; auditEntry.response = data;
AuditLog.create(auditEntry); }
originalSend.call(this, data); };
next(); }; }
static isSensitiveOperation(req) { const sensitivePaths = [ '/api/users', '/api/auth', '/api/admin', '/api/payments', '/api/settings' ];
const sensitiveMethods = ['POST', 'PUT', 'DELETE', 'PATCH'];
return sensitiveMethods.includes(req.method) && sensitivePaths.some(path => req.path.startsWith(path)); }}
// Raportowanie zgodnościclass ComplianceReporter { async generateOWASPReport() { const report = { generatedAt: new Date().toISOString(), standard: 'OWASP Top 10 2021', controls: [] };
// A1: Broken Access Control report.controls.push({ id: 'A01:2021', name: 'Broken Access Control', status: await this.checkAccessControl(), evidence: [ 'Zaimplementowana kontrola dostępu oparta na rolach', 'Middleware autoryzacji na wszystkich wrażliwych ścieżkach', 'Logowanie audytu dla zmian uprawnień' ] });
// A2: Cryptographic Failures report.controls.push({ id: 'A02:2021', name: 'Cryptographic Failures', status: await this.checkCryptography(), evidence: [ 'Silne algorytmy szyfrowania (AES-256)', 'Bezpieczne zarządzanie kluczami', 'Wymuszone TLS 1.3' ] });
// A3: Injection report.controls.push({ id: 'A03:2021', name: 'Injection', status: await this.checkInjectionPrevention(), evidence: [ 'Zapytania sparametryzowane', 'Walidacja wejścia', 'Kodowanie wyjścia' ] });
// Kontynuuj dla wszystkich OWASP Top 10...
return report; }
async checkAccessControl() { // Uruchom automatyczne testy const tests = [ this.testAuthorizationBypass(), this.testPrivilegeEscalation(), this.testJWTValidation() ];
const results = await Promise.all(tests); return results.every(r => r.passed) ? 'PASS' : 'FAIL'; }
async generateCompliancePackage() { const reports = await Promise.all([ this.generateOWASPReport(), this.generatePCIDSSReport(), this.generateSOC2Report() ]);
return { timestamp: new Date().toISOString(), reports, attestation: this.generateAttestation(reports) }; }}
module.exports = { SecurityLogger, AuditTrail, ComplianceReporter};
Automatyczne testowanie bezpieczeństwa
Dział zatytułowany „Automatyczne testowanie bezpieczeństwa”Zestaw testów bezpieczeństwa
Dział zatytułowany „Zestaw testów bezpieczeństwa”> Utwórz kompleksowy zestaw testów bezpieczeństwa:> - Testy penetracyjne> - Fuzzing> - Testy regresji bezpieczeństwa> - Walidacja zgodności
const request = require('supertest');const app = require('../app');const { SecurityTester } = require('./security-tester');
describe('Zestaw testów bezpieczeństwa', () => { const tester = new SecurityTester(app);
describe('Bezpieczeństwo uwierzytelniania', () => { test('Powinno zapobiegać atakom brute force', async () => { const attempts = Array(10).fill().map((_, i) => request(app) .post('/api/auth/login') .send({ email: 'test@example.com', password: `wrong${i}` }) );
const results = await Promise.all(attempts);
// Powinno blokować po przekroczeniu progu const blocked = results.filter(r => r.status === 429); expect(blocked.length).toBeGreaterThan(0); });
test('Powinno zapobiegać atakom timing na login', async () => { const timings = [];
// Testuj z prawidłowymi i nieprawidłowymi użytkownikami for (const email of ['valid@example.com', 'invalid@example.com']) { const start = process.hrtime.bigint(); await request(app) .post('/api/auth/login') .send({ email, password: 'password123' }); const end = process.hrtime.bigint();
timings.push(Number(end - start) / 1000000); // Konwertuj na ms }
// Różnica czasowa powinna być minimalna (< 50ms) const difference = Math.abs(timings[0] - timings[1]); expect(difference).toBeLessThan(50); });
test('Powinno wymuszać silne hasła', async () => { const weakPasswords = [ 'password', '12345678', 'qwerty123', 'admin123', 'Password1' // Brak znaku specjalnego ];
for (const password of weakPasswords) { const response = await request(app) .post('/api/auth/register') .send({ email: 'test@example.com', password, username: 'testuser' });
expect(response.status).toBe(400); expect(response.body.errors).toBeDefined(); } }); });
describe('Bezpieczeństwo walidacji wejścia', () => { test('Powinno zapobiegać SQL injection', async () => { const sqlInjectionPayloads = [ "1' OR '1'='1", "1'; DROP TABLE users; --", "1' UNION SELECT * FROM users--", "admin'--", "' OR 1=1--" ];
for (const payload of sqlInjectionPayloads) { const response = await request(app) .get(`/api/users/${payload}`) .set('Authorization', `Bearer ${validToken}`);
expect(response.status).not.toBe(200); expect(response.body).not.toContain('password'); } });
test('Powinno zapobiegać atakom XSS', async () => { const xssPayloads = [ '<script>alert("XSS")</script>', '<img src=x onerror=alert("XSS")>', '<svg onload=alert("XSS")>', 'javascript:alert("XSS")', '<iframe src="javascript:alert(\'XSS\')">', ];
for (const payload of xssPayloads) { const response = await request(app) .post('/api/comments') .set('Authorization', `Bearer ${validToken}`) .send({ content: payload });
// Sprawdź, że odpowiedź nie zawiera niezaczyszczonego payload expect(response.text).not.toContain(payload);
// Weryfikuj, że zapisana treść jest oczyszczona const comment = await Comment.findOne().sort({ _id: -1 }); expect(comment.content).not.toContain('<script>'); expect(comment.content).not.toContain('javascript:'); } });
test('Powinno zapobiegać NoSQL injection', async () => { const nosqlPayloads = [ { $ne: null }, { $gt: '' }, { $regex: '.*' }, { $where: 'this.password.length > 0' } ];
for (const payload of nosqlPayloads) { const response = await request(app) .post('/api/auth/login') .send({ email: payload, password: 'password' });
expect(response.status).toBe(400); } }); });
describe('Nagłówki bezpieczeństwa', () => { test('Powinno ustawiać wszystkie nagłówki bezpieczeństwa', async () => { const response = await request(app).get('/');
expect(response.headers['x-content-type-options']).toBe('nosniff'); expect(response.headers['x-frame-options']).toBe('DENY'); expect(response.headers['x-xss-protection']).toBe('1; mode=block'); expect(response.headers['strict-transport-security']).toBeDefined(); expect(response.headers['content-security-policy']).toBeDefined(); expect(response.headers['x-powered-by']).toBeUndefined(); }); });
describe('Bezpieczeństwo API', () => { test('Powinno wymuszać rate limiting', async () => { const requests = Array(150).fill().map(() => request(app).get('/api/data') );
const responses = await Promise.all(requests); const rateLimited = responses.filter(r => r.status === 429);
expect(rateLimited.length).toBeGreaterThan(0); });
test('Powinno bezpiecznie walidować klucze API', async () => { // Test brakującego klucza API const response1 = await request(app) .get('/api/protected') .expect(401);
// Test nieprawidłowego klucza API const response2 = await request(app) .get('/api/protected') .set('X-API-Key', 'invalid-key') .expect(401);
// Test odporności na ataki timing const validKeyTime = await measureApiKeyValidation('valid-key'); const invalidKeyTime = await measureApiKeyValidation('invalid-key');
const timingDifference = Math.abs(validKeyTime - invalidKeyTime); expect(timingDifference).toBeLessThan(5); // Mniej niż 5ms różnicy }); });
describe('Testy fuzzing', () => { test('Powinno gracefully obsługiwać zniekształcone wejście', async () => { const fuzzInputs = [ null, undefined, '', ' ', '\n\r\t', '0'.repeat(10000), '{"a":'.repeat(1000) + '}', Buffer.from([0xFF, 0xFE, 0xFD]), '\x00\x01\x02', '' ];
for (const input of fuzzInputs) { const response = await request(app) .post('/api/data') .send({ data: input }) .set('Authorization', `Bearer ${validToken}`);
// Nie powinno się crashować expect([400, 422]).toContain(response.status); } }); });});
// Narzędzia testowania bezpieczeństwaclass SecurityTester { constructor(app) { this.app = app; }
async runPenetrationTest() { const tests = [ this.testAuthBypass(), this.testPrivilegeEscalation(), this.testDataExposure(), this.testCSRF(), this.testXXE(), this.testSSRF() ];
const results = await Promise.all(tests); return this.generatePenTestReport(results); }
async testCSRF() { // Test ochrony CSRF const response = await request(this.app) .post('/api/user/delete') .set('Cookie', 'sessionId=valid-session') .send({ userId: '123' });
// Powinno się nie powieść bez tokenu CSRF expect(response.status).toBe(403);
// Uzyskaj token CSRF const tokenResponse = await request(this.app) .get('/api/csrf-token') .set('Cookie', 'sessionId=valid-session');
const csrfToken = tokenResponse.body.token;
// Powinno się powieść z tokenem const validResponse = await request(this.app) .post('/api/user/delete') .set('Cookie', 'sessionId=valid-session') .set('X-CSRF-Token', csrfToken) .send({ userId: '123' });
expect(validResponse.status).toBe(200); }}
module.exports = { SecurityTester };
Monitorowanie bezpieczeństwa
Dział zatytułowany „Monitorowanie bezpieczeństwa”Wykrywanie zagrożeń w czasie rzeczywistym
Dział zatytułowany „Wykrywanie zagrożeń w czasie rzeczywistym”> Zaimplementuj monitorowanie bezpieczeństwa w czasie rzeczywistym:> - Wykrywanie intruzów> - Wykrywanie anomalii> - Rozpoznawanie wzorców ataków> - Automatyczna odpowiedź
const EventEmitter = require('events');
class ThreatDetector extends EventEmitter { constructor() { super(); this.patterns = new Map(); this.alerts = []; this.initializePatterns(); }
initializePatterns() { // Wzorce SQL Injection this.patterns.set('sql_injection', [ /(\b(union|select|insert|update|delete|drop|create)\b.*\b(from|where|table)\b)/i, /('|(\')|"|(\"))\s*(or|and)\s*('|(\')|"|(\"))?(\d|[a-z])/i, /\b(exec|execute)\s*\(/i ]);
// Wzorce XSS this.patterns.set('xss', [ /<script[^>]*>.*?<\/script>/gi, /on\w+\s*=\s*["'][^"']+["']/gi, /javascript\s*:/gi ]);
// Wzorce path traversal this.patterns.set('path_traversal', [ /\.\.(\/|\\)/g, /%2e%2e(\/|\\)/gi, /\.\.(;|%3b|%09|%00)/gi ]); }
async analyze(request) { const threats = [];
// Sprawdź wszystkie źródła wejścia const inputs = [ ...Object.values(request.params || {}), ...Object.values(request.query || {}), ...this.flattenObject(request.body || {}), request.path, ...Object.values(request.headers || {}) ];
for (const input of inputs) { if (typeof input !== 'string') continue;
for (const [threatType, patterns] of this.patterns) { for (const pattern of patterns) { if (pattern.test(input)) { threats.push({ type: threatType, input: input.substring(0, 100), pattern: pattern.toString(), timestamp: new Date(), request: { ip: request.ip, path: request.path, method: request.method } }); } } } }
if (threats.length > 0) { this.handleThreats(threats); }
return threats; }
handleThreats(threats) { threats.forEach(threat => { this.emit('threat', threat);
// Loguj zagrożenie logger.security.warn('Wykryto zagrożenie', threat);
// Aktualizuj intelligence zagrożeń this.updateThreatIntelligence(threat);
// Wyzwól automatyczną odpowiedź if (this.shouldAutoRespond(threat)) { this.autoRespond(threat); } }); }
async autoRespond(threat) { switch (threat.type) { case 'sql_injection': case 'xss': // Tymczasowo zablokuj IP await this.blockIP(threat.request.ip, 3600); // 1 godzina break;
case 'path_traversal': // Powiadom zespół bezpieczeństwa await this.alertSecurityTeam(threat); break; } }
flattenObject(obj, prefix = '') { const flattened = [];
for (const [key, value] of Object.entries(obj)) { if (typeof value === 'object' && value !== null) { flattened.push(...this.flattenObject(value, `${prefix}${key}.`)); } else { flattened.push(String(value)); } }
return flattened; }}
// Wykrywanie anomaliiclass AnomalyDetector { constructor() { this.baselines = new Map(); this.anomalies = []; }
async detectAnomalies(metrics) { const anomalies = [];
// Anomalia szybkości żądań const requestRate = metrics.requestsPerMinute; const baseline = await this.getBaseline('request_rate');
if (requestRate > baseline.mean + (3 * baseline.stdDev)) { anomalies.push({ type: 'high_request_rate', value: requestRate, baseline: baseline.mean, severity: 'medium' }); }
// Anomalia nieudanych loginów const failedLogins = metrics.failedLoginsPerHour; const loginBaseline = await this.getBaseline('failed_logins');
if (failedLogins > loginBaseline.mean + (2 * loginBaseline.stdDev)) { anomalies.push({ type: 'suspicious_login_activity', value: failedLogins, baseline: loginBaseline.mean, severity: 'high' }); }
// Anomalia geograficzna const unusualLocations = await this.detectGeographicAnomalies(metrics.accessByCountry); anomalies.push(...unusualLocations);
return anomalies; }
async detectGeographicAnomalies(accessByCountry) { const anomalies = []; const knownCountries = await this.getKnownCountries();
for (const [country, count] of Object.entries(accessByCountry)) { if (!knownCountries.includes(country) && count > 10) { anomalies.push({ type: 'unusual_geographic_access', country, accessCount: count, severity: 'medium' }); } }
return anomalies; }}
module.exports = { ThreatDetector, AnomalyDetector};
Reagowanie na incydenty
Dział zatytułowany „Reagowanie na incydenty”Automatyczne reagowanie na incydenty
Dział zatytułowany „Automatyczne reagowanie na incydenty”> Utwórz system reagowania na incydenty:> - Automatyczne opanowanie> - Zbieranie dowodów> - System powiadomień> - Procedury odzyskiwania
class IncidentResponseSystem { async handleIncident(incident) { const response = { incidentId: this.generateIncidentId(), timestamp: new Date(), type: incident.type, severity: incident.severity, actions: [] };
// Faza 1: Opanowanie const containment = await this.contain(incident); response.actions.push(...containment);
// Faza 2: Zbieranie dowodów const evidence = await this.collectEvidence(incident); response.evidence = evidence;
// Faza 3: Powiadomienie await this.notify(incident, response);
// Faza 4: Odzyskiwanie if (incident.severity === 'critical') { const recovery = await this.recover(incident); response.actions.push(...recovery); }
// Faza 5: Dokumentacja await this.document(response);
return response; }
async contain(incident) { const actions = [];
switch (incident.type) { case 'data_breach': // Cofnij skompromitowane dane uwierzytelniające actions.push(await this.revokeCredentials(incident.affectedUsers));
// Izoluj dotknięte systemy actions.push(await this.isolateSystems(incident.affectedSystems));
// Zablokuj podejrzane IP actions.push(await this.blockIPs(incident.suspiciousIPs)); break;
case 'ddos_attack': // Włącz ochronę DDoS actions.push(await this.enableDDoSProtection());
// Skaluj infrastrukturę actions.push(await this.scaleInfrastructure()); break;
case 'malware_detected': // Poddaj kwarantannie dotknięte pliki actions.push(await this.quarantineFiles(incident.files));
// Przeskanuj wszystkie systemy actions.push(await this.fullSystemScan()); break; }
return actions; }
async collectEvidence(incident) { return { logs: await this.collectLogs(incident.timeRange), networkCapture: await this.captureNetwork(incident.affectedSystems), memoryDump: await this.dumpMemory(incident.affectedSystems), fileSnapshots: await this.snapshotFiles(incident.suspiciousFiles), databaseAudit: await this.auditDatabase(incident.timeRange) }; }
async notify(incident, response) { const notifications = [];
// Powiadomienia wewnętrzne if (incident.severity === 'critical') { notifications.push( this.notifyCISO(incident, response), this.notifySecurityTeam(incident, response), this.notifyLegal(incident, response) ); }
// Powiadomienia zewnętrzne (jeśli wymagane) if (incident.type === 'data_breach' && incident.affectedUsers.length > 0) { notifications.push( this.notifyAffectedUsers(incident), this.notifyRegulators(incident) ); }
await Promise.all(notifications); }
async recover(incident) { const recovery = [];
// Przywróć z kopii zapasowych jeśli potrzeba if (incident.dataCorrupted) { recovery.push(await this.restoreFromBackup(incident.affectedData)); }
// Zresetuj środki bezpieczeństwa recovery.push( await this.rotateSecrets(), await this.updateSecurityRules(), await this.patchVulnerabilities(incident.exploitedVulnerabilities) );
return recovery; }
generateIncidentId() { return `INC-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; }}
// Playbook reagowania na incydentyconst runbooks = { data_breach: { steps: [ 'Zidentyfikuj zakres naruszenia', 'Opanuj dotknięte systemy', 'Zachowaj dowody', 'Oceń ujawnione dane', 'Powiadom interesariuszy', 'Rozpocznij analizę forensiczną', 'Zaimplementuj naprawę', 'Udokumentuj wyciągnięte wnioski' ], contacts: { ciso: 'ciso@company.com', legal: 'legal@company.com', pr: 'pr@company.com' }, timeline: { initial_response: '15 minut', containment: '1 godzina', notification: '4 godziny', full_resolution: '72 godziny' } }};
module.exports = { IncidentResponseSystem, runbooks};
Powiązane lekcje
Dział zatytułowany „Powiązane lekcje”Następne kroki
Dział zatytułowany „Następne kroki”Nauczyłeś się, jak wykorzystać Claude Code do kompleksowego skanowania i ochrony bezpieczeństwa. Kluczem jest traktowanie bezpieczeństwa jako ciągłego procesu, a nie jednorazowego sprawdzenia. Buduj bezpieczeństwo w każdą linię kodu, każde wdrożenie, każdą funkcję.
Pamiętaj: Bezpieczeństwo to odpowiedzialność każdego. Użyj Claude Code, aby uczynić bezpieczeństwo dostępnym i zautomatyzowanym, ale zawsze zachowaj czujność. Najlepsze bezpieczeństwo pochodzi z obrony w głębi - wieloma warstwami współpracującymi, aby chronić Twoją aplikację i użytkowników.