Chuyển đến nội dung chính

Bài 13: OWASP Top 10 (2025) — Phân tích Chi tiết

OWASP Top 10 phiên bản mới nhất, từng category kèm demo khai thác thực tế và cách phòng chống.

🔒 DevSecOps — Bài 13 Bài 13: OWASP Top 10 (2025) — Phân tích Chi tiết

Performance Testing & Pentest: Quy trình Chuẩn Doanh nghiệp 2026

Phần 3: Pentest Foundations — Quy trình và Phương pháp luận

xdev.asia

1. OWASP Top 10 — Tổng quan

OWASP Top 10 là danh sách 10 rủi ro bảo mật ứng dụng web phổ biến nhất, được cập nhật dựa trên dữ liệu thực tế từ hàng nghìn tổ chức trên toàn cầu.

OWASP Top 10 (2025 Edition):

 #  │ Category                               │ Severity
────┼────────────────────────────────────────┼──────────
 A01│ Broken Access Control                  │ Critical
 A02│ Cryptographic Failures                 │ High
 A03│ Injection                              │ Critical
 A04│ Insecure Design                        │ High
 A05│ Security Misconfiguration              │ High
 A06│ Vulnerable & Outdated Components       │ High
 A07│ Identification & Authentication Fail   │ Critical
 A08│ Software & Data Integrity Failures     │ High
 A09│ Security Logging & Monitoring Failures │ Medium
 A10│ Server-Side Request Forgery (SSRF)     │ High

2. A01: Broken Access Control

Loại tấn công phổ biến:
  ├── IDOR (Insecure Direct Object Reference)
  ├── Privilege Escalation (vertical/horizontal)
  ├── Missing Function Level Access Control
  ├── CORS misconfiguration
  └── JWT manipulation
# IDOR Example — Vulnerable code
@app.get("/api/users/{user_id}/profile")
def get_profile(user_id: int):
    # ❌ No authorization check — any user can view any profile
    return db.query(User).filter(User.id == user_id).first()

# ✅ Fixed — Check authorization
@app.get("/api/users/{user_id}/profile")
def get_profile(user_id: int, current_user: User = Depends(get_current_user)):
    if current_user.id != user_id and not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Forbidden")
    return db.query(User).filter(User.id == user_id).first()
# Testing IDOR with curl
# Login as user A, get token
TOKEN_A="eyJhbGc..."

# Try to access user B's data with user A's token
curl -H "Authorization: Bearer $TOKEN_A" \
  https://api.example.com/api/users/999/profile

# If 200 OK → IDOR vulnerability confirmed

3. A02: Cryptographic Failures

Common failures:
  ├── Hardcoded secrets in source code
  ├── Weak algorithms (MD5, SHA1, DES)
  ├── Missing TLS / using TLS 1.0-1.1
  ├── Sensitive data in logs
  └── Weak key generation
# ❌ Vulnerable — MD5 for password hashing
import hashlib
password_hash = hashlib.md5(password.encode()).hexdigest()

# ✅ Secure — bcrypt with cost factor
import bcrypt
password_hash = bcrypt.hashpw(
    password.encode('utf-8'),
    bcrypt.gensalt(rounds=12)
)
# Test TLS configuration
# testssl.sh — comprehensive TLS scanner
./testssl.sh --severity HIGH https://example.com

# Check certificate
openssl s_client -connect example.com:443 2>/dev/null | \
  openssl x509 -noout -dates -subject -issuer

# Scan for weak ciphers
nmap --script ssl-enum-ciphers -p 443 example.com

4. A03: Injection

Injection Types:
  ├── SQL Injection (SQLi)
  ├── NoSQL Injection
  ├── OS Command Injection
  ├── LDAP Injection
  ├── Template Injection (SSTI)
  └── Expression Language Injection
# ❌ SQL Injection — Vulnerable
@app.get("/search")
def search(q: str):
    query = f"SELECT * FROM products WHERE name LIKE '%{q}%'"
    return db.execute(text(query)).fetchall()
    # Input: ' OR '1'='1' --
    # Result: Returns ALL products

# ✅ Parameterized query — Secure
@app.get("/search")
def search(q: str):
    query = text("SELECT * FROM products WHERE name LIKE :search")
    return db.execute(query, {"search": f"%{q}%"}).fetchall()
# SQLMap — Automated SQL Injection testing
sqlmap -u "https://example.com/search?q=test" \
  --batch --level=3 --risk=2 \
  --dbs --tables \
  --output-dir=./sqlmap_results

# Manual testing payloads
# ' OR 1=1 --
# ' UNION SELECT null,null,null --
# '; DROP TABLE users; --
# ' AND SLEEP(5) --   (time-based blind)

5. A04: Insecure Design

Insecure Design Examples:
  ├── Missing rate limiting on password reset
  ├── Security questions as only recovery method
  ├── No re-authentication for sensitive actions
  ├── Predictable resource locations
  └── Missing business logic validation

Secure Design Principles:
  ├── Defense in Depth
  ├── Least Privilege
  ├── Fail Secure (not fail open)
  ├── Separation of Duties
  ├── Zero Trust Architecture
  └── Threat Modeling from design phase
# ❌ Insecure Design — No rate limiting on OTP
@app.post("/verify-otp")
def verify_otp(phone: str, otp: str):
    # Attacker can brute-force 4-digit OTP (0000-9999)
    if db.get_otp(phone) == otp:
        return {"status": "verified"}

# ✅ Secure Design — Rate limit + lockout + expiry
@app.post("/verify-otp")
@rate_limit(max_attempts=5, window_seconds=300)
def verify_otp(phone: str, otp: str, request: Request):
    stored = db.get_otp(phone)
    if not stored or stored.expired:
        raise HTTPException(400, "OTP expired")
    if stored.attempts >= 5:
        db.invalidate_otp(phone)
        raise HTTPException(429, "Too many attempts")
    if not hmac.compare_digest(stored.code, otp):
        db.increment_otp_attempts(phone)
        raise HTTPException(400, "Invalid OTP")
    db.invalidate_otp(phone)
    return {"status": "verified"}

6. A05: Security Misconfiguration

# Common misconfigurations to check

# 1. Default credentials
hydra -l admin -P /usr/share/wordlists/common.txt \
  https://example.com/admin http-post-form \
  "/login:user=^USER^&pass=^PASS^:Invalid"

# 2. Directory listing
curl -s https://example.com/ | grep "Index of"

# 3. Unnecessary HTTP methods
curl -X OPTIONS https://example.com -i
# Check for PUT, DELETE, TRACE

# 4. Debug mode in production
curl https://example.com/debug
curl https://example.com/actuator/env  # Spring Boot
curl https://example.com/phpinfo.php

# 5. Security headers check
curl -sI https://example.com | grep -iE \
  "strict-transport|x-frame|x-content-type|content-security|referrer-policy"

# Expected headers:
# Strict-Transport-Security: max-age=31536000; includeSubDomains
# X-Frame-Options: DENY
# X-Content-Type-Options: nosniff
# Content-Security-Policy: default-src 'self'
# Referrer-Policy: strict-origin-when-cross-origin

7. A06-A07: Components & Authentication

# A06: Vulnerable Components
# Check npm dependencies
npm audit --audit-level=high
npx better-npm-audit audit

# Check Python dependencies
pip-audit
safety check

# Scan container images
trivy image myapp:latest --severity HIGH,CRITICAL

# Dependency-Track — SBOM analysis
# Upload SBOM (CycloneDX format)
cyclonedx-npm --output-format json > sbom.json
A07: Authentication Failures:
  ├── Credential stuffing (leaked password databases)
  ├── Brute force (no lockout/rate limiting)
  ├── Default credentials
  ├── Weak password policy
  ├── Session fixation
  ├── Missing MFA on critical functions
  └── JWT implementation flaws
       ├── Algorithm confusion (none, HS256 vs RS256)
       ├── Missing expiration
       └── Weak signing key
# JWT Algorithm Confusion Attack
import jwt

# ❌ Vulnerable — accepts 'none' algorithm
token = jwt.decode(token_string, options={"verify_signature": False})

# ✅ Secure — explicitly specify algorithm
token = jwt.decode(
    token_string,
    key=PUBLIC_KEY,
    algorithms=["RS256"],  # Whitelist allowed algorithms
    options={"require": ["exp", "iss", "sub"]}
)

8. A08-A10: Integrity, Logging, SSRF

A08: Software & Data Integrity Failures:
  ├── Insecure deserialization
  ├── CI/CD pipeline compromise
  ├── Unsigned software updates
  ├── Supply chain attacks
  └── Integrity verification missing

A09: Security Logging & Monitoring:
  ├── Missing audit logs for auth events
  ├── Logs not centralized
  ├── No alerting on suspicious activity
  ├── Log injection vulnerabilities
  └── Insufficient log retention
# A10: SSRF — Server-Side Request Forgery
# ❌ Vulnerable — user controls URL
@app.post("/fetch-url")
def fetch_url(url: str):
    response = requests.get(url)  # Attacker: url=http://169.254.169.254/latest/meta-data/
    return response.text

# ✅ Secure — URL validation + allowlist
import ipaddress
from urllib.parse import urlparse

ALLOWED_DOMAINS = {"api.trusted.com", "cdn.example.com"}

@app.post("/fetch-url")
def fetch_url(url: str):
    parsed = urlparse(url)
    
    # Block internal IPs
    try:
        ip = ipaddress.ip_address(parsed.hostname)
        if ip.is_private or ip.is_loopback or ip.is_link_local:
            raise HTTPException(400, "Internal addresses blocked")
    except ValueError:
        pass  # hostname, not IP
    
    # Domain allowlist
    if parsed.hostname not in ALLOWED_DOMAINS:
        raise HTTPException(400, "Domain not allowed")
    
    if parsed.scheme not in ("https",):
        raise HTTPException(400, "Only HTTPS allowed")
    
    response = requests.get(url, timeout=5, allow_redirects=False)
    return response.text

9. OWASP Testing Checklist

Pentest Checklist theo OWASP:

□ A01: Test IDOR on all API endpoints
□ A01: Test horizontal & vertical privilege escalation
□ A01: Test CORS configuration
□ A02: Check TLS version and cipher suites
□ A02: Scan for hardcoded secrets (git-secrets, trufflehog)
□ A03: Test all input fields for SQLi, XSS, Command injection
□ A04: Review business logic for design flaws
□ A05: Check security headers, error handling, debug endpoints
□ A06: Run dependency audit (npm audit, pip-audit, trivy)
□ A07: Test authentication bypass, session management
□ A08: Check CI/CD pipeline security, dependency integrity
□ A09: Verify logging of security events
□ A10: Test SSRF on URL input parameters

10. Tổng kết

  • A01 Broken Access Control: #1 risk — test IDOR, privilege escalation
  • A03 Injection: Parameterized queries, input validation
  • A05 Misconfiguration: Security headers, debug endpoints, defaults
  • A07 Authentication: MFA, rate limiting, JWT security
  • A10 SSRF: URL validation, IP blocking, domain allowlist

Bài tiếp theo sẽ thực hành Reconnaissance và Scanning với Nmap, Amass, Nuclei.