sgcWebSockets 服务器防火墙

· 组件

安全性已不再是可选项。每台暴露在互联网上的 WebSocket 服务器都是暴力破解攻击、注入尝试、连接洪泛和自动化滥用的目标。抵御这些威胁通常需要接入外部中间件、编写自定义过滤逻辑或部署独立的反向代理——这些方案都会增加复杂性并拖慢开发进度。

sgcWebSockets 2026.4.0 引入了 TsgcWSFirewall——一个可直接插入 WebSocket 服务器的专用防火墙组件,现提供 15 个保护模块,包括 GeoIP 国家过滤、自适应威胁评分、渐进式封禁升级和自定义规则引擎。放置组件、配置所需保护模块、分配给服务器,应用即获保护。无需外部依赖,无需中间件,无需为常见场景编写自定义代码。

本文介绍完整功能集,并演示如何在 Delphi 中配置每个保护模块。

十五个保护模块,一个组件

防火墙提供十五个独立保护模块。仅启用所需模块——每个模块可单独使用,也可与其他模块组合使用。

IP 黑名单
使用 CIDR 表示法封锁特定 IP 地址或整个 IP 段。黑名单中的 IP 连接在到达应用代码之前即被拒绝。
IP 白名单
定义受信任 IP 列表。启用后,白名单地址绕过所有其他安全检查——适用于内部服务和监控工具。
暴力破解防护
按 IP 追踪身份验证失败次数。在滑动时间窗口内超过可配置阈值后自动封禁违规者。
SQL 注入检测
扫描传入消息中的常见 SQL 注入模式。内置检测布尔注入、UNION SELECT、语句注入等。
XSS 检测
检测消息中的跨站脚本攻击载荷。捕获 script 标签、事件处理程序、JavaScript 协议 URI、iframe 注入和 CSS 表达式。
连接速率限制
限制每个 IP 地址的并发连接数,防止单个客户端耗尽服务器资源。
消息洪泛防护
限制单个 IP 每秒可发送的消息数量,防止消息洪泛和拒绝服务攻击模式。
载荷大小限制
拒绝超过最大大小阈值的消息,防止超大载荷耗尽内存。
路径遍历检测
检测消息中的目录遍历序列,阻止访问预期范围之外文件的尝试。
命令注入检测
检测消息中的操作系统命令注入模式,阻止 shell 元字符和常见命令序列。
GeoIP 国家过滤
根据地理来源允许或阻止连接,支持黑名单和白名单模式,使用 CSV 数据库查询。
威胁评分系统
按所有违规类型累积每个 IP 的加权分数,达到阈值后自动封禁,分数随时间自动衰减。
渐进式封禁升级
随每次重复违规增加封禁时长,对持续违规者从短期封禁逐步升级至永久封禁。
WebSocket 保护
验证 WebSocket 来源、强制执行帧大小限制并过滤子协议,提供超越消息内容的协议级保护。
自定义规则引擎
使用条件和动作定义自己的防火墙规则,创建违规阈值、时间窗口和自动响应。

快速开始

启动防火墙只需三个步骤:创建、配置、分配。

var
  oFirewall: TsgcWSFirewall;
  oServer: TsgcWebSocketHTTPServer;
begin
  oFirewall := TsgcWSFirewall.Create(nil);
  oFirewall.Enabled := True;
  // Enable the modules you need
  oFirewall.Blacklist.Enabled := True;
  oFirewall.Blacklist.IPs.Add('10.0.0.0/8');
  oFirewall.RateLimit.Enabled := True;
  oFirewall.RateLimit.MaxConnectionsPerIP := 5;
  oFirewall.SQLInjection.Enabled := True;
  oFirewall.XSS.Enabled := True;
  // Assign to any server component
  oServer.Firewall := oFirewall;
  oServer.Active := True;
end;

分配后,防火墙自动集成:连接在到达事件处理程序之前即被检查,消息实时扫描,断开连接的客户端自动从追踪中注销——无需编写任何事件处理代码。

IP 黑名单与白名单

黑名单拒绝特定 IP 或 IP 段的连接。白名单则相反——定义可绕过所有其他检查(包括消息过滤)的受信任地址集合。

两者均支持精确 IP 地址和 CIDR 表示法进行范围过滤:

// Blacklist: block entire subnets and specific IPs
oFirewall.Blacklist.Enabled := True;
oFirewall.Blacklist.IPs.Add('10.0.0.0/8');        // All 10.x.x.x
oFirewall.Blacklist.IPs.Add('172.16.0.0/16');     // All 172.16.x.x
oFirewall.Blacklist.IPs.Add('192.168.1.100');     // Single IP
// Whitelist: trusted IPs bypass everything
oFirewall.Whitelist.Enabled := True;
oFirewall.Whitelist.IPs.Add('192.168.1.1');       // Admin machine
oFirewall.Whitelist.IPs.Add('192.168.1.0/24');    // Internal network

优先级。启用白名单时,优先检查白名单。若 IP 匹配,连接立即放行——黑名单、封禁、速率限制和消息过滤均跳过。

暴力破解防护

暴力破解模块使用滑动时间窗口追踪每个 IP 的身份验证失败次数。当某 IP 在时间窗口内超过最大尝试次数时,将自动封禁该 IP 一段可配置的时长。

属性 默认值 说明
MaxAttempts 5 触发封禁前的失败尝试次数
TimeWindowSec 60 统计尝试次数的滑动窗口(秒)
BanDurationSec 300 封禁时长(秒),0 表示永久封禁
// Ban after 3 failed logins within 60 seconds, for 10 minutes
oFirewall.BruteForce.Enabled := True;
oFirewall.BruteForce.MaxAttempts := 3;
oFirewall.BruteForce.TimeWindowSec := 60;
oFirewall.BruteForce.BanDurationSec := 600;
// Register failed attempts from your authentication handler
procedure TForm1.ServerAuthentication(Connection: TsgcWSConnection;
  aUser, aPassword: String; var Authenticated: Boolean);
begin
  Authenticated := ValidateCredentials(aUser, aPassword);
  if not Authenticated then
    oFirewall.RegisterFailedAttempt(Connection.IP);
end;

防火墙自动处理其余工作:统计尝试次数、检查时间窗口,并在达到阈值时封禁 IP。被封禁的 IP 在进一步处理之前即在连接层被拒绝。

手动管理封禁

除自动封禁外,您还可以随时以编程方式管理封禁:

// Ban an IP for 1 hour
oFirewall.BanIP('203.0.113.50', 3600);
// Permanent ban (duration = 0)
oFirewall.BanIP('198.51.100.10');
// Check ban status
if oFirewall.IsBanned('203.0.113.50') then
  WriteLn('IP is banned');
// Remove a specific ban
oFirewall.UnbanIP('203.0.113.50');
// Clear all bans
oFirewall.ClearBans;

SQL 注入检测

SQL 注入模块扫描每条传入文本消息中的常见攻击模式。检测到匹配时,可配置的动作决定响应方式:封锁客户端、记录事件或放行。

oFirewall.SQLInjection.Enabled := True;
oFirewall.SQLInjection.Action := faDeny;  // faDeny, faLog, or faAllow
// Add custom patterns beyond the built-in set
oFirewall.SQLInjection.CustomPatterns.Add('WAITFOR DELAY');
oFirewall.SQLInjection.CustomPatterns.Add('BENCHMARK(');

内置检测模式

检测器包含对最常见 SQL 注入技术的不区分大小写检查:

XSS 检测

XSS 模块在 WebSocket 消息中的跨站脚本攻击载荷到达应用逻辑或被转发给其他客户端之前将其检测出来。

oFirewall.XSS.Enabled := True;
oFirewall.XSS.Action := faDeny;

内置检测覆盖:

连接速率限制

限制单个 IP 地址可持有的并发连接数,防止客户端(无论是恶意还是配置错误)建立过多连接耗尽资源。

// Allow up to 5 concurrent connections per IP
oFirewall.RateLimit.Enabled := True;
oFirewall.RateLimit.MaxConnectionsPerIP := 5;
oFirewall.RateLimit.TimeWindowSec := 60;

连接追踪全自动:防火墙在连接时递增计数器,断开时递减。当新连接将超出限制时,在服务器 OnConnect 事件触发之前即被拒绝。

消息洪泛防护

限制单个 IP 每秒可发送的消息数量,防止客户端快速发送消息以压垮服务器或其他已连接客户端的拒绝服务攻击模式。

// Limit to 50 messages per second per IP
oFirewall.FloodProtection.Enabled := True;
oFirewall.FloodProtection.MaxMessagesPerSec := 50;
oFirewall.FloodProtection.Action := faDeny;  // Disconnect offender

载荷大小限制

强制执行最大消息大小,防止客户端发送可能耗尽服务器内存的超大载荷。超过阈值的消息在处理前即被拒绝。

oFirewall.PayloadLimit.Enabled := True;
oFirewall.PayloadLimit.MaxSizeBytes := 65536;  // 64 KB max
oFirewall.PayloadLimit.Action := faDeny;

路径遍历检测

路径遍历模块扫描传入消息中试图访问预期范围之外文件的目录遍历序列。对于处理来自客户端消息中文件路径或资源标识符的应用而言,此功能至关重要。

内置检测覆盖:

oFirewall.PathTraversal.Enabled := True;
oFirewall.PathTraversal.Action := faDeny;

命令注入检测

命令注入模块检测消息中的操作系统命令注入模式,捕获用于执行任意系统命令的 shell 元字符和常见命令序列。

内置检测覆盖:

oFirewall.CommandInjection.Enabled := True;
oFirewall.CommandInjection.Action := faDeny;

GeoIP 国家过滤

根据地理来源使用 IP 到国家的解析过滤连接。GeoIP 模块支持两种模式:BlockList(封锁特定国家,其余放行)和 AllowList(仅允许特定国家,其余封锁)。

属性 说明
Mode gmBlockListgmAllowList
Countries ISO 3166-1 alpha-2 国家代码(如 US、GB、DE)
DatabaseFile 用于 IP 到国家解析的 CSV 文件路径

封锁特定国家

oFirewall.GeoIP.Enabled := True;
oFirewall.GeoIP.Mode := gmBlockList;
oFirewall.GeoIP.Countries.Add('CN');
oFirewall.GeoIP.Countries.Add('RU');
oFirewall.LoadGeoIPDatabase('geoip.csv');

仅允许特定国家

// Only allow connections from US, UK, and Germany
oFirewall.GeoIP.Enabled := True;
oFirewall.GeoIP.Mode := gmAllowList;
oFirewall.GeoIP.Countries.Add('US');
oFirewall.GeoIP.Countries.Add('GB');
oFirewall.GeoIP.Countries.Add('DE');
oFirewall.LoadGeoIPDatabase('geoip.csv');

GeoIP 数据库。DB-IP 和 IP2Location 等提供商提供免费的 IP 到国家 CSV 数据库。或者实现 OnResolveCountry 事件以使用自己的解析逻辑。

威胁评分系统

威胁评分系统为每种违规类型分配加权分数,并按 IP 地址累积分数。当分数超过自动封禁阈值时,该 IP 将自动被封禁。分数随时间衰减,因此偶发事件不会导致永久惩罚。

属性 默认值 说明
AutoBanThreshold 100 触发自动封禁的分数阈值
DecayPerHour 10 每小时减少的分数
oFirewall.ThreatScore.Enabled := True;
oFirewall.ThreatScore.AutoBanThreshold := 80;
oFirewall.ThreatScore.DecayPerHour := 5;

监控评分变化

使用 OnThreatScoreChanged 事件实时监控分数,并在达到自动封禁阈值之前采取自定义操作。

procedure TForm1.FirewallThreatScoreChanged(Sender: TObject;
  const aIP: string; const aOldScore, aNewScore: Integer);
begin
  if aNewScore >= 50 then
    LogToFile(Format('[%s] Threat score elevated: %d -> %d',
      [aIP, aOldScore, aNewScore]));
end;

渐进式封禁升级

渐进式升级模块不使用固定封禁时长,而是随每次重复违规增加封禁时长。初犯获得短期封禁;持续违规者逐步升级至永久封禁。

oFirewall.BanEscalation.Enabled := True;
oFirewall.BanEscalation.Levels.Add('300');    // 5 minutes
oFirewall.BanEscalation.Levels.Add('1800');   // 30 minutes
oFirewall.BanEscalation.Levels.Add('7200');   // 2 hours
oFirewall.BanEscalation.Levels.Add('86400');  // 24 hours
oFirewall.BanEscalation.Levels.Add('0');      // permanent

提示。将渐进式升级与威胁评分系统结合以获得最佳效果。威胁评分通过多种违规类型识别恶意行为者,而升级机制确保重复违规者面临愈发严重的后果。

WebSocket 专项保护

除消息级扫描外,防火墙还提供 WebSocket 连接特有的协议级保护:来源验证、帧大小强制执行和子协议过滤。

// Validate the Origin header to prevent cross-site hijacking
oFirewall.WebSocket.Enabled := True;
oFirewall.WebSocket.AllowedOrigins.Add('https://www.example.com');
oFirewall.WebSocket.AllowedOrigins.Add('https://app.example.com');
// Enforce maximum frame size (bytes)
oFirewall.WebSocket.MaxFrameSize := 131072;  // 128 KB
// Only allow specific subprotocols
oFirewall.WebSocket.AllowedSubProtocols.Add('graphql-ws');
oFirewall.WebSocket.AllowedSubProtocols.Add('mqtt');

自定义规则引擎

自定义规则引擎允许您使用条件和自动化动作定义自己的防火墙规则。每条规则指定时间窗口内的违规阈值以及超过阈值时采取的动作。

属性 说明
Name 规则的描述性名称
MinViolations 触发规则所需的违规次数
TimeWindowSec 统计违规次数的滑动窗口(秒)
ActionType 采取的动作:raDenyraAllowraBanraLog
BanDurationSec ActionType 为 raBan 时的封禁时长

动作类型:

动作 行为
raDeny 立即断开客户端连接
raAllow 无动作(规则被追踪但不执行)
raBan 按指定时长封禁 IP
raLog 仅触发 OnViolation 事件
var
  vRule: TsgcFirewallRuleItem;
begin
  oFirewall.CustomRules.Enabled := True;
  vRule := TsgcFirewallRuleItem(oFirewall.CustomRules.Rules.Add);
  vRule.Name := 'Block high-risk IPs';
  vRule.MinViolations := 5;
  vRule.TimeWindowSec := 300;
  vRule.ActionType := raBan;
  vRule.BanDurationSec := 3600;
end;

实时统计

防火墙通过 Stats 对象公开实时计数器,包括活跃连接数、封锁尝试总数和各违规类型计数。可用于构建监控仪表板或记录定期摘要。

WriteLn('Active: ', oFirewall.Stats.ActiveConnections);
WriteLn('Blocked: ', oFirewall.Stats.TotalBlocked);
WriteLn('SQL Injection: ', oFirewall.Stats.GetViolationCount(fvSQLInjection));

持久化封禁

默认情况下,封禁存储在内存中,重启后清除。使用 SaveBansToFileLoadBansFromFile 在服务器重启后持久保留封禁。

// Save bans before shutdown
oFirewall.SaveBansToFile('bans.dat');
// Restore bans on startup
oFirewall.LoadBansFromFile('bans.dat');

动作模式

SQL 注入、XSS 和洪泛防护模块支持三种可配置的违规响应动作:

动作 行为 使用场景
faDeny 封锁并断开客户端 生产服务器
faLog 触发 OnViolation 事件但允许连接 监控、测试、灰度上线
faAllow 无动作 在不删除配置的情况下临时禁用某模块

提示。在生产环境中先使用 faLog,观察防火墙对真实流量的响应后再切换到 faDeny,避免在初期部署时封锁合法用户。

事件——日志记录与覆盖

事件让您完全掌握防火墙决策,并在需要时覆盖它们。

OnViolation — 安全日志

每次检测到违规时触发。用于写入安全日志、发送告警或更新监控仪表板。

procedure TForm1.FirewallViolation(Sender: TObject;
  const aIP: string;
  const aViolationType: TsgcFirewallViolationType;
  const aDetails: string);
begin
  LogToFile(Format('[%s] Firewall: %s - %s',
    [aIP, ViolationTypeToStr(aViolationType), aDetails]));
end;

违规类型包括:

类型 触发条件
fvBlacklist IP 在黑名单中
fvBruteForce 超过失败尝试次数阈值
fvRateLimit 超过连接速率限制
fvFlood 检测到消息洪泛
fvSQLInjection 检测到 SQL 注入模式
fvXSS 检测到 XSS 模式
fvGeoIP 国家过滤器封锁连接
fvPathTraversal 检测到路径遍历模式
fvCommandInjection 检测到命令注入模式
fvPayloadSize 消息超过最大载荷大小
fvOrigin WebSocket 来源不在允许列表中
fvFrameSize WebSocket 帧超过最大大小
fvThreatScore 威胁评分超过自动封禁阈值
fvCustomRule 自定义规则阈值被超过

OnFiltered — 覆盖决策

当连接或消息即将被封锁时触发。Allow 参数允许您在运行时覆盖防火墙的决策。

procedure TForm1.FirewallFiltered(Sender: TObject;
  const aIP: string; const aReason: string;
  var Allow: Boolean);
begin
  // Override: always allow the office IP even if rate-limited
  if aIP = '203.0.113.10' then
    Allow := True;
end;

OnResolveCountry — 自定义 GeoIP 解析

当 GeoIP 模块需要将 IP 地址解析为国家代码时触发。用于实现自己的解析逻辑,代替(或补充)内置 CSV 数据库。

procedure TForm1.FirewallResolveCountry(Sender: TObject;
  const aIP: string; var aCountryCode: string);
begin
  aCountryCode := MyGeoIPLookup(aIP);
end;

OnThreatScoreChanged — 评分监控

当某 IP 的威胁评分发生变化时触发。用于实现自定义阈值、告警或在达到自动封禁阈值之前采取渐进式响应。

procedure TForm1.FirewallThreatScoreChanged(Sender: TObject;
  const aIP: string; const aOldScore, aNewScore: Integer);
begin
  if aNewScore >= 50 then
    SendAlert(Format('IP %s threat score: %d', [aIP, aNewScore]));
end;

服务器集成

防火墙适用于所有三种服务器组件。单个防火墙实例甚至可以在多个服务器之间共享。

组件 说明
TsgcWebSocketHTTPServer WebSocket + HTTP 服务器(基于 Indy)
TsgcWebSocketServer 纯 WebSocket 服务器(Indy TCP)
TsgcWebSocketServer_HTTPAPI 使用 HTTP.SYS 内核驱动的 WebSocket 服务器

分配后自动集成。防火墙在三个关键点拦截:

完整示例

启用了核心保护模块和新高级功能的完整配置 WebSocket 服务器。

uses
  sgcWebSocket_Server, sgcWebSocket_Server_Firewall;
var
  oFirewall: TsgcWSFirewall;
  oServer: TsgcWebSocketHTTPServer;
begin
  oFirewall := TsgcWSFirewall.Create(nil);
  oServer := TsgcWebSocketHTTPServer.Create(nil);
  Try
    // IP filtering
    oFirewall.Blacklist.Enabled := True;
    oFirewall.Blacklist.IPs.Add('10.0.0.0/8');
    oFirewall.Whitelist.Enabled := True;
    oFirewall.Whitelist.IPs.Add('192.168.1.0/24');
    // Brute force: ban after 3 failures in 60s, for 10 minutes
    oFirewall.BruteForce.Enabled := True;
    oFirewall.BruteForce.MaxAttempts := 3;
    oFirewall.BruteForce.BanDurationSec := 600;
    // Message security
    oFirewall.SQLInjection.Enabled := True;
    oFirewall.XSS.Enabled := True;
    // Rate limiting and flood protection
    oFirewall.RateLimit.Enabled := True;
    oFirewall.RateLimit.MaxConnectionsPerIP := 5;
    oFirewall.FloodProtection.Enabled := True;
    oFirewall.FloodProtection.MaxMessagesPerSec := 50;
    // Payload size limit
    oFirewall.PayloadLimit.Enabled := True;
    oFirewall.PayloadLimit.MaxSizeBytes := 65536;
    // GeoIP: block specific countries
    oFirewall.GeoIP.Enabled := True;
    oFirewall.GeoIP.Mode := gmBlockList;
    oFirewall.GeoIP.Countries.Add('CN');
    oFirewall.GeoIP.Countries.Add('RU');
    oFirewall.LoadGeoIPDatabase('geoip.csv');
    // Threat scoring with auto-ban
    oFirewall.ThreatScore.Enabled := True;
    oFirewall.ThreatScore.AutoBanThreshold := 80;
    oFirewall.ThreatScore.DecayPerHour := 5;
    // Progressive ban escalation
    oFirewall.BanEscalation.Enabled := True;
    oFirewall.BanEscalation.Levels.Add('300');
    oFirewall.BanEscalation.Levels.Add('3600');
    oFirewall.BanEscalation.Levels.Add('86400');
    oFirewall.BanEscalation.Levels.Add('0');
    // Restore persistent bans
    oFirewall.LoadBansFromFile('bans.dat');
    // Events
    oFirewall.OnViolation := FirewallViolation;
    oFirewall.OnFiltered := FirewallFiltered;
    oFirewall.OnThreatScoreChanged := FirewallThreatScoreChanged;
    // Assign to server and start
    oServer.Port := 443;
    oServer.Firewall := oFirewall;
    oServer.Active := True;
    WriteLn('Server running with firewall protection.');
    ReadLn;
    // Save bans before shutdown
    oFirewall.SaveBansToFile('bans.dat');
  Finally
    oServer.Active := False;
    oServer.Free;
    oFirewall.Free;
  End;
end;

线程安全

防火墙组件完全线程安全。所有公共方法使用内部临界区保护对追踪数据的并发访问。经过 20 个并发线程执行 100,000 次操作的压力测试,零错误,零内存泄漏。

该组件可在多个服务器实例之间安全共享,并可从任何线程(服务器事件处理程序、定时器线程、后台工作线程)访问,无需外部同步。

重要说明