Firewall Essentials
Firewall Essentials A firewall is a network control point that inspects traffic and decides, based on a rule set, whether to allow or block it. It's the first l…
Firewall Essentials
A firewall is a network control point that inspects traffic and decides, based on a rule set, whether to allow or block it. It's the first line of network defense — the boundary between trust zones (internet vs internal network, or between segments of the same network). Firewalls range from a single "allow/deny by port" rule on a home router to stateful cloud security groups to full next-gen appliances doing deep packet inspection. The concepts below apply at every layer.
Stateless vs Stateful Filtering
A stateless (packet-filtering) firewall evaluates each packet in isolation against a rule list — source/destination IP, port, protocol. It has no memory of prior packets, so to allow a TCP connection you must write two rules: one for the outbound SYN and one for the inbound SYN-ACK response. This makes rule sets larger and easier to misconfigure, but it's fast and cheap — this is how basic router ACLs and some cloud network ACLs (as opposed to security groups) work.
A stateful firewall tracks the connection as a whole in a state table (source/dest IP+port, protocol, sequence numbers, connection state). Once you allow the outbound request, the firewall automatically permits the matching inbound response without a separate rule — it recognizes the reply belongs to an already-approved connection. This is the default for almost everything today: iptables/nftables conntrack, AWS/GCP/Azure security groups, and consumer routers doing NAT all rely on stateful tracking.
The trade-off: stateful firewalls hold more resources per connection (the state table can be exhausted by a SYN flood) and are slightly more complex to reason about at scale, but they eliminate most of the "forgot the return rule" misconfiguration class that plagues stateless setups.
Packet Filtering, Proxy, and Next-Gen Firewalls
Packet-filtering firewalls (stateless or stateful) work at layers 3/4 — IP addresses, ports, protocol. They're fast but blind to what's actually inside the payload; they can't tell a legitimate HTTPS request from an exfiltration attempt over port 443.
Proxy firewalls (application-layer gateways) terminate the connection themselves and open a new one to the destination, inspecting and potentially rewriting the actual application data (HTTP headers, FTP commands) in between. This gives much finer control — you can block specific HTTP methods, strip headers, cache content — at the cost of latency and having to understand every protocol you proxy.
Next-generation firewalls (NGFW) combine stateful packet filtering with deep packet inspection, application awareness (identifying traffic by application, not just port — e.g. distinguishing Slack from generic HTTPS), intrusion prevention (IPS) signatures, and often TLS inspection (decrypt-inspect-re-encrypt). A Web Application Firewall (WAF) is a specialized layer-7 firewall sitting in front of web apps specifically, matching request patterns against rules for SQL injection, XSS, path traversal, and similar attack signatures rather than general network threats.
Writing Rules: iptables/nftables Example
# nftables — modern default-deny setup for a web server
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# allow established/related traffic from connections we opened
ct state established,related accept
# allow loopback
iif "lo" accept
# drop invalid packets outright (helps against some spoofing/scan techniques)
ct state invalid drop
# allow SSH only from the office CIDR, rate-limited against brute force
ip saddr 203.0.113.0/24 tcp dport 22 ct state new limit rate 5/minute accept
# allow inbound HTTP/HTTPS from anywhere
tcp dport { 80, 443 } ct state new accept
# allow ICMP echo (ping) for diagnostics, rate-limited
ip protocol icmp icmp type echo-request limit rate 10/second accept
# everything else hits the default policy: drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}Two things to notice: the default policy on `input` is `drop`, not `accept` — this is default-deny, the correct posture (allow only what you explicitly need). And rules are evaluated top-to-bottom with first-match-wins semantics in most implementations, so rule order matters — a broad allow rule placed above a narrow deny rule will shadow it.
Cloud Security Groups & Network Segmentation
In cloud environments, the "firewall" is usually a security group (stateful, attached to an instance/resource, allow-only — you can't write explicit deny rules) plus a network ACL (stateless, attached to a subnet, supports allow and deny, evaluated in rule-number order). Security groups are the primary tool day-to-day; NACLs are a coarser backstop, often used to explicitly block a known-bad IP range at the subnet level regardless of what any security group says.
{
"GroupName": "app-tier-sg",
"Description": "App servers - only reachable from the load balancer tier",
"SecurityGroupRules": [
{
"IpProtocol": "tcp",
"FromPort": 8080,
"ToPort": 8080,
"ReferencedGroupId": "sg-0a1b2c3d4e5f6g7h8",
"Description": "App port, only from the ALB security group"
},
{
"IpProtocol": "tcp",
"FromPort": 22,
"ToPort": 22,
"CidrIpv4": "10.0.5.0/24",
"Description": "SSH only from the bastion subnet"
}
],
"Egress": [
{
"IpProtocol": "tcp",
"FromPort": 5432,
"ToPort": 5432,
"ReferencedGroupId": "sg-db-tier",
"Description": "Only allow outbound to the DB tier on Postgres port"
}
]
}Notice the rule references another security group ID rather than a hardcoded CIDR — this is the pattern for network segmentation: the app tier only accepts traffic from the load-balancer tier's security group, the DB tier only accepts traffic from the app tier's group, and nothing can jump directly from the internet to the database. If an attacker compromises one tier, segmentation limits lateral movement to adjacent tiers rather than exposing the whole network. This is the practical implementation of zero-trust-adjacent "least privilege at the network layer."
Also note the explicit egress rule — many teams only lock down ingress and leave egress wide open, which does nothing to stop data exfiltration or a compromised host calling out to a command-and-control server.
Common Misconfigurations
Wide-open ingress (0.0.0.0/0) on management ports — SSH (22), RDP (3389), or database ports exposed to the entire internet are among the most common causes of breach in cloud misconfiguration reports; scope these to known IP ranges or a bastion/VPN.
No egress restrictions — default-allow-all outbound means a compromised host can freely exfiltrate data or reach C2 infrastructure; default-deny egress and allow-list only what's needed is stronger but requires more upkeep.
Rule order mistakes in first-match-wins systems — a broad allow rule higher in the list can silently make a more specific deny rule below it unreachable; audit for shadowed rules.
Flat networks with no segmentation — one security group/VLAN for everything means a single compromised host can reach the database, internal admin tools, and every other service directly.
Stale rules never cleaned up — temporary "allow my IP for debugging" rules that outlive the debugging session are a classic source of forgotten exposure; tag and periodically audit rules.
Relying on the firewall as the only control — a firewall stops unauthorized network access, but it doesn't stop SQL injection over an allowed port 443 connection; it's one layer of defense-in-depth, not a substitute for application-level security.
Not logging denied/allowed traffic — without flow logs (VPC Flow Logs, firewall logs), you have no way to investigate an incident after the fact or notice a slow port-scan happening right now.