jan-karel.com
Home / Security Measures / Network & Active Directory / E-mail & DNS Hardening

E-mail & DNS Hardening

E-mail & DNS Hardening

E-mail & DNS Hardening

Privileges Down, Control Up

Attack paths become small once privileges, segments and management channels are consistently configured.

For E-mail & DNS Hardening the basis remains the same: less implicit trust and more visibility into anomalous behavior.

This way you not only reduce the chance of incidents, but especially the scope and duration when something goes wrong.

Immediate measures (15 minutes)

Why this matters

The core of E-mail & DNS Hardening is risk reduction in practice. Technical context supports the measure selection, but implementation and assurance are central.

SPF (Sender Policy Framework)

SPF is the first mechanism that prevents attackers from sending emails on behalf of your domain. It works simply: you publish a DNS TXT record that describes which mail servers are allowed to send on behalf of your domain. The receiving mail server checks whether the sending server is in that list.

How SPF works

The sender sends an email, the receiving server performs a DNS TXT lookup on the domain of the envelope-from, and checks whether the IP address of the sender is in the SPF record. Result: pass, fail, softfail, or neutral.

example.com.  IN  TXT  "v=spf1 <mechanisms> <qualifier>all"

Mechanisms

Mechanism Description Example
ip4 IPv4 address or CIDR range ip4:192.0.2.0/24
ip6 IPv6 address or CIDR range ip6:2001:db8::/32
include Refers to SPF record of another domain include:_spf.google.com
a A record of the domain itself a
mx MX records of the domain mx
exists DNS A lookup on specified domain exists:%{i}._spf.example.com
redirect Replaces SPF record with that of another domain redirect=_spf.example.com

Qualifiers

Qualifier Meaning Result
+ (default) Pass – sender is authorized Accept
- Hard fail – sender is not authorized Reject
~ Soft fail – sender is probably not authorized Accept but mark
? Neutral – no statement Accept

~all vs -all

The difference is crucial:

# Soft fail -- suspicious mail is still delivered (often to spam)
example.com.  IN  TXT  "v=spf1 include:_spf.google.com ~all"

# Hard fail -- unauthorized mail is rejected
example.com.  IN  TXT  "v=spf1 include:_spf.google.com -all"

Always use -all in production. ~all is intended as a temporary setting during rollout, not as a permanent policy. Yet most organizations run on ~all for years because "it works" and nobody ever adjusts it.

Examples for commonly used setups

Office 365:

example.com.  IN  TXT  "v=spf1 include:spf.protection.outlook.com -all"

Google Workspace:

example.com.  IN  TXT  "v=spf1 include:_spf.google.com -all"

Self-hosted (Postfix on 203.0.113.25):

example.com.  IN  TXT  "v=spf1 ip4:203.0.113.25 mx -all"

Combined (O365 + marketing tool + own server):

example.com.  IN  TXT  "v=spf1 include:spf.protection.outlook.com include:mail.marketingtool.com ip4:203.0.113.25 -all"

Common mistakes

  • Too many DNS lookups: SPF allows a maximum of 10 lookups (include, a, mx, exists, redirect). If you exceed this, the entire SPF check fails. Use ip4/ip6 where possible.
  • Too permissive: v=spf1 +all authorizes the entire world to send mail on behalf of your domain.
  • No SPF for subdomains: Attackers use subdomains without SPF records for phishing.

DKIM (DomainKeys Identified Mail)

DKIM adds a cryptographic signature to outgoing emails. The receiving server verifies the signature with a public key stored in DNS. This allows the recipient to establish that the message actually originates from the claimed domain and was not modified in transit.

How DKIM works

  1. The sending mail server calculates a hash of specific headers and the body
  2. The hash is signed with a private key
  3. The signature is added as a DKIM-Signature header
  4. The recipient retrieves the public key from DNS: selector._domainkey.example.com
  5. The recipient verifies the signature

DNS record

selector1._domainkey.example.com.  IN  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkqh..."

The selector is a freely chosen name (e.g. s1, google, selector1) that allows you to use multiple DKIM keys – useful for key rotation.

Key length

Use at least 2048 bits. RSA 1024-bit keys are considered insecure. Some organizations are transitioning to Ed25519 (k=ed25519), but support for this is still limited.

# Generate a 2048-bit RSA keypair for DKIM
opendkim-genkey -b 2048 -d example.com -s selector1

This produces two files: - selector1.private – the private key (on the mail server) - selector1.txt – the DNS TXT record (publish in DNS)

Key rotation

Rotate your DKIM keys at least annually: generate a new keypair with a new selector, publish the DNS record, wait for propagation, switch the mail server over, and remove the old record after 48 hours.

OpenDKIM configuration

# /etc/opendkim.conf
Syslog                  yes
Domain                  example.com
KeyFile                 /etc/opendkim/keys/selector1.private
Selector                selector1
Socket                  inet:8891@localhost
Canonicalization        relaxed/simple
Mode                    sv
SubDomains              yes
AutoRestart             yes
MinimumKeyBits          2048

DMARC (Domain-based Message Authentication)

DMARC builds on SPF and DKIM. It tells receiving mail servers what to do when a message fails both SPF and DKIM, and where to send reports.

How DMARC combines SPF and DKIM

DMARC requires alignment – the domain in the From: header must match: - The domain validated by SPF (envelope-from), or - The domain for which DKIM signed (d= parameter)

If neither is aligned, DMARC fails – regardless of whether SPF and DKIM individually pass.

Policy levels

Policy Action Usage
p=none Do nothing, only send reports Phase 1: monitoring
p=quarantine Place in spam/quarantine Phase 2: testing
p=reject Reject the message Phase 3: production

Rollout strategy

Roll out DMARC in phases. Do not go directly to p=reject, unless you enjoy discovering which systems are all sending mail on behalf of your domain.

Phase 1 – Monitoring (2-4 weeks):

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; ruf=mailto:dmarc-forensic@example.com; fo=1"

Phase 2 – Quarantine with percentage (2-4 weeks):

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc-reports@example.com"

Phase 3 – Quarantine 100% (2 weeks):

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com"

Phase 4 – Reject (end goal):

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@example.com; ruf=mailto:dmarc-forensic@example.com; fo=1"

Reports

Tag Type Description
rua Aggregate Daily XML reports with statistics on all mail traffic
ruf Forensic Detailed notifications per failed message (not all providers send these)
fo=1 Failure options Send forensic report when SPF or DKIM fails (not only when both fail)

Subdomain policy

Do not forget subdomains. Without sp=reject a subdomain inherits the main policy, but an attacker can use subdomains that are not in your SPF record:

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@example.com"

DMARC reporting tools

Manually parsing XML reports is an impossible task. Use a tool such as parsedmarc (open source, run locally), dmarcian (SaaS, free tier), DMARC Analyzer, or Postmark DMARC (free weekly summaries).

DNSSEC

DNSSEC protects against DNS spoofing and cache poisoning by cryptographically signing DNS responses. Without DNSSEC an attacker can inject forged DNS responses and redirect traffic to a malicious server – including your MX records.

How DNSSEC works

Record type Function
RRSIG Digital signature over a DNS record set
DNSKEY Public key used to verify RRSIG records
DS Hash of the DNSKEY, published in the parent zone (delegation signer)
NSEC/NSEC3 Proves that a domain does not exist (authenticated denial of existence)

The chain of trust runs from the root zone (.) via the TLD (.nl, .com) to your domain. Each layer contains a DS record that refers to the DNSKEY of the underlying zone.

How to activate

  1. At your DNS provider/registrar: Most major registrars (TransIP, Cloudflare, Route 53) support DNSSEC with a single button. Activate it and the provider automatically handles the DS record at the TLD.

  2. Self-hosted (BIND): Generate a ZSK and KSK with dnssec-keygen, sign the zone with dnssec-signzone, and publish the DS record at your registrar.

dnssec-keygen -a ECDSAP256SHA256 -n ZONE example.com        # ZSK
dnssec-keygen -a ECDSAP256SHA256 -n ZONE -f KSK example.com # KSK
dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) \
    -N INCREMENT -o example.com -t db.example.com

Validation testing

# Check if DNSSEC signatures are present
dig +dnssec example.com A

# Look for the 'ad' (Authenticated Data) flag in the response
dig +dnssec +multi example.com SOA

# Extended DNSSEC validation
delv @1.1.1.1 example.com A +rtrace

# Online test
# https://dnssec-analyzer.verisignlabs.com/

Note: a misconfigured DNSSEC makes your domain completely unreachable. Test thoroughly in a staging environment.

DNS filtering and sinkholing

DNS filtering blocks connections to known malware and phishing domains by manipulating the DNS response. Instead of returning the real IP address, the client receives a blocked page or an NXDOMAIN.

Response Policy Zone (RPZ)

RPZ is a standard for DNS firewalling. You load a list of malicious domains into your DNS resolver, and every query for those domains is blocked:

# /etc/bind/rpz.db
$TTL 300
@  IN  SOA  localhost. admin.localhost. (
   2024010101 3600 600 86400 300 )
   IN  NS   localhost.

; Block specific domain
malware-c2.evil.com     CNAME  .    ; NXDOMAIN
*.malware-c2.evil.com   CNAME  .    ; including subdomains

; Redirect to sinkhole
phishing.example.com    A      127.0.0.1

Solutions for organizations

Solution Type Suitable for
Pi-hole Self-hosted (blocklists) Small network, lab
NextDNS SaaS (AI + lists) SMB
Quad9 (9.9.9.9) Free resolver (threat intel) Everyone
Cloudflare Gateway SaaS (zero trust) Enterprise
Cisco Umbrella SaaS (comprehensive) Enterprise

Sinkholing

With sinkholing you point malicious domains to an internal server that logs the request. Every system that tries to resolve a C2 domain appears in your logs – ideal for detecting infected hosts:

# Unbound sinkhole configuration
local-zone: "malware-c2.evil.com" redirect
local-data: "malware-c2.evil.com A 10.0.0.100"

Additional DNS hardening

DoH (DNS over HTTPS) and DoT (DNS over TLS)

Standard DNS traffic is unencrypted (port 53/UDP). Anyone on the network can eavesdrop. DoH and DoT encrypt DNS queries:

Protocol Port Advantage Disadvantage
DoT 853/TCP Easy to filter at network level Visible as DoT traffic
DoH 443/TCP Indistinguishable from HTTPS traffic Difficult to monitor/block

For internal networks DoT is often the better choice – you can still monitor it via the network layer. DoH is more difficult because it runs over port 443, the same port as all other HTTPS traffic.

# Unbound DoT configuration (as forwarder)
server:
    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt

forward-zone:
    name: "."
    forward-tls-upstream: yes
    forward-addr: 1.1.1.1@853#cloudflare-dns.com
    forward-addr: 9.9.9.9@853#dns.quad9.net

Restrict zone transfers (AXFR)

An open zone transfer leaks your entire DNS zone – all hostnames, IP addresses, MX records. Restrict AXFR to your secondary nameservers:

# BIND - named.conf
zone "example.com" {
    type master;
    file "db.example.com";
    allow-transfer { 198.51.100.10; 198.51.100.11; };  # Secondary NS only
    also-notify { 198.51.100.10; 198.51.100.11; };
};

Test whether your zone transfer is actually blocked:

# This should fail
dig @ns1.example.com example.com AXFR

Disable DNS recursion on authoritative servers

Authoritative nameservers should not allow recursion. Only allow recursion on your internal resolvers:

# BIND - on the authoritative server
options {
    recursion no;
    allow-query { any; };
};

# BIND - on the internal resolver
options {
    recursion yes;
    allow-recursion { 10.0.0.0/8; 172.16.0.0/12; 192.168.0.0/16; };
};

MTA-STS (Mail Transfer Agent Strict Transport Security)

MTA-STS enforces that incoming mail servers use TLS when delivering email, thereby preventing TLS downgrade attacks. Configuration requires a DNS TXT record and a policy file:

_mta-sts.example.com.  IN  TXT  "v=STSv1; id=20240101T000000"

The policy file at https://mta-sts.example.com/.well-known/mta-sts.txt:

version: STSv1
mode: enforce
mx: mail.example.com
max_age: 86400

DANE (DNS-based Authentication of Named Entities)

DANE uses DNSSEC to bind TLS certificates to DNS names via TLSA records. This allows you to specify which certificate a mail server must present:

_25._tcp.mail.example.com.  IN  TLSA  3 1 1 a]b]c]d]e]f]...  (SHA-256 hash of certificate)

DANE requires a working DNSSEC configuration. Without DNSSEC, DANE has no value whatsoever.

TLS-RPT (SMTP TLS Reporting)

Similar to DMARC reports, but for TLS failures during mail delivery. Publish a _smtp._tls TXT record with a rua address to receive notifications when TLS connections fail.

_smtp._tls.example.com.  IN  TXT  "v=TLSRPTv1; rua=mailto:tls-reports@example.com"

The cynical note

Phishing has been the number-1 attack vector for ten years. Not number two. Not "one of the" vectors. Number. One. Every pentest, every red team exercise, every breach analysis – phishing is at the top. And the technology to stop it exists. SPF has been around since 2006. DKIM since 2007. DMARC since 2012. More than ten years ago.

And yet at least half of all organizations run without a proper DMARC record. Or they have p=none and think that they are protected. p=none literally does nothing. It is the equivalent of a security camera that records but that nobody watches.

The best are the organizations that buy an email security gateway for two hundred thousand euros – with sandboxing, AI detection, URL rewriting, and a dashboard that looks like NASA mission control – but forget to set up a DMARC record. That is like buying an armored door for your house but leaving the kitchen window open. The technology that is free and consists of three DNS records is too difficult. But an appliance that needs its own rack, that we do want.

The truth is simple: everything that does not have a vendor demo, does not generate a sales lunch, and does not have a nice dashboard, does not get implemented. SPF/DKIM/DMARC is free, so it is nobody's project. DNSSEC is a DNS setting, so it falls between operations and security in the no-man's land of "the other team will handle that." And meanwhile an attacker sends emails from any IP address on behalf of your CEO, because your domain has ~all instead of -all and your DMARC policy is set to none. But hey, that email gateway did detect the phish – in the demo.

Common mistakes

# Mistake Risk Solution
1 No SPF record Anyone can send mail on behalf of your domain Publish SPF with -all
2 SPF with ~all in production Spoofed mail is delivered (as spam) Change to -all
3 More than 10 DNS lookups in SPF SPF check fails completely (PermError) Use ip4/ip6, flatten includes
4 DKIM with 1024-bit key Key can be cracked Generate 2048-bit (or higher) keypair
5 DMARC at p=none as end goal No protection, only monitoring Roll out to p=reject
6 No DMARC record No control over spoofing policy Publish DMARC, start with p=none
7 Subdomains without SPF/DMARC Attackers use subdomains for spoofing sp=reject in DMARC, SPF per subdomain
8 Open zone transfer (AXFR) Entire DNS zone leaks to attackers Restrict allow-transfer
9 Recursion on authoritative DNS DNS amplification attacks, cache poisoning recursion no on authoritative servers
10 No DNSSEC Vulnerable to DNS spoofing/cache poisoning Activate DNSSEC at registrar
11 Never rotating DKIM keys Increased risk upon key compromise Annual key rotation
12 No MTA-STS TLS downgrade attacks on mail traffic Publish MTA-STS policy
13 No TLS-RPT No visibility into TLS issues during mail delivery Publish _smtp._tls TXT record
14 Not analyzing DMARC reports No visibility into spoofing attempts Use parsedmarc or SaaS tool
15 DNS over plain UDP internally DNS queries can be eavesdropped on the network Implement DoT for internal resolvers

Checklist

# Measure Priority Complexity Status
1 Publish SPF record with -all Critical Low
2 Enable DKIM (2048-bit) Critical Medium
3 Roll out DMARC (none -> quarantine -> reject) Critical Medium
4 DMARC sp=reject for subdomains High Low
5 Monitor DMARC reports High Medium
6 Activate DNSSEC High Low-Medium
7 Restrict zone transfers (AXFR) High Low
8 Disable recursion on authoritative servers High Low
9 Implement DNS filtering (RPZ/Quad9/NextDNS) High Medium
10 Configure MTA-STS Medium Medium
11 Publish DANE/TLSA records Medium High
12 DoT/DoH for internal resolvers Medium Medium
13 Enable TLS-RPT Medium Low
14 DKIM key rotation procedure Medium Medium
15 DNS sinkholing for C2 detection Medium Medium
16 Validate SPF record (< 10 lookups) High Low

Summary

Email and DNS together form the foundation of virtually all business communication, and thereby also the primary attack surface for phishing, spoofing and man-in-the-middle attacks. The defense consists of layers: SPF tells who is allowed to send mail, DKIM proves that the message is authentic, and DMARC combines both and defines the enforcement policy. DNSSEC protects the DNS infrastructure itself against manipulation. Additional measures such as MTA-STS, DANE, DNS filtering and sinkholing complete the chain. None of these technologies is new, none is particularly complex, and most are free. The only thing missing is the discipline to set them up, test them, and push through to p=reject. Three DNS records separate your domain from a phishing paradise and a well-protected mail infrastructure. The choice is not difficult – the execution apparently is.

In the next chapter we cover MSSQL hardening: how to secure SQL Server instances against abuse of xp_cmdshell, linked servers, and credential harvesting via UNC path injection.

Op de hoogte blijven?

Ontvang maandelijks cybersecurity-inzichten in je inbox.

← Network & Active Directory ← Home