Przejdź do głównej zawartości

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.

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.

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
> 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:

  1. Wykrywanie SQL Injection

    // ZNALEZIONO KOD PODATNY
    app.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ĄPIENIE
    app.get('/user/:id', async (req, res) => {
    const userId = req.params.id;
    // ✅ Walidacja wejścia
    if (!/^\d+$/.test(userId)) {
    return res.status(400).json({ error: 'Invalid user ID' });
    }
    // ✅ Zapytanie sparametryzowane
    const query = 'SELECT * FROM users WHERE id = $1';
    const result = await db.query(query, [userId]);
    // ✅ Nie ujawniaj wrażliwych pól
    const { password_hash, ...safeUser } = result.rows[0] || {};
    res.json(safeUser);
    });
  2. Zapobieganie Cross-Site Scripting (XSS)

    // ZNALEZIONO KOD PODATNY
    app.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ĄPIENIE
    const DOMPurify = require('isomorphic-dompurify');
    const { JSDOM } = require('jsdom');
    app.post('/comment', (req, res) => {
    const comment = req.body.comment;
    // ✅ Oczyść wejście HTML
    const 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 Policy
    res.setHeader(
    'Content-Security-Policy',
    "default-src 'self'; script-src 'self' 'nonce-${nonce}'"
    );
    const html = `<div class="comment">${clean}</div>`;
    saveCommentHTML(html);
    });
  3. Uwierzytelnianie i autoryzacja

    // ZNALEZIONO KOD PODATNY
    app.post('/admin/users', (req, res) => {
    // ❌ Brak sprawdzenia uwierzytelniania!
    updateUsers(req.body);
    res.json({ success: true });
    });
    // BEZPIECZNE ZASTĄPIENIE
    const jwt = require('jsonwebtoken');
    const bcrypt = require('bcrypt');
    // Middleware uwierzytelniania
    const 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 autoryzacji
    const 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 & authz
    app.post('/admin/users',
    authenticate,
    authorize('admin', 'superadmin'),
    async (req, res) => {
    // Dodatkowa walidacja
    const { error } = validateUserUpdate(req.body);
    if (error) {
    return res.status(400).json({ error: error.details[0].message });
    }
    await updateUsers(req.body);
    // Logowanie audytu
    await auditLog({
    action: 'UPDATE_USERS',
    userId: req.user.id,
    changes: req.body,
    ip: req.ip
    });
    res.json({ success: true });
    }
    );
  4. Bezpieczeństwo kryptograficzne

    // ZNALEZIONO KOD PODATNY
    const 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 algorytm
    const key = '1234567890123456';
    const cipher = crypto.createCipher('aes-128-ecb', key);
    return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
    }
    // BEZPIECZNE ZASTĄPIENIE
    const bcrypt = require('bcrypt');
    const argon2 = require('argon2');
    // ✅ Silne haszowanie hasła
    async 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 szyfrowanie
    async 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')
    };
    }
> Zaimplementuj kompleksową walidację wejścia:
> - Walidacja request body
> - Oczyszczanie parametrów zapytania
> - Bezpieczeństwo przesyłania plików
> - Rate limiting
> - Limity rozmiaru żądań
validation.js
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ów
const 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 walidacji
const 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ństwa
const 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ów
const 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
};
> Skonfiguruj automatyczne skanowanie luk zależności:
> - Sprawdź znane CVE
> - Zidentyfikuj przestarzałe pakiety
> - Zasugeruj bezpieczne alternatywy
> - Utwórz strategię aktualizacji
security-scan.js
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 poprawek
class 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/CD
module.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
`
};
> Zaimplementuj wzorce bezpiecznego kodowania dla naszej aplikacji:
> - Bezpieczne zarządzanie sesjami
> - Ochrona CSRF
> - Nagłówki bezpieczeństwa
> - Bezpieczna obsługa cookies
> - Bezpieczeństwo API
security-patterns.js
const session = require('express-session');
const MongoStore = require('connect-mongo');
const csrf = require('csurf');
const crypto = require('crypto');
// Bezpieczna konfiguracja sesji
const 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 CSRF
const csrfProtection = csrf({
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict'
}
});
// Middleware bezpieczeństwa API
class 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ów
const 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ów
const 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 Policy
class 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
};
> Zaimplementuj standardy bezpieczeństwa OWASP:
> - Ochrona OWASP Top 10
> - Logowanie bezpieczeństwa
> - Ścieżki audytu
> - Raportowanie zgodności
owasp-compliance.js
const winston = require('winston');
const { ElasticsearchTransport } = require('winston-elasticsearch');
// Logger zdarzeń bezpieczeństwa
class 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 audytu
class 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ści
class 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
};
> Utwórz kompleksowy zestaw testów bezpieczeństwa:
> - Testy penetracyjne
> - Fuzzing
> - Testy regresji bezpieczeństwa
> - Walidacja zgodności
security-tests.spec.js
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ństwa
class 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 };
> Zaimplementuj monitorowanie bezpieczeństwa w czasie rzeczywistym:
> - Wykrywanie intruzów
> - Wykrywanie anomalii
> - Rozpoznawanie wzorców ataków
> - Automatyczna odpowiedź
threat-detection.js
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 anomalii
class 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
};
> Utwórz system reagowania na incydenty:
> - Automatyczne opanowanie
> - Zbieranie dowodów
> - System powiadomień
> - Procedury odzyskiwania
incident-response.js
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 incydenty
const 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
};

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.