eSeGeCe
software
Security is no longer optional. Every WebSocket server exposed to the internet is a target for brute force attacks, injection attempts, connection flooding, and automated abuse. Defending against these threats typically requires bolting on external middleware, writing custom filtering logic, or deploying a separate reverse proxy — all of which add complexity and slow down development.
sgcWebSockets 2026.4.0 introduces TsgcWSFirewall — a dedicated firewall component that plugs directly into your WebSocket server, now with 15 protection modules including GeoIP country filtering, adaptive threat scoring, progressive ban escalation, and a custom rules engine. Drop the component, configure the protection modules you need, assign it to the server, and your application is protected. No external dependencies. No middleware. No custom code for the common cases.
This article covers the full feature set and shows how to configure each protection module in Delphi.
The firewall provides fifteen independent protection modules. Enable only what you need — each module works on its own or in combination with the others.
|
IP Blacklist Block specific IP addresses or entire ranges using CIDR notation. Connections from blacklisted IPs are rejected before reaching your application code. |
IP Whitelist Define a trusted list of IPs. When enabled, whitelisted addresses bypass all other security checks — ideal for internal services and monitoring tools. |
Brute Force Protection Track failed authentication attempts per IP. Automatically ban offenders after a configurable threshold within a sliding time window. |
|
SQL Injection Detection Scan incoming messages for common SQL injection patterns. Built-in detection for boolean injection, UNION SELECT, statement injection, and more. |
XSS Detection Detect cross-site scripting payloads in messages. Catches script tags, event handlers, JavaScript protocol URIs, iframe injection, and CSS expressions. |
Connection Rate Limiting Limit the number of concurrent connections per IP address. Prevent a single client from exhausting server resources. |
|
Message Flood Protection Throttle the number of messages a single IP can send per second. Protects against message flooding and denial-of-service patterns. |
Payload Size Limiting Reject messages that exceed a maximum size threshold. Prevents memory exhaustion from oversized payloads. |
Path Traversal Detection Detect directory traversal sequences in messages. Blocks attempts to access files outside the intended scope. |
|
Command Injection Detection Detect OS command injection patterns in messages. Blocks shell metacharacters and common command sequences. |
GeoIP Country Filtering Allow or block connections based on geographic origin. Supports blocklist and allowlist modes with CSV database lookup. |
Threat Score System Accumulate weighted scores per IP across all violation types. Auto-ban when a threshold is reached, with automatic decay over time. |
|
Progressive Ban Escalation Increase ban duration with each repeated offense. Escalate from short bans to permanent blocks for persistent offenders. |
WebSocket Protection Validate WebSocket origins, enforce frame size limits, and filter subprotocols. Protocol-level protection beyond message content. |
Custom Rules Engine Define your own firewall rules with conditions and actions. Create violation thresholds, time windows, and automated responses. |
Getting the firewall up and running requires just three steps: create, configure, and assign.
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;
Once assigned, the firewall integrates automatically: connections are checked before they reach your event handlers, messages are scanned in real-time, and disconnected clients are unregistered from tracking — all without writing a single line of event handling code.
The blacklist rejects connections from specific IPs or ranges. The whitelist does the opposite — it defines a trusted set of addresses that bypass all other checks, including message filtering.
Both support exact IP addresses and CIDR notation for range-based filtering:
// 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
Priority. When the whitelist is enabled, it is checked first. If the IP matches, the connection is allowed immediately — blacklist, bans, rate limits, and message filters are all skipped.
The brute force module tracks failed authentication attempts per IP using a sliding time window. When an IP exceeds the maximum number of attempts within the window, it is automatically banned for a configurable duration.
| Property | Default | Description |
|---|---|---|
| MaxAttempts | 5 | Failed attempts before ban |
| TimeWindowSec | 60 | Sliding window in seconds for counting attempts |
| BanDurationSec | 300 | Ban duration in seconds (0 = permanent) |
// 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;
The firewall automatically handles the rest: it counts attempts, checks the time window, and bans the IP when the threshold is reached. Banned IPs are rejected at the connection level before any further processing.
Beyond automatic bans, you can manage bans programmatically at any time:
// 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;
The SQL injection module scans every incoming text message for common attack patterns. When a match is detected, the configurable action determines the response: block the client, log the event, or allow it through.
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(');
The detector includes case-insensitive checks for the most common SQL injection techniques:
The XSS module detects cross-site scripting payloads in WebSocket messages before they can reach your application logic or be relayed to other clients.
oFirewall.XSS.Enabled := True;
oFirewall.XSS.Action := faDeny;
Built-in detection covers:
Limit the number of concurrent connections a single IP address can hold. This prevents resource exhaustion from clients that open excessive connections — whether malicious or misconfigured.
// Allow up to 5 concurrent connections per IP
oFirewall.RateLimit.Enabled := True;
oFirewall.RateLimit.MaxConnectionsPerIP := 5;
oFirewall.RateLimit.TimeWindowSec := 60;
Connection tracking is fully automatic: the firewall increments the counter on connect and decrements it on disconnect. When a new connection would exceed the limit, it is rejected before the server's OnConnect event fires.
Throttle the number of messages a single IP can send per second. This protects against denial-of-service patterns where a client rapidly sends messages to overwhelm the server or other connected clients.
// Limit to 50 messages per second per IP
oFirewall.FloodProtection.Enabled := True;
oFirewall.FloodProtection.MaxMessagesPerSec := 50;
oFirewall.FloodProtection.Action := faDeny; // Disconnect offender
Enforce a maximum message size to prevent clients from sending oversized payloads that could exhaust server memory. Messages exceeding the threshold are rejected before processing.
oFirewall.PayloadLimit.Enabled := True;
oFirewall.PayloadLimit.MaxSizeBytes := 65536; // 64 KB max
oFirewall.PayloadLimit.Action := faDeny;
The path traversal module scans incoming messages for directory traversal sequences that attempt to access files outside the intended scope. This is critical for applications that process file paths or resource identifiers from client messages.
Built-in detection covers:
oFirewall.PathTraversal.Enabled := True;
oFirewall.PathTraversal.Action := faDeny;
The command injection module detects OS command injection patterns in messages. It catches shell metacharacters and common command sequences used to execute arbitrary system commands.
Built-in detection covers:
oFirewall.CommandInjection.Enabled := True;
oFirewall.CommandInjection.Action := faDeny;
Filter connections based on their geographic origin using IP-to-country resolution. The GeoIP module supports two modes: BlockList (block specific countries, allow everything else) and AllowList (allow only specific countries, block everything else).
| Property | Description |
|---|---|
| Mode | gmBlockList or gmAllowList |
| Countries | ISO 3166-1 alpha-2 country codes (e.g., US, GB, DE) |
| DatabaseFile | Path to CSV file for IP-to-country resolution |
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 databases. Free IP-to-country CSV databases are available from providers like DB-IP and IP2Location. Alternatively, implement the OnResolveCountry event to use your own resolution logic.
The threat score system assigns weighted points to each violation type and accumulates a score per IP address. When the score exceeds the auto-ban threshold, the IP is automatically banned. Scores decay over time, so one-off incidents do not result in permanent penalties.
| Property | Default | Description |
|---|---|---|
| AutoBanThreshold | 100 | Score at which the IP is automatically banned |
| DecayPerHour | 10 | Points subtracted per hour of inactivity |
oFirewall.ThreatScore.Enabled := True;
oFirewall.ThreatScore.AutoBanThreshold := 80;
oFirewall.ThreatScore.DecayPerHour := 5;
Use the OnThreatScoreChanged event to monitor scores in real time and take custom action before the auto-ban threshold is reached.
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;
Instead of a fixed ban duration, the escalation module increases the ban length with each repeated offense. First-time offenders get a short ban; persistent offenders are escalated up to a permanent block.
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
Tip. Combine progressive escalation with the threat score system for maximum effectiveness. The threat score identifies bad actors across multiple violation types, and the escalation ensures repeat offenders face increasingly severe consequences.
Beyond message-level scanning, the firewall provides protocol-level protections specific to WebSocket connections: origin validation, frame size enforcement, and subprotocol filtering.
// 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');
The custom rules engine lets you define your own firewall rules with conditions and automated actions. Each rule specifies a violation threshold within a time window, and the action to take when the threshold is exceeded.
| Property | Description |
|---|---|
| Name | Descriptive name for the rule |
| MinViolations | Number of violations required to trigger the rule |
| TimeWindowSec | Sliding window in seconds for counting violations |
| ActionType | Action to take: raDeny, raAllow, raBan, or raLog |
| BanDurationSec | Ban duration when ActionType is raBan |
Action types:
| Action | Behavior |
|---|---|
raDeny |
Disconnect the client immediately |
raAllow |
No action (rule is tracked but not enforced) |
raBan |
Ban the IP for the specified duration |
raLog |
Fire the OnViolation event only |
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;
The firewall exposes a Stats object with real-time counters for active connections, total blocked attempts, and per-violation-type counts. Use it to build monitoring dashboards or log periodic summaries.
WriteLn('Active: ', oFirewall.Stats.ActiveConnections);
WriteLn('Blocked: ', oFirewall.Stats.TotalBlocked);
WriteLn('SQL Injection: ', oFirewall.Stats.GetViolationCount(fvSQLInjection));
By default, bans are stored in memory and cleared on restart. Use SaveBansToFile and LoadBansFromFile to persist bans across server restarts.
// Save bans before shutdown
oFirewall.SaveBansToFile('bans.dat');
// Restore bans on startup
oFirewall.LoadBansFromFile('bans.dat');
The SQL injection, XSS, and flood protection modules support three configurable actions when a violation is detected:
| Action | Behavior | Use Case |
|---|---|---|
faDeny |
Block and disconnect the client | Production servers |
faLog |
Fire the OnViolation event but allow the connection | Monitoring, testing, gradual rollout |
faAllow |
No action | Temporarily disable a module without removing config |
Tip. Start with faLog in production to observe how the firewall reacts to your real traffic before switching to faDeny. This avoids blocking legitimate users during the initial deployment.
Events give you full visibility into firewall decisions and the ability to override them when needed.
Fired on every detected violation. Use it to write security logs, send alerts, or feed a monitoring dashboard.
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;
Violation types include:
| Type | Triggered When |
|---|---|
fvBlacklist |
IP is in the blacklist |
fvBruteForce |
Failed attempt threshold exceeded |
fvRateLimit |
Connection rate limit exceeded |
fvFlood |
Message flood detected |
fvSQLInjection |
SQL injection pattern detected |
fvXSS |
XSS pattern detected |
fvGeoIP |
Connection blocked by country filter |
fvPathTraversal |
Path traversal pattern detected |
fvCommandInjection |
Command injection pattern detected |
fvPayloadSize |
Message exceeds maximum payload size |
fvOrigin |
WebSocket origin not in allowed list |
fvFrameSize |
WebSocket frame exceeds maximum size |
fvThreatScore |
Threat score exceeded auto-ban threshold |
fvCustomRule |
Custom rule threshold exceeded |
Fired when a connection or message is about to be blocked. The Allow parameter lets you override the firewall's decision at runtime.
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;
Fired when the GeoIP module needs to resolve an IP address to a country code. Use this to implement your own resolution logic instead of (or in addition to) the built-in CSV database.
procedure TForm1.FirewallResolveCountry(Sender: TObject;
const aIP: string; var aCountryCode: string);
begin
aCountryCode := MyGeoIPLookup(aIP);
end;
Fired whenever an IP's threat score changes. Use this to implement custom thresholds, alerts, or graduated responses before the auto-ban threshold is reached.
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;
The firewall works with all three server components. A single firewall instance can even be shared across multiple servers.
| Component | Description |
|---|---|
TsgcWebSocketHTTPServer |
WebSocket + HTTP server (Indy-based) |
TsgcWebSocketServer |
Pure WebSocket server (Indy TCP) |
TsgcWebSocketServer_HTTPAPI |
WebSocket server using HTTP.SYS kernel driver |
Integration is automatic once assigned. The firewall intercepts at three points:
A fully configured WebSocket server with core protection modules and the new advanced features enabled.
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;
The firewall component is fully thread-safe. All public methods use internal critical sections to protect concurrent access to tracking data. It has been stress-tested with 20 concurrent threads performing 100,000 operations with zero errors and zero memory leaks.
The component can safely be shared across multiple server instances and accessed from any thread — server event handlers, timer threads, background workers — without external synchronization.
SaveBansToFile and LoadBansFromFile to persist bans across server restarts. Without these calls, bans are stored in memory only and cleared on restart.RegisterFailedAttempt from your authentication handler. Everything else is automatic.LoadGeoIPDatabase for country resolution, or implement the OnResolveCountry event for custom lookup logic.DecayPerHour to match your traffic patterns — high-traffic servers may benefit from faster decay to avoid false positives.When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.