標題
二零二六年之API安全:毀滅生產系統之攻擊
標籤
安全,API,網絡開發,編程,後端,開發者安全運營
內容
二零二六年之API安全:真實毀滅生產系統之攻擊
每岁一周,有公司告其数据泄露。攻者非用零日或诡谲之毒,实乃利用旧岁已存之API漏洞。至二六年间,API安全犹为众团队所忽,而攻者知之。
吾昔半载,究析世实API之溃。此乃实击生产系统者。
OWASP API Top 10 未变(行业应对亦然)
OWASP API Security Top 10 貌似与 2019 年无甚异:
- 碎物层级授权 (Broken Object Level Authorization)
- 认证破损
- 碎物产权级授权
- 无节制之资源消耗
- 破损功能层级授权
- 批量赋值
- 安全配置不当
- 注入攻击
- 库存管理失当
- API不安全使用
此非空谈。十八月内,皆已见诸重大事件中遭利用。
攻击之壹:BOLA — 潜行数据窃取者
残缺之物授权,为数据泄露之患最甚。其弊常如一辙:API之端点暴露物之标识,而API不验其认证者果否为该物之主。
实例(简自实患)
// VULNERABLE API
app.get('/api/orders/:orderId', authMiddleware, async (req, res) => {
const order = await Order.findById(req.params.orderId);
res.json(order); // No ownership check!
});
// ATTACK: Iterate through order IDs
// curl https://api.example.com/api/orders/1
// curl https://api.example.com/api/orders/2
// curl https://api.example.com/api/orders/3
// ... extracted 50,000 customer records
如何革之
// SECURE API
app.get('/api/orders/:orderId', authMiddleware, async (req, res) => {
// Explicit ownership check
const order = await Order.findOne({
_id: req.params.orderId,
userId: req.user.id // Always filter by owner
});
if (!order) {
return res.status(404).json({
error: 'Order not found'
});
}
res.json(order);
});
要义所在:恒验权属,非独验认证。认证非即授权于是物也
攻击之二者:认证有缺——JWT之失
JSON Web Tokens 普遍存在,且常被错误实现。此乃吾于生产API中所发现之JWT真实漏洞之例。
弱点:算法混淆
// VULNERABLE: Server accepts any algorithm
const decoded = jwt.verify(token, publicKey, {
algorithms: ['HS256', 'RS256'] // DON'T DO THIS
});
// ATTACK: Change RS256 to HS256 and sign with the public key
// Since the server uses the SAME key for both symmetric and asymmetric,
// the attacker can forge tokens by signing HS256 with the RSA public key
// SECURE: Explicit algorithm allowlist
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'] // Only allow the intended algorithm
});
无缺隙:无算法
// VULNERABLE: Some libraries accept 'none' algorithm
jwt.verify(token, '', { algorithms: ['none'] });
// Produces: {"alg":"none","typ":"JWT"}
// becomes: eyJhbGciOiJub25lIiwidHlwIjoiand0In0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
// SECURE: Explicitly reject 'none'
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
alloweds: { algorithms: ['HS256', 'RS256'] } // Reject none
});
// Or use a library that defaults to rejecting 'none'
const decoded = jwt.verify(token, publicKey);
攻击之三者:无节制资源消耗——钱包之拒
此术常被轻视,渐成常态。攻击者无需使汝之服务崩坏,但需令其运行昂贵即可.
现实之境
# VULNERABLE: No pagination, no limits
@app.get("/api/search")
def search(q: str):
results = db.query(f"SELECT * FROM products WHERE name LIKE '%{q}%'")
return results # Returns ALL matches, attacker controls result set size
# Attack: Search for "a" - returns 2.3M rows
# Your database does a full table scan
# You pay $0.02 per query × 10,000 queries/minute = $200/minute
# SECURE: Strict pagination and query limits
@app.get("/api/search")
def search(
q: str,
limit: int = Query(default=20, ge=1, le=100), # Max 100
offset: int = Query(default=0, ge=0, le=10000) # Max offset
):
# Parameterized query prevents injection
results = db.query(
"SELECT * FROM products WHERE name LIKE %s LIMIT %s OFFSET %s",
(f"%{q}%", limit, offset)
)
# Also add query complexity limits
if len(q) > 100:
raise HTTPException(400, "Query too long")
return results
密码重置拒绝服务攻击
# VULNERABLE: Email sending has no rate limit
@app.post("/api/password-reset")
def request_reset(email: str):
user = db.find_user(email)
if user:
send_email(user.email, generate_token()) # No throttle
return {"message": "If email exists, reset was sent"}
# Attack: Script 1000 emails/second to your SMTP provider
# Cost: $0.10 per email × 86,400,000 emails/day = $8.6M/day
# SECURE: Strict rate limiting per IP and email
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.post("/api/password-reset")
@limiter.limit("3/hour") # 3 attempts per hour per IP
def request_reset(email: str, request: Request):
user = db.find_user(email)
if user:
send_email(user.email, generate_token())
# Always return same message to prevent enumeration
return {"message": "If email exists, reset was sent"}
攻击之四:批量赋值——隐秘参数
// VULNERABLE: Trusting client input blindly
app.post('/api/profile', authMiddleware, async (req, res) => {
await User.updateOne(
{ _id: req.user.id },
{ $set: req.body } // Client can set ANY field
);
});
// ATTACK: Send this request
// POST /api/profile
// {"name": "John", "role": "admin", "isVerified": true, "creditLimit": 1000000}
//
// Suddenly the regular user is an admin with unlimited credit
// SECURE: Explicit field allowlist
app.post('/api/profile', authMiddleware, async (req, res) => {
const allowedFields = ['name', 'bio', 'avatarUrl', 'timezone'];
const updates = {};
for (const field of allowedFields) {
if (field in req.body) {
updates[field] = req.body[field];
}
}
await User.updateOne(
{ _id: req.user.id },
{ $set: updates }
);
res.json({ success: true });
});
攻击之五:无防护之管理员端点
# VULNERABLE: Admin endpoint without role check
@app.post("/api/admin/users/delete")
def delete_user(user_id: str):
db.delete_user(user_id)
return {"success": True}
# Attack: Anyone who finds this endpoint can delete any user
# No authentication, no authorization check
# SECURE: Explicit role requirement
from functools import wraps
def require_admin(f):
@wraps(f)
async def decorated(*args, **kwargs):
if not request.user or request.user.role != 'admin':
return {"error": "Forbidden"}, 403
return await f(*args, **kwargs)
return decorated
@app.post("/api/admin/users/delete")
@require_admin
@require_auth
def delete_user(user_id: str):
db.delete_user(user_id)
return {"success": True}
测试之框架,汝当用之
import httpx
import pytest
class TestAPISecurity:
"""API Security Test Suite - Run these against staging before every deploy"""
def test_bola_object_level_access(self):
"""Test that users can't access other users' resources"""
user1_token = self.get_token("user1@example.com")
user2_resource = self.create_resource("user2@example.com")
# User 1 tries to access User 2's resource
response = httpx.get(
f"{BASE_URL}/api/resources/{user2_resource.id}",
headers={"Authorization": f"Bearer {user1_token}"}
)
assert response.status_code == 403, "BOLA vulnerability: User can access others' resources!"
def test_jwt_algorithm_confusion(self):
"""Test JWT algorithm confusion attack"""
token = self.get_valid_token()
# Tamper with the algorithm
header_b64 = base64.b64encode(b'{"alg":"HS256","typ":"JWT"}').decode()
# Re-sign with a known key
tampered = f"{header_b64}.{token.split('.')[1]}.{fake_signature}"
response = httpx.get(
f"{BASE_URL}/api/protected",
headers={"Authorization": f"Bearer {tampered}"}
)
assert response.status_code == 401, "JWT algorithm confusion succeeded!"
def test_mass_assignment_protection(self):
"""Test that users can't set admin fields"""
user_token = self.get_token("regular@example.com")
response = httpx.post(
f"{BASE_URL}/api/profile",
headers={"Authorization": f"Bearer {user_token}"},
json={"name": "Test", "role": "admin", "isVerified": True}
)
# Verify admin fields weren't changed
profile = self.get_profile("regular@example.com")
assert profile["role"] != "admin", "Mass assignment vulnerability!"
def test_rate_limiting(self):
"""Test that rate limiting prevents abuse"""
for _ in range(100):
response = httpx.post(
f"{BASE_URL}/api/password-reset",
json={"email": "test@example.com"}
)
# 101st request should be rate limited
response = httpx.post(
f"{BASE_URL}/api/password-reset",
json={"email": "test@example.com"}
)
assert response.status_code == 429, "Rate limiting not enforced!"
部署之前之安全检点
□ Object-level authorization tested for every endpoint
□ All JWT implementations use explicit algorithm allowlists
□ Rate limiting on all public endpoints
□ Pagination limits on all list endpoints
□ Mass assignment protection via field allowlists
□ Admin endpoints protected by role checks
□ No sensitive data in URL parameters (tokens, IDs)
□ SQL injection protection (parameterized queries)
□ No stack traces or internal errors in responses
□ CORS properly configured
□ Security headers present (CSP, X-Frame-Options, etc.)
严酷之实情
二零二六年,API安全犹滞于应用安全数载。众团队多然:
- 无API安全测试于CI/CD
- 无API清单(汝有多少端点?汝竟不知耶?)
- 八成端点无速率限制
- 认证无授权之检
攻者知此。彼等规模化扫描此等弱点,自动化,昼夜不息。
佳音:治之非难。惟需将安测试尊为开发之要务耳。
汝之最大API安全之困也?于江湖间尝得有趣之漏洞乎?吾辈共论之。
再读之:OWASP API Security Top 10— 仍为 API 安全之根本要义之最佳发端。













