How to Implement DNS Security Controls: RPZ, DNSSEC, and DNS Filtering

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
DNS is the first step in nearly every network attack: before malware can reach its C2 server, before ransomware can download a payload, before a phishing site can load, a DNS lookup must succeed. This makes the DNS resolver the highest-leverage security control in the network: blocking the DNS lookup stops the entire attack chain before a single packet reaches the destination.
RPZ blocklists implement this at the recursive resolver by intercepting queries to known-malicious domains and returning NXDOMAIN (or a sinkhole IP) instead. Combined with DNS query logging for threat hunting, this gives both preventive and detective coverage for DNS-based attacks.
BIND9 RPZ Configuration
# Install BIND9 on Ubuntu:
apt install bind9 bind9-utils -y
# Edit /etc/bind/named.conf.options:
options {
# ... existing options ...
# Enable DNSSEC validation:
dnssec-validation auto;
# Enable query logging:
querylog yes;
# Configure RPZ:
response-policy {
zone "rpz.malware-domains.local" policy NXDOMAIN;
zone "rpz.phishing.local" policy NXDOMAIN;
# Multiple zones processed in order; first match wins
};
};
# Create the RPZ zone file: /etc/bind/db.rpz.malware
$TTL 300
@ IN SOA localhost. root.localhost. (
2024010101 ; Serial
3600 ; Refresh
900 ; Retry
604800 ; Expire
300 ) ; Negative Cache TTL
@ IN NS localhost.
; Block specific malicious domains:
evil-c2-domain.com IN CNAME .
*.evil-c2-domain.com IN CNAME .
malware-dist.net IN CNAME .
*.malware-dist.net IN CNAME .
# CNAME . = NXDOMAIN (no such domain response)
# Add the RPZ zone to named.conf.local:
zone "rpz.malware-domains.local" {
type master;
file "/etc/bind/db.rpz.malware";
allow-query { none; };
};
# Restart BIND9:
named-checkconf && systemctl restart bind9
# Test RPZ is working:
dig evil-c2-domain.com @localhost
# Expected: NXDOMAIN with authority section from RPZ zone
# Check BIND9 logs for RPZ hits:
tail -f /var/log/named/named.log | grep 'rpz'
Subscribe to external RPZ threat intelligence feeds:
# Configure BIND9 to pull RPZ from a remote threat intelligence provider:
# Many vendors provide RPZ feeds (Spamhaus, SURBL, Farsight Security)
# Example: Spamhaus RPZ DNSBL (subscription required for enterprise use):
zone "rpz.spamhaus.org" {
type slave;
masters { [spamhaus-transfer-ip] port 53; };
file "/var/cache/bind/db.rpz.spamhaus";
allow-query { none; };
};
# Free option: use Pi-hole as RPZ frontend with community blocklists:
# Pi-hole integrates with Gravity (blocklist aggregator) for free DNS blocking
Windows DNS Server RPZ
Windows DNS Server added Response Policy Zone support in Windows Server 2016.
# Check Windows DNS Server version (RPZ requires Server 2016+):
Get-DnsServerSetting | Select-Object -ExpandProperty BuildNumber
# Add a Response Policy Zone to Windows DNS:
Add-DnsServerResponsePolicyZone \
-Name 'rpz.malware-blocks' \
-TransferTo 'None' \
-PassThru
# Add specific domain blocking rules to the RPZ:
# Block a specific domain:
Add-DnsServerResponsePolicyZoneRule \
-ZoneName 'rpz.malware-blocks' \
-Name 'evil-c2-domain.com.' \
-QType '*' \
-Action NXDomain
# Block a domain and all subdomains:
Add-DnsServerResponsePolicyZoneRule \
-ZoneName 'rpz.malware-blocks' \
-Name '*.evil-c2-domain.com.' \
-QType '*' \
-Action NXDomain
# Import a blocklist from file (mass import):
$blocklist = Get-Content 'C:\DNS\blocklist.txt' # One domain per line
foreach ($domain in $blocklist) {
Add-DnsServerResponsePolicyZoneRule \
-ZoneName 'rpz.malware-blocks' \
-Name "$domain." \
-QType '*' \
-Action NXDomain
Add-DnsServerResponsePolicyZoneRule \
-ZoneName 'rpz.malware-blocks' \
-Name "*.$domain." \
-QType '*' \
-Action NXDomain
}
# Verify RPZ is working:
Resolve-DnsName evil-c2-domain.com -Server [DNS-server-IP]
# Expected: no result returned (NXDomain)
# Enable Windows DNS audit logging (query logging):
Set-DnsServerDiagnostics \
-Queries $true \
-Answers $true \
-FullPackets $false \
-LogFilePath 'C:\Windows\System32\dns\dns-query-log.txt' \
-MaxMBFileSize 500
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
DNS Query Logging and Threat Detection
Forward Windows DNS queries to Sentinel:
Windows DNS Server query logging writes to:
%SystemRoot%\System32\dns\dns-query-log.txt
Forward to Log Analytics workspace via:
- Azure Monitor Agent (AMA) with a custom table data collection rule
- Or: Microsoft Sentinel DNS connector (native integration for Windows DNS)
In Sentinel: Data connectors > DNS (Preview) > Connect
This automatically parses Windows DNS debug log format into:
DnsEvents table in Log Analytics
Threat hunting with DNS query logs:
// Detect DNS tunneling: high-volume queries with long subdomain names
DnsEvents
| where TimeGenerated > ago(24h)
| where SubType == "LookupQuery"
// Long subdomain names are characteristic of DNS tunneling (encoded data):
| extend SubdomainLength = strlen(extract(@'^([^.]+)\.', 1, Name))
| where SubdomainLength > 40 // 40+ char subdomain = likely encoded payload
// High query volume from one host to one domain:
| summarize
QueryCount = count(),
LongQueries = countif(SubdomainLength > 40)
by Computer, Domain = tostring(split(Name, ".", 1)), bin(TimeGenerated, 1h)
| where LongQueries > 20 // Many long queries = DNS tunneling
| order by LongQueries desc
// Detect beaconing: regular-interval DNS queries to same domain
DnsEvents
| where TimeGenerated > ago(24h)
| where SubType == "LookupQuery"
// Look for consistent query intervals (C2 beaconing signature):
| summarize
QueryCount = count(),
Times = make_list(TimeGenerated, 100)
by Computer, Name
| where QueryCount > 50 // Minimum query count to analyze
// High count, regular interval = beacon pattern
| order by QueryCount desc
// Detect newly registered domains (high risk):
DnsEvents
| where TimeGenerated > ago(24h)
| join kind=inner (
ThreatIntelligenceIndicator
| where Active == true
| where NetworkDnsName != ""
| project MaliciousDomain = NetworkDnsName, IndicatorId
) on $left.Name == $right.MaliciousDomain
| project TimeGenerated, Computer, Name, IndicatorId
// Match against MISP or other TIP indicators
Block DNS-over-HTTPS and Maintain Visibility
DNS-over-HTTPS (DoH) encrypts DNS queries inside HTTPS: bypassing corporate DNS resolvers, RPZ blocklists, and query logging. Attackers increasingly use DoH to evade DNS-based controls.
Block known DoH providers at the firewall:
Block outbound HTTPS to DoH provider IPs:
# Major DoH providers (Palo Alto, Cisco, Fortinet have signature-based blocks):
# Cloudflare: 1.1.1.1, 1.0.0.1
# Google: 8.8.8.8, 8.8.4.4
# Quad9: 9.9.9.9, 149.112.112.112
# NextDNS: 45.90.28.0/23
# Firewall rule: block outbound HTTPS (443) to these IPs
# This prevents DoH bypassing the corporate DNS resolver
# Exception: allow DNS (UDP/TCP 53) to corporate DNS resolver ONLY
# Block DNS to all other destinations:
# Deny outbound UDP/TCP 53 to anything except [corporate DNS IPs]
Windows GPO to prevent browser DoH:
For Chrome:
Computer Configuration > Administrative Templates > Google > Google Chrome >
"DNS interception checks enabled": Disabled
"Use built-in DNS client": Disabled
For Firefox:
Deploy enterprise policy via GPO:
Computer Configuration > Administrative Templates > Mozilla > Firefox >
"DNS over HTTPS": Disabled (or set to "off")
Or via registry:
HKCU\SOFTWARE\Policies\Mozilla\Firefox
DNSOverHTTPS.Enabled = 0
Configure DNSSEC validation on Windows DNS:
# Enable DNSSEC validation on Windows DNS resolver:
Set-DnsServerRecursion -Enable $true
# DNSSEC validation is enabled by default in Windows Server 2012+
# Verify DNSSEC validation is active:
Resolve-DnsName dnssec-failed.org -Type A
# If DNSSEC is working: this should return SERVFAIL (intentionally failing domain)
Resolve-DnsName dnssec.works -Type A
# This should return a valid IP (intentionally working DNSSEC domain)
# Check DNSSEC status on a specific zone:
Get-DnsServerDnsSecZoneSetting -ZoneName 'yourdomain.com'
The bottom line
DNS security requires four controls: (1) RPZ blocklists: configure BIND9 or Windows DNS Server with Response Policy Zones that return NXDOMAIN for known-malicious domains; subscribe to external threat feeds; (2) DNS query logging: enable Windows DNS debug logging or BIND9 querylog and forward to Sentinel's DnsEvents table; (3) DNS tunneling detection: alert on subdomains longer than 40 characters and high-frequency queries from a single host to a single domain; (4) block DoH: deny outbound HTTPS to known DoH provider IPs and outbound DNS to all except corporate resolvers, and disable browser DoH via GPO to maintain resolver visibility.
Frequently asked questions
What is a Response Policy Zone and how does it block malware?
A Response Policy Zone (RPZ) is a special DNS zone that overrides normal DNS resolution for specified domains: when a client queries for a domain that matches an RPZ entry, the resolver returns NXDOMAIN (or a configured sinkhole address) instead of the real IP. The client never makes a TCP connection to the malware infrastructure because the DNS lookup fails first. RPZ operates at the recursive resolver level, so all clients using that resolver are protected without any client-side configuration. BIND9 and Windows DNS Server both support RPZ natively.
How do you detect DNS tunneling in enterprise environments?
DNS tunneling encodes data in DNS query strings: the subdomain portion of the query contains base32/base64-encoded payload data, producing unusually long (40+ characters) and high-entropy subdomains. Detection uses two signals: query length anomaly (subdomains significantly longer than legitimate domain names) and query volume anomaly (hundreds of queries per hour to a single domain from one host). Analyze DNS query logs with `strlen(extract('^([^.]+)\.', 1, Name)) > 40` to find long subdomains, and `summarize count() by Computer, Domain` to find hosts generating abnormal DNS query volumes.
What is DNSSEC and should I implement it for internal enterprise DNS?
DNSSEC (DNS Security Extensions) cryptographically signs DNS records, allowing resolvers to verify that responses were not tampered with in transit. It protects against DNS cache poisoning and man-in-the-middle attacks on DNS resolution. For external-facing domains: DNSSEC is strongly recommended and many registrars support it with minimal configuration. For internal Active Directory DNS: DNSSEC is generally not implemented because AD-integrated DNS operates on trusted internal networks, DNSSEC adds operational complexity (key rotation, broken resolution on misconfigurations), and the primary internal DNS attack (LLMNR/NBT-NS poisoning) is not mitigated by DNSSEC. Prioritize disabling LLMNR and NBT-NS for internal security over implementing DNSSEC.
How do I set up DNS-over-HTTPS (DoH) filtering for an enterprise network?
Enterprise DoH implementation for security filtering: deploy a central DoH-capable recursive resolver (Cisco Umbrella, Cloudflare Gateway, or a self-hosted bind9/Unbound with DoH support) and configure clients to use it. Block or redirect public DoH providers (1.1.1.1, 8.8.8.8, 9.9.9.9 on port 443) via firewall rules to prevent DoH bypass of corporate filtering: use Cisco Umbrella's DoH IP block list or create custom firewall rules blocking DoH traffic not destined for your corporate resolver. Configure Windows 11 and Chrome/Edge DoH settings via Group Policy: set the 'Configure DNS over HTTPS' policy to 'Secure Only' pointing to your corporate DoH endpoint. This maintains DNS-based security controls (RPZ blocking) even when clients use encrypted DNS.
What is DNS Response Policy Zone (RPZ) and how is it different from a hosts file?
An RPZ is managed at the DNS resolver level and applies to all clients using that resolver automatically, without any client-side configuration. A hosts file requires manual editing on each individual machine and does not update automatically. RPZ advantages: centralized management (one feed update applies to all clients instantly), supports dynamic threat intelligence feeds (BIND9 and Windows DNS Server can pull RPZ feeds from commercial providers like Infoblox, Cisco Umbrella, and community sources like the Spamhaus domain block list), and provides visibility (DNS query logs show which clients attempted to resolve blocked domains). Hosts file approach is impractical at enterprise scale: a 50,000-entry hosts file deployed via GPO is operationally unmanageable compared to a centrally maintained RPZ.
How do you triage a DNS tunneling alert without disrupting legitimate traffic from the same host?
DNS tunneling triage starts with passive analysis before any blocking action. Pull the full DNS query log for the alerting host and the flagged domain from the past 24 hours: examine the subdomain strings for base32 or base64 character distributions (high proportion of A-Z2-7 for base32, or A-Za-z0-9+/ for base64) versus the random-looking but low-entropy subdomains that content delivery networks legitimately generate. Calculate query frequency: a beaconing C2 tunnel typically sends queries at a consistent interval (every 30, 60, or 300 seconds) while legitimate applications generate burst traffic followed by silence. Check the TLD and domain registration age via WHOIS or a threat intelligence API: newly registered domains (less than 30 days old) with high-entropy subdomains are high-confidence tunneling. Cross-reference the destination domain against threat intelligence feeds (Cisco Umbrella Investigate, VirusTotal) before blocking. If the evidence is ambiguous, apply a DNS sinkhole to the flagged domain at the RPZ level (redirect to an internal IP you control) rather than NXDOMAIN: this preserves the connection attempt, lets you observe what data the client sends, and allows the endpoint team to collect a memory sample from the host for malware analysis.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
