#!/usr/bin/env python3
"""
安全审计测试脚本 - 第13轮 Phase 2
测试被速率限制阻塞的项目: 用户名枚举、注册、越权访问
"""
import subprocess
import json
import time
BASE = "http://localhost:8080"
HDR = {"Content-Type": "application/json"}
def curl(method, path, headers=None, data=None):
cmd = ["curl", "-s", "-w", "\n%{http_code}", "-X", method, f"{BASE}{path}", "--max-time", "10"]
if headers:
for k, v in headers.items():
cmd += ["-H", f"{k}: {v}"]
if data:
cmd += ["-d", data]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
output = result.stdout.strip()
lines = output.rsplit("\n", 1)
body = lines[0]
try:
status = int(lines[1])
except:
status = 0
return status, body
def pr(test, status, body, expected=None):
icon = "✅" if (expected is None or status == expected) else "❌"
print(f"{icon} [{status}] {test}")
print(f" {body[:200]}")
if expected and status != expected:
print(f" 期望: {expected}, 实际: {status}")
print()
# Get admin token
print("🔑 获取管理员 token...")
s, b = curl("POST", "/api/v1/auth/login", HDR, json.dumps({"username":"yeij0942","password":"Jiang1143218570"}))
admin_token = json.loads(b).get("token","")
print(f" token: {admin_token[:30]}...\n")
time.sleep(2) # 等待一点时间让令牌桶恢复
# ==========================================
# 测试 1: 用户名枚举
# ==========================================
print("=" * 60)
print(" 用户名枚举测试")
print("=" * 60)
# 登录不存在的用户
s1, b1 = curl("POST", "/api/v1/auth/login", HDR, json.dumps({"username":"nonexistent_user_xyz_12345","password":"any_password"}))
pr("不存在用户登录", s1, b1, 401)
time.sleep(1)
# 登录存在的用户但密码错误
s2, b2 = curl("POST", "/api/v1/auth/login", HDR, json.dumps({"username":"yeij0942","password":"wrong_password"}))
pr("存在用户但密码错误", s2, b2, 401)
print(f" 不存在用户消息: {b1}")
print(f" 存在用户消息: {b2}")
if b1 == b2:
print(" ✅ 错误消息一致,防止用户名枚举")
else:
print(" ⚠️ 错误消息不同,可能存在用户名枚举风险")
time.sleep(1)
# ==========================================
# 测试 2: 注册端点详细测试
# ==========================================
print("\n" + "=" * 60)
print(" 注册端点安全测试")
print("=" * 60)
# 2.1 极短用户名 (2字符)
s, b = curl("POST", "/api/v1/auth/register", HDR, json.dumps({
"username":"ab","password":"123456","email":"test@test.com","nickname":"Test","verify_code":"000000"
}))
pr("极短用户名 (2字符 ab)", s, b, 400)
time.sleep(0.5)
# 2.2 XSS in username
s, b = curl("POST", "/api/v1/auth/register", HDR, json.dumps({
"username":"","password":"123456","email":"test@test.com","nickname":"Test","verify_code":"000000"
}))
pr("XSS in username", s, b, 400)
time.sleep(0.5)
# 2.3 Special chars in username
s, b = curl("POST", "/api/v1/auth/register", HDR, json.dumps({
"username":"test user","password":"123456","email":"test@test.com","nickname":"Test","verify_code":"000000"
}))
pr("空格在用户名中", s, b, 400)
time.sleep(0.5)
# 2.4 Unicode in username
s, b = curl("POST", "/api/v1/auth/register", HDR, json.dumps({
"username":"test😀user","password":"123456","email":"test@test.com","nickname":"Test","verify_code":"000000"
}))
pr("Emoji in username", s, b, 400)
time.sleep(0.5)
# 2.5 Forward slash in username (路径遍历)
s, b = curl("POST", "/api/v1/auth/register", HDR, json.dumps({
"username":"../../etc/passwd","password":"123456","email":"test@test.com","nickname":"Test","verify_code":"000000"
}))
pr("路径遍历 in username", s, b, 400)
time.sleep(0.5)
# 2.6 XSS in nickname (应该允许注册但需要检查nickname是否被过滤)
s, b = curl("POST", "/api/v1/auth/register", HDR, json.dumps({
"username":"testnick99","password":"Test123456","email":"test99@test.com","nickname":"","verify_code":"000000"
}))
pr("XSS in nickname", s, b, None)
if s == 201:
resp = json.loads(b)
nn = resp.get("nickname","")
print(f" 昵称返回值: {nn}")
if "