When implementing IP-based firewall rules for services like RDP, we're essentially making two assumptions: that IP addresses can't be easily spoofed in TCP connections, and that our allowed IP list remains accurate. The first assumption holds surprisingly well due to TCP's three-way handshake mechanism.
# Example Linux iptables rule for RDP IP restriction
iptables -A INPUT -p tcp --dport 3389 -s 203.0.113.45 -j ACCEPT
iptables -A INPUT -p tcp --dport 3389 -j DROP
While IP spoofing is possible in UDP or ICMP floods (DDoS scenarios), establishing a stateful TCP connection like RDP requires bidirectional communication. An attacker spoofing their source IP would never receive the SYN-ACK packet, making connection establishment impossible. The real vulnerabilities come from elsewhere.
IP-based protection fails in several practical scenarios:
- Corporate networks where multiple users share the same public IP
- Mobile employees with dynamic IP addresses
- Cloud environments where instances get reassigned IPs
- APNIC/ARIN IP space hijacking incidents
Instead of relying solely on IP restrictions, consider these layered approaches:
# Example SSH jump host configuration
Match Address 192.0.2.*
ForceCommand echo 'Attempting direct access' | mail -s "SSH Attempt" admin@example.com
PermitOpen localhost:22
For RDP specifically:
- Implement Network Level Authentication (NLA)
- Use RD Gateway with SSL certificate authentication
- Enable account lockout policies
- Deploy 2FA solutions like Duo Security
Major cloud providers offer better alternatives to simple IP filtering:
// AWS Security Group with tags-based access
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": "ec2:AuthorizeSecurityGroupIngress",
"Condition": {
"StringEquals": {"ec2:ResourceTag/AccessGroup": "prod-rdp"}
}
}]
}
When implementing IP-based firewall rules for services like RDP or SSH, we're essentially leveraging network-layer access control. The typical implementation looks like this in common firewall solutions:
# Linux iptables example for RDP restriction
iptables -A INPUT -p tcp --dport 3389 -s 192.0.2.100 -j ACCEPT
iptables -A INPUT -p tcp --dport 3389 -j DROP
# Windows Firewall equivalent
New-NetFirewallRule -DisplayName "Restrict RDP" -Direction Inbound -LocalPort 3389 -Protocol TCP -RemoteAddress 192.0.2.100 -Action Allow
While IP restrictions provide a first layer of defense, several attack vectors remain:
- IP Spoofing Limitations: While attackers can spoof source IPs in SYN packets, TCP's 3-way handshake makes successful connection establishment difficult unless they control routing infrastructure (BGP hijacking) or compromise intermediate systems.
- Shared Infrastructure Risks: Cloud environments where multiple tenants share IP ranges (e.g., AWS VPCs) may expose your service if another tenant is compromised.
- Stale Rules: Dynamic IP changes (common in residential/business networks) can lock out legitimate users while creating false security assumptions.
For production systems, consider these layered approaches:
# Cloudflare example with authenticated origin pulls
# 1. Restrict at network layer
gcloud compute firewall-rules create restrict-rdp \
--allow=tcp:3389 \
--source-ranges=203.0.113.0/24 \
--target-tags=rdp-enabled
# 2. Add application layer validation
# (Nginx config snippet for proxy scenarios)
location /rdp-gateway {
satisfy all;
allow 203.0.113.0/24;
deny all;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
}
When IP-based restrictions aren't sufficient:
# WireGuard VPN alternative (simplified config)
# /etc/wireguard/wg0.conf
[Interface]
PrivateKey = local_private_key
ListenPort = 51820
[Peer]
PublicKey = remote_public_key
AllowedIPs = 10.8.0.2/32
# IP restriction + crypto authentication
For critical infrastructure, implement:
- Certificate-based authentication (e.g., OpenSSH certificates)
- Port knocking sequences
- Time-based access controls
- Multi-factor authentication at network layer (e.g., Tailscale)
Effective IP-based restrictions require active management:
# AWS CLI example to update security groups dynamically
aws ec2 authorize-security-group-ingress \
--group-id sg-123456 \
--protocol tcp \
--port 3389 \
--cidr $(curl -s https://checkip.amazonaws.com)/32
# Cron job to update residential IP weekly
0 3 * * 1 /usr/local/bin/update-firewall-ip.sh