Files
whale-town/tests/test_security_manager.gd
2025-12-05 19:00:14 +08:00

226 lines
8.5 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends GutTest
## 安全管理器测试
## 测试安全验证、输入过滤和防护措施
var security_manager: SecurityManager
func before_each():
"""每个测试前的设置"""
security_manager = SecurityManager.new()
func after_each():
"""每个测试后的清理"""
if security_manager:
security_manager.queue_free()
## 测试输入验证 - 有效输入
func test_validate_input_valid():
"""测试有效输入的验证"""
# 测试有效用户名
var result = SecurityManager.validate_input("TestUser123", "username")
assert_true(result.valid, "Valid username should pass validation")
assert_eq(result.sanitized, "TestUser123", "Valid username should not be modified")
# 测试有效角色名
result = SecurityManager.validate_input("MyCharacter", "character_name")
assert_true(result.valid, "Valid character name should pass validation")
assert_eq(result.sanitized, "MyCharacter", "Valid character name should not be modified")
# 测试有效消息
result = SecurityManager.validate_input("Hello, world!", "message")
assert_true(result.valid, "Valid message should pass validation")
assert_eq(result.sanitized, "Hello, world!", "Valid message should not be modified")
## 测试输入验证 - 无效输入
func test_validate_input_invalid():
"""测试无效输入的验证"""
# 测试空输入
var result = SecurityManager.validate_input("", "username")
assert_false(result.valid, "Empty username should fail validation")
assert_true(result.error.length() > 0, "Should provide error message")
# 测试过长输入
var long_string = "a".repeat(100)
result = SecurityManager.validate_input(long_string, "character_name")
assert_false(result.valid, "Overly long character name should fail validation")
# 测试过短角色名
result = SecurityManager.validate_input("a", "character_name")
assert_false(result.valid, "Too short character name should fail validation")
## 测试恶意内容检测
func test_malicious_content_detection():
"""测试恶意内容检测"""
# 测试脚本注入
var malicious_inputs = [
"<script>alert('xss')</script>",
"javascript:alert('xss')",
"onload=alert('xss')",
"eval(malicious_code)",
"document.cookie"
]
for malicious_input in malicious_inputs:
var result = SecurityManager.validate_input(malicious_input, "message")
assert_false(result.valid, "Malicious input should be rejected: " + malicious_input)
assert_true(result.error.contains("不安全内容"), "Should indicate unsafe content")
## 测试SQL注入检测
func test_sql_injection_detection():
"""测试SQL注入检测"""
var injection_inputs = [
"'; DROP TABLE users; --",
"' OR '1'='1",
"UNION SELECT * FROM passwords",
"INSERT INTO users VALUES"
]
for injection_input in injection_inputs:
var result = SecurityManager.validate_input(injection_input, "message")
assert_false(result.valid, "SQL injection should be rejected: " + injection_input)
## 测试过度重复字符检测
func test_excessive_repetition_detection():
"""测试过度重复字符检测"""
# 创建70%重复字符的字符串
var repetitive_string = "a".repeat(70) + "b".repeat(30)
var result = SecurityManager.validate_input(repetitive_string, "message")
assert_false(result.valid, "Excessive repetition should be rejected")
assert_true(result.error.contains("重复字符"), "Should indicate repetition issue")
## 测试输入清理
func test_input_sanitization():
"""测试输入清理功能"""
# 测试HTML标签移除
var html_input = "Hello <b>world</b>!"
var sanitized = SecurityManager.sanitize_input(html_input)
assert_false(sanitized.contains("<b>"), "HTML tags should be removed")
assert_false(sanitized.contains("</b>"), "HTML tags should be removed")
assert_true(sanitized.contains("Hello"), "Text content should be preserved")
assert_true(sanitized.contains("world"), "Text content should be preserved")
# 测试多余空格处理
var spaced_input = "Hello world !"
sanitized = SecurityManager.sanitize_input(spaced_input)
assert_false(sanitized.contains(" "), "Multiple spaces should be reduced")
assert_true(sanitized.contains("Hello world"), "Should contain single spaces")
## 测试消息格式验证
func test_message_format_validation():
"""测试网络消息格式验证"""
# 测试有效消息
var valid_message = {
"type": "auth_request",
"data": {"username": "test"},
"timestamp": Time.get_unix_time_from_system()
}
assert_true(SecurityManager.validate_message_format(valid_message), "Valid message should pass")
# 测试缺少字段的消息
var invalid_message = {
"type": "auth_request"
# 缺少 data 和 timestamp
}
assert_false(SecurityManager.validate_message_format(invalid_message), "Invalid message should fail")
# 测试无效消息类型
var invalid_type_message = {
"type": "malicious_type",
"data": {},
"timestamp": Time.get_unix_time_from_system()
}
assert_false(SecurityManager.validate_message_format(invalid_type_message), "Invalid message type should fail")
# 测试时间戳过旧
var old_message = {
"type": "auth_request",
"data": {},
"timestamp": Time.get_unix_time_from_system() - 400 # 超过5分钟
}
assert_false(SecurityManager.validate_message_format(old_message), "Old timestamp should fail")
## 测试会话管理
func test_session_management():
"""测试会话管理功能"""
# 创建会话
var session_token = security_manager.create_session("client123", "testuser")
assert_true(session_token.length() > 0, "Should generate session token")
# 验证会话
assert_true(security_manager.validate_session(session_token), "New session should be valid")
# 使会话无效
security_manager.invalidate_session(session_token)
assert_false(security_manager.validate_session(session_token), "Invalidated session should be invalid")
## 测试失败尝试记录
func test_failed_attempt_recording():
"""测试失败尝试记录和锁定机制"""
var client_id = "test_client"
# 记录多次失败尝试
for i in range(4): # 4次失败还未达到锁定阈值
var should_lock = security_manager.record_failed_attempt(client_id)
assert_false(should_lock, "Should not lock before reaching max attempts")
# 第5次失败应该触发锁定
var should_lock = security_manager.record_failed_attempt(client_id)
assert_true(should_lock, "Should lock after max failed attempts")
# 检查锁定状态
assert_true(security_manager.is_locked(client_id), "Client should be locked")
# 清除失败尝试
security_manager.clear_failed_attempts(client_id)
assert_false(security_manager.is_locked(client_id), "Client should be unlocked after clearing attempts")
## 测试安全统计
func test_security_statistics():
"""测试安全统计功能"""
# 创建一些会话和失败尝试
security_manager.create_session("client1", "user1")
security_manager.create_session("client2", "user2")
security_manager.record_failed_attempt("client3")
var stats = security_manager.get_security_stats()
assert_true(stats.has("active_sessions"), "Stats should include active sessions")
assert_true(stats.has("failed_attempts"), "Stats should include failed attempts")
assert_true(stats.has("locked_clients"), "Stats should include locked clients")
assert_eq(stats.active_sessions, 2, "Should have 2 active sessions")
assert_eq(stats.failed_attempts, 1, "Should have 1 failed attempt record")
## 测试会话超时
func test_session_timeout():
"""测试会话超时机制"""
# 创建会话
var session_token = security_manager.create_session("client123", "testuser")
# 修改会话超时时间为很短的时间进行测试
security_manager.session_timeout = 0.1 # 0.1秒
# 等待超时
await get_tree().create_timer(0.2).timeout
# 验证会话应该已过期
assert_false(security_manager.validate_session(session_token), "Session should expire after timeout")
## 测试边界情况
func test_edge_cases():
"""测试边界情况"""
# 测试null输入
var result = SecurityManager.validate_input(null, "username")
assert_false(result.valid, "Null input should be rejected")
# 测试空白字符输入
result = SecurityManager.validate_input(" ", "character_name")
assert_false(result.valid, "Whitespace-only input should be rejected")
# 测试边界长度
var min_length_name = "ab" # 最小长度
result = SecurityManager.validate_input(min_length_name, "character_name")
assert_true(result.valid, "Minimum length name should be valid")
var max_length_name = "a".repeat(20) # 最大长度
result = SecurityManager.validate_input(max_length_name, "character_name")
assert_true(result.valid, "Maximum length name should be valid")