#!/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 "