#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ SQL 注入防護測試腳本 測試 app.py 中的 SQL 安全函數 """ import sys import os # 確保可以導入專案模組 sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from app import validate_table_name, validate_column_names from database.manager import sanitize_timestamp def test_table_name_validation(): """測試表名驗證函數""" print("\n" + "="*60) print("測試 1: 表名驗證 (validate_table_name)") print("="*60) test_cases = [ # (輸入, 是否應該通過, 描述) ('products', True, '正常表名'), ('price_records', True, '包含底線的表名'), ('realtime_sales_monthly', True, '長表名'), ("products'; DROP TABLE users--", False, 'SQL 注入攻擊'), ("products; DELETE FROM users", False, 'SQL 刪除攻擊'), ("products UNION SELECT * FROM users", False, 'UNION 注入'), ("../../../etc/passwd", False, '路徑遍歷'), ("products OR 1=1", False, '邏輯注入'), ("", False, '空字串'), ("product-name", False, '包含破折號'), ] passed = 0 failed = 0 for table_name, should_pass, description in test_cases: try: result = validate_table_name(table_name) if should_pass: print(f"✅ 通過: {description} | 表名: '{table_name}'") passed += 1 else: print(f"❌ 失敗: {description} | 應該被阻擋但通過了: '{table_name}'") failed += 1 except (ValueError, Exception) as e: if not should_pass: print(f"✅ 通過: {description} | 成功阻擋: '{table_name}'") passed += 1 else: print(f"❌ 失敗: {description} | 不應該被阻擋: '{table_name}' | 錯誤: {e}") failed += 1 assert failed == 0 def test_column_name_validation(): """測試欄位名驗證函數""" print("\n" + "="*60) print("測試 2: 欄位名驗證 (validate_column_names)") print("="*60) test_cases = [ # (輸入, 是否應該通過, 描述) (['name', 'price'], True, '正常欄位名'), (['商品名稱', '價格'], True, '中文欄位名'), (['product_id', 'user_name'], True, '包含底線'), (['name; DROP TABLE--'], False, 'SQL 注入'), (['id', 'name; DELETE FROM users'], False, '混合注入'), (['name', "price' OR '1'='1"], False, '邏輯注入'), (['name'], False, 'XSS 嘗試'), (['name', ''], False, '空欄位名'), ] passed = 0 failed = 0 for columns, should_pass, description in test_cases: try: result = validate_column_names(columns) if should_pass: print(f"✅ 通過: {description} | 欄位: {columns}") passed += 1 else: print(f"❌ 失敗: {description} | 應該被阻擋但通過了: {columns}") failed += 1 except (ValueError, Exception) as e: if not should_pass: print(f"✅ 通過: {description} | 成功阻擋: {columns}") passed += 1 else: print(f"❌ 失敗: {description} | 不應該被阻擋: {columns} | 錯誤: {e}") failed += 1 assert failed == 0 def test_timestamp_sanitization(): """測試時間戳清理函數""" print("\n" + "="*60) print("測試 3: 時間戳清理 (sanitize_timestamp)") print("="*60) test_cases = [ # (輸入, 是否應該通過, 描述) ('2026-01-12 14:30:00', True, '正常時間戳'), ('2025-12-31 23:59:59', True, '年底時間'), ('2026-01-01 00:00:00', True, '年初時間'), ("2026-01-12'; DROP TABLE users--", False, 'SQL 注入攻擊'), ('2026-01-12 14:30', False, '缺少秒數'), ('2026/01/12 14:30:00', False, '錯誤分隔符'), ('invalid timestamp', False, '無效格式'), ('', False, '空字串'), ] passed = 0 failed = 0 for timestamp, should_pass, description in test_cases: try: result = sanitize_timestamp(timestamp) if should_pass: print(f"✅ 通過: {description} | 時間戳: '{timestamp}'") passed += 1 else: print(f"❌ 失敗: {description} | 應該被阻擋但通過了: '{timestamp}'") failed += 1 except (ValueError, Exception) as e: if not should_pass: print(f"✅ 通過: {description} | 成功阻擋: '{timestamp}'") passed += 1 else: print(f"❌ 失敗: {description} | 不應該被阻擋: '{timestamp}' | 錯誤: {e}") failed += 1 assert failed == 0 def main(): """主測試函數""" print("="*60) print("MOMO 監控系統 - SQL 注入防護測試") print("="*60) # 執行所有測試 try: test_table_name_validation() test_column_name_validation() test_timestamp_sanitization() except AssertionError: print(f"\n⚠️ 有 1 個測試區段未通過,請檢查!") return 1 # 顯示總結 print("\n" + "="*60) print("測試結果摘要") print("="*60) print("✅ 通過: 3 個測試函式") print("❌ 失敗: 0") print("總計: 3") print("\n🎉 所有 SQL 注入防護測試通過!") return 0 if __name__ == "__main__": sys.exit(main())