226 lines
8.5 KiB
GDScript
226 lines
8.5 KiB
GDScript
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") |