Mục tiêu chương / Learning objectives
- Áp dụng secure coding standards (CERT C, OWASP Secure Coding Practices, MISRA) vào code review.
- Thực hiện input validation đúng cách: allowlist vs denylist, canonicalization, type checking.
- Áp dụng output encoding phù hợp ngữ cảnh: HTML, JS, CSS, URL, SQL.
- Phòng chống injection attacks: SQL, NoSQL, LDAP, XML, OS command injection.
- Hiểu memory management security: buffer overflow, use-after-free, integer overflow prevention.
- Triển khai secrets management đúng cách: env vars, vaults — không bao giờ hardcode trong source.
1. Lý thuyết cốt lõi / Core theory
1.1. Secure Coding Standards (CERT / OWASP / MISRA)
CERT Secure Coding Standards: bộ rules cho C/C++, Java, Python — phân loại theo severity (L1-L3) và remediation cost. Ví dụ CERT C Rule ERR34-C: "Detect errors when converting a string to a number" — phòng tránh undefined behavior khi dùng atoi() thay vì strtol(). OWASP Secure Coding Practices: checklist 13 categories (Input Validation, Output Encoding, Authentication, Session Management, Access Control, Cryptography, Error Handling, Data Protection, Communication Security, System Configuration, Database Security, File Management, Memory Management). MISRA C/C++: guidelines cho safety-critical systems (automotive, aviation) — prohibit undefined behavior, restrict dynamic memory allocation.
Secure coding là về defaults: Secure defaults nghĩa là code phải làm thêm thao tác để trở nên insecure. Ví dụ: parameterized query là default trong ORM — developer phải chủ động gọi raw query method mới có thể SQL inject. Ngược lại, string concatenation là insecure default — developer phải cố ý dùng parameterized để an toàn.
1.2. Input Validation & Output Encoding (Validation vs Encoding)
Input validation: validate ở server-side (client-side chỉ là UX, không phải security); dùng allowlist (whitelist) thay vì denylist (blacklist) — chấp nhận những gì biết là tốt, từ chối phần còn lại; canonicalization trước khi validate — normalize encoding (URL decode, Unicode normalization) để tránh bypass: ../ vs %2E%2E%2F vs ..%c0%af đều là path traversal; type checking + range checking + length checking.
Output encoding — encode đúng ngữ cảnh (context-aware encoding): HTML context → HTML entity encoding (< → <); JS context → JavaScript encoding; URL context → percent encoding; SQL context → parameterized queries (không encode, mà tách data khỏi query structure); LDAP → LDAP escape. Dùng thư viện chuẩn: OWASP Java Encoder, AntiXSS (.NET), DOMPurify (JS).
1.3. Injection Prevention Deep Dive (SQL / NoSQL / LDAP / XML / OS Command)
SQL injection: Parameterized queries / prepared statements là giải pháp duy nhất tin cậy. Stored procedures không đủ nếu vẫn dùng dynamic SQL bên trong. ORM không đủ nếu dùng raw query methods. NoSQL injection: MongoDB vulnerable khi nhận JSON input trực tiếp vào query operator ($where, $gt). Validate schema input với Joi/Zod. LDAP injection: escape special chars: ( ) * \ NUL. XML injection/XXE: disable external entity processing (DTD) trong XML parser — XXE (XML External Entity) có thể đọc /etc/passwd hoặc SSRF. OS command injection: không truyền user input vào shell command — dùng API trực tiếp thay vì shell (ví dụ: dùng subprocess(['ping', hostname]) với shell=False thay vì xây dựng command string).
1.4. Memory Management & Error Handling (Memory Safety & Secure Logging)
Memory safety (C/C++): buffer overflow — luôn kiểm tra bounds trước khi write; use-after-free — dùng smart pointers (std::unique_ptr, std::shared_ptr); integer overflow — kiểm tra trước khi cộng, dùng safe integer libraries; format string — không bao giờ dùng printf(user_input), luôn printf("%s", user_input). Ngôn ngữ memory-safe (Rust, Go, Java, Python) eliminates nhiều classes này nhưng vẫn có logic bugs.
Secure error handling: không trả về stack traces, exception details, internal paths, DB error messages cho client — attacker dùng để enumerate hệ thống; log đủ thông tin ở server-side (request ID, user ID, timestamp, action, result) nhưng không log passwords, session tokens, PII; log injection — sanitize user input trước khi log (attacker có thể inject fake log entries bằng newline characters).
1.5. Secrets Management & Dependency Security (Secrets & Dependencies)
Secrets management: KHÔNG bao giờ hardcode secrets trong source code — git history là permanent, ngay cả khi xóa file sau đó; dùng environment variables (cho simple cases), secret managers (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager) cho production; .gitignore file .env nhưng commit .env.example với placeholder values; scan pre-commit với TruffleHog, git-secrets, detect-secrets. Dependency pinning: pin exact versions trong lockfiles (package-lock.json, Pipfile.lock, go.sum) — floating versions (^1.2.3) có thể pull malicious update; review lockfile changes trong PRs.
2. Bài thực hành / Hands-on labs
Lab 1 — Secret Detection trong Git History (PowerShell)
OS: Windows 11 · Tool: PowerShell 7 + TruffleHog (hoặc regex scan).
# Scan codebase tìm hardcoded secrets bằng regex patterns
Write-Host "=== Secret Detection Scan ===" -ForegroundColor Yellow
# Pattern phổ biến cho secrets bị lộ
$patterns = @(
'[A-Za-z0-9+/]{40,}={0,2}', # Base64-encoded secrets (40+ chars)
'AKIA[0-9A-Z]{16}', # AWS Access Key ID
'ghp_[A-Za-z0-9]{36}', # GitHub Personal Access Token
'sk-[A-Za-z0-9]{48}', # OpenAI API Key
'xox[baprs]-[0-9A-Za-z-]+', # Slack token
'password\s*[:=]\s*[''"][^''"]{8,}[''"]' # Literal password assignment
)
$patternStr = ($patterns | ForEach-Object { "($_)" }) -join '|'
Get-ChildItem -Recurse -Include *.cs,*.py,*.js,*.ts,*.env,*.yaml,*.yml,*.json `
-Exclude *.lock,node_modules -ErrorAction SilentlyContinue |
Select-String -Pattern $patternStr |
Select-Object Path, LineNumber, Line |
Select-Object -First 15 |
Format-Table -Wrap -AutoSize
# Kiểm tra xem có .env files bị track trong git không (nguy hiểm!)
Write-Host "`n=== Checking .env files in git ===" -ForegroundColor Cyan
$gitTracked = git ls-files --error-unmatch .env 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Warning ".env is tracked by git! Run: git rm --cached .env"
} else {
Write-Host ".env is NOT tracked by git — OK" -ForegroundColor Green
}
# TruffleHog scan (nếu đã cài)
Write-Host "`n=== TruffleHog scan (nếu đã cài) ===" -ForegroundColor Cyan
if (Get-Command trufflehog -ErrorAction SilentlyContinue) {
trufflehog filesystem . --json 2>/dev/null | ConvertFrom-Json |
Select-Object -First 5 | Format-List SourceMetadata, DetectorName
} else {
Write-Host "Install: pip install trufflehog hoặc winget install TruffleHog" -ForegroundColor Gray
}
✅ Kết quả mong đợi / Expected output: Scan liệt kê files và lines có secret patterns. AWS keys (AKIA...) và GitHub tokens (ghp_...) được highlight. .env check xác nhận không bị track trong git. TruffleHog (nếu cài) scan cả git history — tìm secrets đã từng commit rồi xóa. Bài học: một khi secret được push lên remote repo, phải coi là compromised — rotate ngay lập tức.
Lab 2 — Static Analysis với Bandit (Python Security) (Bash)
OS: Ubuntu 22.04 · Tool: Bash + Bandit (Python SAST).
# Cài Bandit — Python SAST tool
pip install bandit 2>/dev/null
# Tạo file Python với các vấn đề bảo mật phổ biến để phân tích
mkdir -p /tmp/bandit-demo
cat > /tmp/bandit-demo/insecure_patterns.py << 'PYEOF'
import hashlib, yaml, xml.etree.ElementTree as ET, tempfile, random
# B303: MD5 use (weak hashing)
def hash_data(data):
return hashlib.md5(data.encode()).hexdigest()
# B506: yaml.load without Loader (unsafe deserialization)
def parse_config(yaml_string):
return yaml.load(yaml_string) # should be yaml.safe_load
# B320: xml.etree allows XXE in some contexts — use defusedxml
def parse_xml(xml_string):
return ET.fromstring(xml_string)
# B311: Standard random — not cryptographically secure
def generate_token():
return str(random.randint(100000, 999999))
# B108: Insecure temp file
def write_temp(data):
f = tempfile.mktemp() # race condition risk; use mkstemp
with open(f, 'w') as fp:
fp.write(data)
return f
# Secure alternatives (for reference — not flagged by Bandit)
import secrets, hashlib
def generate_token_secure():
return secrets.token_hex(32)
def hash_data_secure(data):
return hashlib.sha256(data.encode()).hexdigest()
PYEOF
# Chạy Bandit với tất cả severity levels
echo "=== Bandit SAST Analysis ==="
bandit -r /tmp/bandit-demo/ -ll 2>/dev/null | head -40
# Xuất kết quả JSON để integrate với CI/CD
bandit -r /tmp/bandit-demo/ -f json 2>/dev/null | python3 -c "
import json, sys
data = json.load(sys.stdin)
results = data.get('results', [])
print(f'Total issues: {len(results)}')
for r in results[:6]:
print(f' [{r[\"issue_severity\"]}] {r[\"test_id\"]}: {r[\"issue_text\"][:60]}')
print(f' File: {r[\"filename\"]}:{r[\"line_number\"]}')
" 2>/dev/null
✅ Kết quả mong đợi / Expected output: Bandit phát hiện: B303 (MD5 weak hash, MEDIUM severity), B506 (yaml.load unsafe, HIGH severity), B311 (random not secure, LOW severity), B108 (insecure temp file). JSON output có thể pipe vào CI/CD pipeline để fail build khi có HIGH/CRITICAL findings. Secure versions (secrets.token_hex, sha256) không bị flag.
3. Tình huống doanh nghiệp / Real-world scenario
Bối cảnh:
Một developer push code chứa AWS access key lên GitHub public repo. 4 phút sau, bot của attacker tự động detect và bắt đầu spin up EC2 instances để mine crypto — bill AWS lên $50,000 trong 2 giờ.
Ngăn chặn và xử lý:
- Ngăn chặn: Pre-commit hook với detect-secrets:
detect-secrets scan --baseline .secrets.baseline— block commit nếu phát hiện secret pattern. - Phát hiện: GitHub Advanced Security (Secret Scanning) tự động alert khi AWS key được push — thường trong vòng giây.
- Response: Rotate key ngay lập tức trong AWS IAM Console → Deactivate old key → Tạo key mới → Update secret manager. Coi key cũ là compromised vĩnh viễn.
- Purge từ git history:
git filter-repo --path secrets.py --invert-pathsđể xóa file khỏi toàn bộ history, sau đó force-push (cần coordination với team). - Phòng ngừa lâu dài: IAM role thay vì access keys cho EC2/Lambda; Secrets Manager cho apps; SCPs (Service Control Policies) giới hạn regions được phép tạo resources.
Bài học: bots scan GitHub liên tục trong thời gian thực — không có "chỉ public 1 phút rồi xóa". Phòng ngừa qua pre-commit hooks là giải pháp duy nhất hiệu quả.
4. Tự kiểm tra / Knowledge check
- Phân biệt allowlist và denylist validation. Khi nào dùng allowlist không khả thi và giải pháp thay thế?
- Output encoding "context-aware" nghĩa là gì? Cho ví dụ encoding khác nhau cho HTML vs JavaScript context.
- XXE (XML External Entity) attack hoạt động như thế nào? Cách mitigate trong Java và Python?
- Tại sao
random.randint()trong Python không an toàn cho token generation? Module nào nên dùng? - Log injection attack là gì? Developer cần làm gì trước khi log user-supplied data?