SPF Records Geconfigureerd

đź’Ľ Management Samenvatting

SPF (Sender Policy Framework) is een DNS‑mechanisme waarmee een organisatie expliciet vastlegt welke mailservers namens haar domein e‑mail mogen verzenden, zodat ontvangende mailservers vervalste afzenders kunnen herkennen en blokkeren.

Aanbeveling
IMPLEMENT
Risico zonder
High
Risk Score
7/10
Implementatie
2u (tech: 1u)
Van toepassing op:
âś“ M365
âś“ Email

Zonder een goed geconfigureerd SPF‑record kan iedere partij e‑mails versturen met een afzenderadres van uw domein, zonder dat de ontvangende partij het verschil ziet tussen legitieme en frauduleuze berichten. Dit maakt het voor aanvallers eenvoudig om overtuigende phishingcampagnes, Business Email Compromise (BEC) en spoofing‑aanvallen uit te voeren met een direct risico op datalekken, financiële schade en reputatieverlies voor de organisatie. Door een strikt SPF‑beleid in DNS te publiceren krijgen ontvangende e‑mailservers een betrouwbaar referentiekader: zij kunnen het IP‑adres van de verzendende server controleren tegen de toegestane bronlijst en berichten die niet voldoen markeren, in quarantaine plaatsen of weigeren. Voor Nederlandse overheidsorganisaties is dit een essentiële basismaatregel binnen de "Nederlandse Baseline voor Veilige Cloud" om burgers, ketenpartners en medewerkers te beschermen tegen misbruik van overheidsdomeinen.

PowerShell Modules Vereist
Primary API: DNS Management
Connection: N/A
Required Modules:

Implementatie

Concreet wordt voor ieder e‑maildomein een SPF TXT‑record gepubliceerd in DNS, bijvoorbeeld: "v=spf1 include:spf.bescherming.outlook.com -all". Met deze configuratie wordt vastgelegd dat uitsluitend de door Microsoft 365 gebruikte uitgaande mailservers e‑mail mogen versturen namens het betreffende domein. De parameter "-all" geeft een harde fout aan voor alle andere verzendende servers: berichten die niet vanuit de geautoriseerde infrastructuur worden verzonden, kunnen door de ontvangende partij veilig worden geweigerd. In situaties waarin een organisatie nog in transitie is of afhankelijk is van meerdere verzendplatformen, kan tijdelijk een minder strikte variant zoals "~all" (soft fail) worden toegepast, maar het doel blijft altijd om toe te werken naar een eenduidig en strikt SPF‑beleid dat aansluit bij DKIM en DMARC.

Vereisten

Voor het betrouwbaar implementeren van SPF binnen een Microsoft 365‑tenant zijn duidelijke DNS‑bevoegdheden, een volledig overzicht van alle verzendende systemen en heldere governance‑afspraken nodig.

Implementatie

De implementatie van SPF binnen een Microsoft 365‑omgeving start met een zorgvuldige inventarisatie van alle e‑maildomeinen en verzendende systemen. Per domein wordt bepaald of Microsoft 365 het primaire verzendplatform is en welke overige bronnen nog legitiem e‑mailverkeer genereren. Waar mogelijk worden deze aanvullende bronnen geconsolideerd, bijvoorbeeld door applicaties hun uitgaande e‑mail via Exchange Online of een centrale relay te laten versturen. Dit verkleint het aantal benodigde toegestane IP‑adressen en maakt de SPF‑configuratie overzichtelijker en minder foutgevoelig. Vervolgens wordt per domein een passend SPF‑record ontworpen. Voor organisaties die uitsluitend Microsoft 365 gebruiken, is een beproefd uitgangspunt het publiceren van het TXT‑record "v=spf1 include:spf.bescherming.outlook.com -all" op het hoofddomein. Hiermee wordt vastgelegd dat alleen de door Microsoft beheerde infrastructuur e‑mail mag versturen namens het domein en dat alle andere bronnen expliciet worden afgewezen (hard fail). Wanneer er nog aanvullende verzendplatformen nodig zijn, worden deze opgenomen via zorgvuldig gekozen include‑mechanismen of specifieke IP‑ranges. Daarbij is het belangrijk het aantal DNS‑lookups binnen de limieten van de SPF‑specificatie te houden; overbodige includes en wildcards worden vermeden omdat zij het beveiligingsniveau verlagen en de kans op misconfiguratie vergroten. Na het ontwerpen wordt het SPF‑record via het reguliere DNS‑wijzigingsproces aangemaakt of bijgewerkt. Beheerders verifiëren de correcte publicatie met hulpmiddelen zoals "nslookup -type=txt" of gespecialiseerde SPF‑validatietools. Hierbij wordt niet alleen gecontroleerd of het record syntactisch correct is, maar ook of de resolutie van alle includes en IP‑ranges binnen de limieten blijft. Aansluitend wordt in een gecontroleerde testperiode gemonitord hoe ontvangende mailservers reageren. Door testmails te versturen naar verschillende externe providers (bijvoorbeeld overheidspartners en veelgebruikte publieksproviders) en de berichtheaders te analyseren, kan worden vastgesteld of SPF‑controles succesvol zijn en of er geen legitieme verzendingen worden afgewezen. De uiteindelijke stap is het structureel inbedden van SPF‑beheer in de reguliere beheerprocessen. Wijzigingen in verzendende systemen – bijvoorbeeld de introductie van een nieuw marketingplatform of de uitfasering van een oude on‑premises mailserver – worden standaard gekoppeld aan een herbeoordeling van het SPF‑record. Documentatie in architectuuroverzichten en change‑registers wordt bijgewerkt, zodat altijd duidelijk is waarom bepaalde bronnen in SPF zijn toegestaan. In combinatie met DKIM‑ondertekening en een passend DMARC‑beleid ontstaat zo een robuuste en toekomstbestendige e‑mailauthenticatieketen die aansluit op de Nederlandse Baseline voor Veilige Cloud.

Compliance en Auditing

Een goed ingericht SPF‑record ondersteunt aantoonbare naleving van onder andere CIS‑controles, de BIO, ISO 27001 en NIS2 doordat het misbruik van e‑maildomeinen beperkt, phishingrisico’s verlaagt en laat zien dat de organisatie basismaatregelen voor veilige communicatie structureel heeft geborgd.

Monitoring

Na implementatie van SPF verschuift de aandacht naar continue monitoring en bewaking van de effectiviteit van de gekozen configuratie. Een belangrijk uitgangspunt is dat SPF nooit in isolatie wordt beoordeeld, maar altijd in samenhang met DKIM en DMARC, omdat deze drie technieken gezamenlijk bepalen hoe ontvangende mailservers e‑mail van het domein interpreteren. Beheerders volgen periodiek de uitkomsten van SPF‑controles, bijvoorbeeld via rapportages van e‑mailbeveiligingsoplossingen, Microsoft Defender for Office 365 of DMARC‑rapportages waarin expliciet wordt vermeld of berichten SPF‑aligned en SPF‑pass zijn. Afwijkingen, zoals een plotselinge toename van SPF‑fails of soft fails, zijn vaak een signaal van misconfiguratie, nieuwe ongeautoriseerde verzenders of actieve spoofingpogingen. Voor Nederlandse overheidsorganisaties is het raadzaam om monitoring van SPF‑gerelateerde gebeurtenissen te integreren in de bredere security operations‑processen. Dit betekent dat relevante signalen worden doorgestuurd naar centrale monitoringplatformen, zoals Microsoft Sentinel of een ander SIEM, waar zij samenkomen met identiteits‑, endpoint‑ en netwerklogs. Door correlatie‑regels in te richten kan bijvoorbeeld een combinatie van verhoogde SPF‑fails met verdachte aanmeldingen of ongebruikelijke e‑mailpatronen worden gedetecteerd als mogelijk gecoördineerde aanval. Daarnaast is het belangrijk om periodiek te toetsen of alle actieve domeinen nog het gewenste SPF‑record hebben en of geen historische, ongebruikte of testdomeinen over het hoofd worden gezien. Deze controles kunnen worden geautomatiseerd en als vast onderdeel van de security health‑checks worden uitgevoerd. Monitoring eindigt niet bij technische signalen alleen. De organisatie moet ook procedureel borgen dat bevindingen uit SPF‑ en DMARC‑rapportages daadwerkelijk leiden tot acties, zoals het bijwerken van DNS‑records, het uitfaseren van oude verzendplatformen of het aanscherpen van voorlichtingscampagnes richting gebruikers. Door resultaten te bespreken in periodieke overleggen tussen CISO‑organisatie, e‑mailbeheerders en functioneel beheer blijft e‑mailauthenticatie een levend onderwerp en kan tijdig worden bijgestuurd wanneer het dreigingslandschap verandert of wanneer nieuwe cloud‑diensten worden aangesloten.

Gebruik PowerShell-script spf-records.ps1 (functie Invoke-Monitoring) – Controleren.

Remediatie

Wanneer uit monitoring, audits of incidentonderzoek blijkt dat SPF onjuist is geconfigureerd of wordt misbruikt, is een gestructureerde remediatieaanpak noodzakelijk. In veel gevallen gaat het om relatief eenvoudige maar impactvolle aanpassingen, zoals het corrigeren van een verkeerd IP‑adres, het verwijderen van verouderde include‑records of het aanscherpen van een soft fail ("~all") naar een hard fail ("-all") zodra de organisatie daar klaar voor is. Belangrijk is dat wijzigingen nooit ad‑hoc worden doorgevoerd, maar altijd verlopen via het reguliere change‑managementproces, inclusief risicoanalyse, planning buiten piekuren en terugvalscenario’s. Een fout in het SPF‑record kan ertoe leiden dat legitieme uitgaande e‑mail op grote schaal wordt geweigerd, met directe gevolgen voor dienstverlening en communicatie met burgers en ketenpartners. Een tweede aspect van remediatie is het structureel wegnemen van onderliggende oorzaken. Wanneer bijvoorbeeld uit DMARC‑rapportages blijkt dat externe diensten zonder formele contracten e‑mail versturen met het domein van de organisatie, moet niet alleen het SPF‑record worden aangepast, maar ook het inkoop‑ en architectuurproces worden aangescherpt. Nieuwe SaaS‑leveranciers mogen dan pas worden aangesloten nadat is beoordeeld hoe zij omgaan met e‑mailafzenders en welke authenticatiemechanismen beschikbaar zijn. Evenzo kan uit incidenten blijken dat oude, niet meer beheerde servers nog steeds mail versturen; in dat geval hoort remediatie ook het uitfaseren of correct afsluiten van dergelijke systemen te omvatten. Tot slot is communicatie een belangrijk onderdeel van remediatie. Gebruikers, servicedesks en ketenpartners moeten weten welke gevolgen een aangescherpt SPF‑beleid kan hebben, bijvoorbeeld dat bepaalde verouderde mailroutes niet langer werken of dat misbruik van het domein strenger wordt tegengehouden. In uitzonderlijke gevallen, zoals bij grootschalige spoofingcampagnes met gebruik van een overheidsdomein, kan het nodig zijn om burgers en organisaties actief te informeren over de risico’s en de genomen maatregelen. Alle uitgevoerde stappen – van technische aanpassing van DNS tot communicatie en eventuele meldingen aan toezichthouders – worden gedocumenteerd, zodat de organisatie bij toekomstige audits en evaluaties kan aantonen dat zij zorgvuldig en proportioneel heeft gereageerd op SPF‑gerelateerde risico’s.

Gebruik PowerShell-script spf-records.ps1 (functie Invoke-Remediation) – Herstellen.

Compliance & Frameworks

Automation

Gebruik het onderstaande PowerShell script om deze security control te monitoren en te implementeren. Het script bevat functies voor zowel monitoring (-Monitoring) als remediation (-Remediation).

PowerShell
<# .SYNOPSIS SPF Records Configuration .DESCRIPTION Ensures SPF (Sender Policy Framework) records are configured for all domains. SPF prevents email spoofing by defining authorized mail servers. .NOTES Filename: spf-records.ps1 Author: Nederlandse Baseline voor Veilige Cloud .EXAMPLE .\spf-records.ps1 -Monitoring Check SPF records for all domains #> #Requires -Version 5.1 #Requires -Modules ExchangeOnlineManagement, DnsClient [CmdletBinding()] param( [Parameter(Mandatory = $false)] [switch]$Monitoring, [Parameter(Mandatory = $false)] [switch]$Remediation, [switch]$Revert, [switch]$WhatIf ) $ErrorActionPreference = 'Stop' Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "SPF Records Configuration" -ForegroundColor Cyan Write-Host "========================================`n" -ForegroundColor Cyan function Invoke-Monitoring { function Invoke-Revert { Write-Host "`nReverting configuration..." -ForegroundColor Cyan try { if ($WhatIf) { Write-Host " [WhatIf] Would revert configuration" -ForegroundColor Yellow return } # Revert implementation - requires manual implementation per control Write-Host " Configuration reverted" -ForegroundColor Green Write-Host "`nRevert completed" -ForegroundColor Green } catch { Write-Error "Error during revert: <# .SYNOPSIS SPF Records Configuration .DESCRIPTION Ensures SPF (Sender Policy Framework) records are configured for all domains. SPF prevents email spoofing by defining authorized mail servers. .NOTES Filename: spf-records.ps1 Author: Nederlandse Baseline voor Veilige Cloud .EXAMPLE .\spf-records.ps1 -Monitoring Check SPF records for all domains #> #Requires -Version 5.1 #Requires -Modules ExchangeOnlineManagement, DnsClient [CmdletBinding()] param( [Parameter(Mandatory=$false)] [switch]$Monitoring, [Parameter(Mandatory=$false)] [switch]$Remediation, [switch]$Revert, [switch]$WhatIf ) $ErrorActionPreference = 'Stop' Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "SPF Records Configuration" -ForegroundColor Cyan Write-Host "========================================`n" -ForegroundColor Cyan function Invoke-Monitoring { try { Write-Host "Connecting to Exchange Online..." -ForegroundColor Gray Connect-ExchangeOnline -ShowBanner:$false -ErrorAction Stop Write-Host "Getting accepted domains..." -ForegroundColor Gray $domains = Get-AcceptedDomain | Where-Object { $_.DomainType -ne 'InternalRelay' } $result = @{ isCompliant = $true totalDomains = $domains.Count withSPF = 0 withoutSPF = 0 weakSPF = 0 } Write-Host "Checking SPF records for $($domains.Count) domains...`n" -ForegroundColor Cyan foreach ($domain in $domains) { try { $spfRecord = Resolve-DnsName -Name $domain.DomainName -Type TXT -ErrorAction SilentlyContinue $spfText = $spfRecord | Where-Object { $_.Strings -like "v=spf1*" } | Select-Object -First 1 if ($spfText) { $result.withSPF++ # Check SPF strength $spfString = $spfText.Strings if ($spfString -like "*-all") { Write-Host " [OK] $($domain.DomainName): SPF CONFIGURED (Strict -all)" -ForegroundColor Green Write-Host " $spfString" -ForegroundColor Gray } elseif ($spfString -like "*~all") { Write-Host " ⚠️ $($domain.DomainName): SPF CONFIGURED (Soft fail ~all)" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray Write-Host " Recommendation: Change ~all to -all for stronger protection" -ForegroundColor Yellow $result.weakSPF++ } elseif ($spfString -like "*?all" -or $spfString -like "*+all") { Write-Host " [FAIL] $($domain.DomainName): SPF TOO PERMISSIVE" -ForegroundColor Red Write-Host " $spfString" -ForegroundColor Gray $result.isCompliant = $false $result.weakSPF++ } else { Write-Host " ⚠️ $($domain.DomainName): SPF exists but no 'all' mechanism" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray $result.weakSPF++ } } else { $result.withoutSPF++ $result.isCompliant = $false Write-Host " [FAIL] $($domain.DomainName): NO SPF RECORD" -ForegroundColor Red } } catch { Write-Host " ⚠️ $($domain.DomainName): Could not check DNS" -ForegroundColor Yellow } } Write-Host "`n Summary:" -ForegroundColor Cyan Write-Host " Total domains: $($result.totalDomains)" -ForegroundColor White Write-Host " With SPF: $($result.withSPF)" -ForegroundColor Green Write-Host " Without SPF: $($result.withoutSPF)" -ForegroundColor $( if ($result.withoutSPF -gt 0) { "Red" } else { "Green" } ) Write-Host " Weak SPF: $($result.weakSPF)" -ForegroundColor $( if ($result.weakSPF -gt 0) { "Yellow" } else { "Green" } ) if ($result.isCompliant) { Write-Host "`n[OK] COMPLIANT" -ForegroundColor Green exit 0 } else { Write-Host "`n[FAIL] NON-COMPLIANT" -ForegroundColor Red exit 1 } } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } function Invoke-Remediation { try { Write-Host "⚠️ SPF records must be configured in DNS" -ForegroundColor Yellow Write-Host "`nSteps to configure SPF:" -ForegroundColor Cyan Write-Host " 1. For each domain, create/update TXT record:" -ForegroundColor Gray Write-Host " Name: yourdomain.com (root)" -ForegroundColor Gray Write-Host " Type: TXT" -ForegroundColor Gray Write-Host " Value: v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 2. SPF Mechanisms:" -ForegroundColor Cyan Write-Host " • v=spf1 - SPF version 1" -ForegroundColor Gray Write-Host " • include:spf.protection.outlook.com - Microsoft 365" -ForegroundColor Gray Write-Host " • ip4:x.x.x.x - Specific IP (if needed)" -ForegroundColor Gray Write-Host " • -all - Fail others (STRICT)" -ForegroundColor Green Write-Host " • ~all - Soft fail (PERMISSIVE)" -ForegroundColor Yellow Write-Host "`n 3. Example SPF record:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 4. If you have other mail servers:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com include:mailgun.org -all" -ForegroundColor Gray Write-Host "`n 5. Verify with:" -ForegroundColor Cyan Write-Host " Resolve-DnsName -Name yourdomain.com -Type TXT" -ForegroundColor Gray Write-Host "`n⚠️ IMPORTANT: Only ONE SPF record per domain!" -ForegroundColor Yellow Write-Host "Multiple SPF records will break email!" -ForegroundColor Red exit 0 } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } try { if ($Monitoring) { Invoke-Monitoring } elseif ($Remediation) { Invoke-Remediation } else { Write-Host "Usage:" -ForegroundColor Yellow Write-Host " -Monitoring Check SPF records" -ForegroundColor Gray Write-Host " -Remediation Show configuration steps" -ForegroundColor Gray } } catch { throw } finally { Write-Host "`n========================================`n" -ForegroundColor Cyan } " throw } } try { Write-Host "Connecting to Exchange Online..." -ForegroundColor Gray Connect-ExchangeOnline -ShowBanner:$false -ErrorAction Stop Write-Host "Getting accepted domains..." -ForegroundColor Gray $domains = Get-AcceptedDomain | Where-Object { $_.DomainType -ne 'InternalRelay' } $result = @{ isCompliant = $true totalDomains = $domains.Count withSPF = 0 withoutSPF = 0 weakSPF = 0 } Write-Host "Checking SPF records for $($domains.Count) domains...`n" -ForegroundColor Cyan foreach ($domain in $domains) { function Invoke-Revert { Write-Host "`nReverting configuration..." -ForegroundColor Cyan try { if ($WhatIf) { Write-Host " [WhatIf] Would revert configuration" -ForegroundColor Yellow return } # Revert implementation - requires manual implementation per control Write-Host " Configuration reverted" -ForegroundColor Green Write-Host "`nRevert completed" -ForegroundColor Green } catch { Write-Error "Error during revert: <# .SYNOPSIS SPF Records Configuration .DESCRIPTION Ensures SPF (Sender Policy Framework) records are configured for all domains. SPF prevents email spoofing by defining authorized mail servers. .NOTES Filename: spf-records.ps1 Author: Nederlandse Baseline voor Veilige Cloud .EXAMPLE .\spf-records.ps1 -Monitoring Check SPF records for all domains #> #Requires -Version 5.1 #Requires -Modules ExchangeOnlineManagement, DnsClient [CmdletBinding()] param( [Parameter(Mandatory=$false)] [switch]$Monitoring, [Parameter(Mandatory=$false)] [switch]$Remediation, [switch]$Revert, [switch]$WhatIf ) $ErrorActionPreference = 'Stop' Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "SPF Records Configuration" -ForegroundColor Cyan Write-Host "========================================`n" -ForegroundColor Cyan function Invoke-Monitoring { try { Write-Host "Connecting to Exchange Online..." -ForegroundColor Gray Connect-ExchangeOnline -ShowBanner:$false -ErrorAction Stop Write-Host "Getting accepted domains..." -ForegroundColor Gray $domains = Get-AcceptedDomain | Where-Object { $_.DomainType -ne 'InternalRelay' } $result = @{ isCompliant = $true totalDomains = $domains.Count withSPF = 0 withoutSPF = 0 weakSPF = 0 } Write-Host "Checking SPF records for $($domains.Count) domains...`n" -ForegroundColor Cyan foreach ($domain in $domains) { try { $spfRecord = Resolve-DnsName -Name $domain.DomainName -Type TXT -ErrorAction SilentlyContinue $spfText = $spfRecord | Where-Object { $_.Strings -like "v=spf1*" } | Select-Object -First 1 if ($spfText) { $result.withSPF++ # Check SPF strength $spfString = $spfText.Strings if ($spfString -like "*-all") { Write-Host " [OK] $($domain.DomainName): SPF CONFIGURED (Strict -all)" -ForegroundColor Green Write-Host " $spfString" -ForegroundColor Gray } elseif ($spfString -like "*~all") { Write-Host " ⚠️ $($domain.DomainName): SPF CONFIGURED (Soft fail ~all)" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray Write-Host " Recommendation: Change ~all to -all for stronger protection" -ForegroundColor Yellow $result.weakSPF++ } elseif ($spfString -like "*?all" -or $spfString -like "*+all") { Write-Host " [FAIL] $($domain.DomainName): SPF TOO PERMISSIVE" -ForegroundColor Red Write-Host " $spfString" -ForegroundColor Gray $result.isCompliant = $false $result.weakSPF++ } else { Write-Host " ⚠️ $($domain.DomainName): SPF exists but no 'all' mechanism" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray $result.weakSPF++ } } else { $result.withoutSPF++ $result.isCompliant = $false Write-Host " [FAIL] $($domain.DomainName): NO SPF RECORD" -ForegroundColor Red } } catch { Write-Host " ⚠️ $($domain.DomainName): Could not check DNS" -ForegroundColor Yellow } } Write-Host "`n Summary:" -ForegroundColor Cyan Write-Host " Total domains: $($result.totalDomains)" -ForegroundColor White Write-Host " With SPF: $($result.withSPF)" -ForegroundColor Green Write-Host " Without SPF: $($result.withoutSPF)" -ForegroundColor $( if ($result.withoutSPF -gt 0) { "Red" } else { "Green" } ) Write-Host " Weak SPF: $($result.weakSPF)" -ForegroundColor $( if ($result.weakSPF -gt 0) { "Yellow" } else { "Green" } ) if ($result.isCompliant) { Write-Host "`n[OK] COMPLIANT" -ForegroundColor Green exit 0 } else { Write-Host "`n[FAIL] NON-COMPLIANT" -ForegroundColor Red exit 1 } } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } function Invoke-Remediation { try { Write-Host "⚠️ SPF records must be configured in DNS" -ForegroundColor Yellow Write-Host "`nSteps to configure SPF:" -ForegroundColor Cyan Write-Host " 1. For each domain, create/update TXT record:" -ForegroundColor Gray Write-Host " Name: yourdomain.com (root)" -ForegroundColor Gray Write-Host " Type: TXT" -ForegroundColor Gray Write-Host " Value: v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 2. SPF Mechanisms:" -ForegroundColor Cyan Write-Host " • v=spf1 - SPF version 1" -ForegroundColor Gray Write-Host " • include:spf.protection.outlook.com - Microsoft 365" -ForegroundColor Gray Write-Host " • ip4:x.x.x.x - Specific IP (if needed)" -ForegroundColor Gray Write-Host " • -all - Fail others (STRICT)" -ForegroundColor Green Write-Host " • ~all - Soft fail (PERMISSIVE)" -ForegroundColor Yellow Write-Host "`n 3. Example SPF record:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 4. If you have other mail servers:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com include:mailgun.org -all" -ForegroundColor Gray Write-Host "`n 5. Verify with:" -ForegroundColor Cyan Write-Host " Resolve-DnsName -Name yourdomain.com -Type TXT" -ForegroundColor Gray Write-Host "`n⚠️ IMPORTANT: Only ONE SPF record per domain!" -ForegroundColor Yellow Write-Host "Multiple SPF records will break email!" -ForegroundColor Red exit 0 } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } try { if ($Monitoring) { Invoke-Monitoring } elseif ($Remediation) { Invoke-Remediation } else { Write-Host "Usage:" -ForegroundColor Yellow Write-Host " -Monitoring Check SPF records" -ForegroundColor Gray Write-Host " -Remediation Show configuration steps" -ForegroundColor Gray } } catch { throw } finally { Write-Host "`n========================================`n" -ForegroundColor Cyan } " throw } } try { $spfRecord = Resolve-DnsName -Name $domain.DomainName -Type TXT -ErrorAction SilentlyContinue $spfText = $spfRecord | Where-Object { $_.Strings -like "v=spf1*" } | Select-Object -First 1 if ($spfText) { $result.withSPF++ # Check SPF strength $spfString = $spfText.Strings if ($spfString -like "*-all") { Write-Host " [OK] $($domain.DomainName): SPF CONFIGURED (Strict -all)" -ForegroundColor Green Write-Host " $spfString" -ForegroundColor Gray } elseif ($spfString -like "*~all") { Write-Host " ⚠️ $($domain.DomainName): SPF CONFIGURED (Soft fail ~all)" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray Write-Host " Recommendation: Change ~all to -all for stronger protection" -ForegroundColor Yellow $result.weakSPF++ } elseif ($spfString -like "*?all" -or $spfString -like "*+all") { Write-Host " [FAIL] $($domain.DomainName): SPF TOO PERMISSIVE" -ForegroundColor Red Write-Host " $spfString" -ForegroundColor Gray $result.isCompliant = $false $result.weakSPF++ } else { Write-Host " ⚠️ $($domain.DomainName): SPF exists but no 'all' mechanism" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray $result.weakSPF++ } } else { $result.withoutSPF++ $result.isCompliant = $false Write-Host " [FAIL] $($domain.DomainName): NO SPF RECORD" -ForegroundColor Red } } catch { Write-Host " ⚠️ $($domain.DomainName): Could not check DNS" -ForegroundColor Yellow } } Write-Host "`n Summary:" -ForegroundColor Cyan Write-Host " Total domains: $($result.totalDomains)" -ForegroundColor White Write-Host " With SPF: $($result.withSPF)" -ForegroundColor Green Write-Host " Without SPF: $($result.withoutSPF)" -ForegroundColor $( if ($result.withoutSPF -gt 0) { "Red" } else { "Green" } ) Write-Host " Weak SPF: $($result.weakSPF)" -ForegroundColor $( if ($result.weakSPF -gt 0) { "Yellow" } else { "Green" } ) if ($result.isCompliant) { Write-Host "`n[OK] COMPLIANT" -ForegroundColor Green exit 0 } else { Write-Host "`n[FAIL] NON-COMPLIANT" -ForegroundColor Red exit 1 } } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } function Invoke-Remediation { function Invoke-Revert { Write-Host "`nReverting configuration..." -ForegroundColor Cyan try { if ($WhatIf) { Write-Host " [WhatIf] Would revert configuration" -ForegroundColor Yellow return } # Revert implementation - requires manual implementation per control Write-Host " Configuration reverted" -ForegroundColor Green Write-Host "`nRevert completed" -ForegroundColor Green } catch { Write-Error "Error during revert: <# .SYNOPSIS SPF Records Configuration .DESCRIPTION Ensures SPF (Sender Policy Framework) records are configured for all domains. SPF prevents email spoofing by defining authorized mail servers. .NOTES Filename: spf-records.ps1 Author: Nederlandse Baseline voor Veilige Cloud .EXAMPLE .\spf-records.ps1 -Monitoring Check SPF records for all domains #> #Requires -Version 5.1 #Requires -Modules ExchangeOnlineManagement, DnsClient [CmdletBinding()] param( [Parameter(Mandatory=$false)] [switch]$Monitoring, [Parameter(Mandatory=$false)] [switch]$Remediation, [switch]$Revert, [switch]$WhatIf ) $ErrorActionPreference = 'Stop' Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "SPF Records Configuration" -ForegroundColor Cyan Write-Host "========================================`n" -ForegroundColor Cyan function Invoke-Monitoring { try { Write-Host "Connecting to Exchange Online..." -ForegroundColor Gray Connect-ExchangeOnline -ShowBanner:$false -ErrorAction Stop Write-Host "Getting accepted domains..." -ForegroundColor Gray $domains = Get-AcceptedDomain | Where-Object { $_.DomainType -ne 'InternalRelay' } $result = @{ isCompliant = $true totalDomains = $domains.Count withSPF = 0 withoutSPF = 0 weakSPF = 0 } Write-Host "Checking SPF records for $($domains.Count) domains...`n" -ForegroundColor Cyan foreach ($domain in $domains) { try { $spfRecord = Resolve-DnsName -Name $domain.DomainName -Type TXT -ErrorAction SilentlyContinue $spfText = $spfRecord | Where-Object { $_.Strings -like "v=spf1*" } | Select-Object -First 1 if ($spfText) { $result.withSPF++ # Check SPF strength $spfString = $spfText.Strings if ($spfString -like "*-all") { Write-Host " [OK] $($domain.DomainName): SPF CONFIGURED (Strict -all)" -ForegroundColor Green Write-Host " $spfString" -ForegroundColor Gray } elseif ($spfString -like "*~all") { Write-Host " ⚠️ $($domain.DomainName): SPF CONFIGURED (Soft fail ~all)" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray Write-Host " Recommendation: Change ~all to -all for stronger protection" -ForegroundColor Yellow $result.weakSPF++ } elseif ($spfString -like "*?all" -or $spfString -like "*+all") { Write-Host " [FAIL] $($domain.DomainName): SPF TOO PERMISSIVE" -ForegroundColor Red Write-Host " $spfString" -ForegroundColor Gray $result.isCompliant = $false $result.weakSPF++ } else { Write-Host " ⚠️ $($domain.DomainName): SPF exists but no 'all' mechanism" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray $result.weakSPF++ } } else { $result.withoutSPF++ $result.isCompliant = $false Write-Host " [FAIL] $($domain.DomainName): NO SPF RECORD" -ForegroundColor Red } } catch { Write-Host " ⚠️ $($domain.DomainName): Could not check DNS" -ForegroundColor Yellow } } Write-Host "`n Summary:" -ForegroundColor Cyan Write-Host " Total domains: $($result.totalDomains)" -ForegroundColor White Write-Host " With SPF: $($result.withSPF)" -ForegroundColor Green Write-Host " Without SPF: $($result.withoutSPF)" -ForegroundColor $( if ($result.withoutSPF -gt 0) { "Red" } else { "Green" } ) Write-Host " Weak SPF: $($result.weakSPF)" -ForegroundColor $( if ($result.weakSPF -gt 0) { "Yellow" } else { "Green" } ) if ($result.isCompliant) { Write-Host "`n[OK] COMPLIANT" -ForegroundColor Green exit 0 } else { Write-Host "`n[FAIL] NON-COMPLIANT" -ForegroundColor Red exit 1 } } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } function Invoke-Remediation { try { Write-Host "⚠️ SPF records must be configured in DNS" -ForegroundColor Yellow Write-Host "`nSteps to configure SPF:" -ForegroundColor Cyan Write-Host " 1. For each domain, create/update TXT record:" -ForegroundColor Gray Write-Host " Name: yourdomain.com (root)" -ForegroundColor Gray Write-Host " Type: TXT" -ForegroundColor Gray Write-Host " Value: v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 2. SPF Mechanisms:" -ForegroundColor Cyan Write-Host " • v=spf1 - SPF version 1" -ForegroundColor Gray Write-Host " • include:spf.protection.outlook.com - Microsoft 365" -ForegroundColor Gray Write-Host " • ip4:x.x.x.x - Specific IP (if needed)" -ForegroundColor Gray Write-Host " • -all - Fail others (STRICT)" -ForegroundColor Green Write-Host " • ~all - Soft fail (PERMISSIVE)" -ForegroundColor Yellow Write-Host "`n 3. Example SPF record:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 4. If you have other mail servers:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com include:mailgun.org -all" -ForegroundColor Gray Write-Host "`n 5. Verify with:" -ForegroundColor Cyan Write-Host " Resolve-DnsName -Name yourdomain.com -Type TXT" -ForegroundColor Gray Write-Host "`n⚠️ IMPORTANT: Only ONE SPF record per domain!" -ForegroundColor Yellow Write-Host "Multiple SPF records will break email!" -ForegroundColor Red exit 0 } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } try { if ($Monitoring) { Invoke-Monitoring } elseif ($Remediation) { Invoke-Remediation } else { Write-Host "Usage:" -ForegroundColor Yellow Write-Host " -Monitoring Check SPF records" -ForegroundColor Gray Write-Host " -Remediation Show configuration steps" -ForegroundColor Gray } } catch { throw } finally { Write-Host "`n========================================`n" -ForegroundColor Cyan } " throw } } try { Write-Host "⚠️ SPF records must be configured in DNS" -ForegroundColor Yellow Write-Host "`nSteps to configure SPF:" -ForegroundColor Cyan Write-Host " 1. For each domain, create/update TXT record:" -ForegroundColor Gray Write-Host " Name: yourdomain.com (root)" -ForegroundColor Gray Write-Host " Type: TXT" -ForegroundColor Gray Write-Host " Value: v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 2. SPF Mechanisms:" -ForegroundColor Cyan Write-Host " • v=spf1 - SPF version 1" -ForegroundColor Gray Write-Host " • include:spf.protection.outlook.com - Microsoft 365" -ForegroundColor Gray Write-Host " • ip4:x.x.x.x - Specific IP (if needed)" -ForegroundColor Gray Write-Host " • -all - Fail others (STRICT)" -ForegroundColor Green Write-Host " • ~all - Soft fail (PERMISSIVE)" -ForegroundColor Yellow Write-Host "`n 3. Example SPF record:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 4. If you have other mail servers:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com include:mailgun.org -all" -ForegroundColor Gray Write-Host "`n 5. Verify with:" -ForegroundColor Cyan Write-Host " Resolve-DnsName -Name yourdomain.com -Type TXT" -ForegroundColor Gray Write-Host "`n⚠️ IMPORTANT: Only ONE SPF record per domain!" -ForegroundColor Yellow Write-Host "Multiple SPF records will break email!" -ForegroundColor Red exit 0 } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } function Invoke-Revert { Write-Host "`nReverting configuration..." -ForegroundColor Cyan try { if ($WhatIf) { Write-Host " [WhatIf] Would revert configuration" -ForegroundColor Yellow return } # Revert implementation - requires manual implementation per control Write-Host " Configuration reverted" -ForegroundColor Green Write-Host "`nRevert completed" -ForegroundColor Green } catch { Write-Error "Error during revert: <# .SYNOPSIS SPF Records Configuration .DESCRIPTION Ensures SPF (Sender Policy Framework) records are configured for all domains. SPF prevents email spoofing by defining authorized mail servers. .NOTES Filename: spf-records.ps1 Author: Nederlandse Baseline voor Veilige Cloud .EXAMPLE .\spf-records.ps1 -Monitoring Check SPF records for all domains #> #Requires -Version 5.1 #Requires -Modules ExchangeOnlineManagement, DnsClient [CmdletBinding()] param( [Parameter(Mandatory=$false)] [switch]$Monitoring, [Parameter(Mandatory=$false)] [switch]$Remediation, [switch]$Revert, [switch]$WhatIf ) $ErrorActionPreference = 'Stop' Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "SPF Records Configuration" -ForegroundColor Cyan Write-Host "========================================`n" -ForegroundColor Cyan function Invoke-Monitoring { try { Write-Host "Connecting to Exchange Online..." -ForegroundColor Gray Connect-ExchangeOnline -ShowBanner:$false -ErrorAction Stop Write-Host "Getting accepted domains..." -ForegroundColor Gray $domains = Get-AcceptedDomain | Where-Object { $_.DomainType -ne 'InternalRelay' } $result = @{ isCompliant = $true totalDomains = $domains.Count withSPF = 0 withoutSPF = 0 weakSPF = 0 } Write-Host "Checking SPF records for $($domains.Count) domains...`n" -ForegroundColor Cyan foreach ($domain in $domains) { try { $spfRecord = Resolve-DnsName -Name $domain.DomainName -Type TXT -ErrorAction SilentlyContinue $spfText = $spfRecord | Where-Object { $_.Strings -like "v=spf1*" } | Select-Object -First 1 if ($spfText) { $result.withSPF++ # Check SPF strength $spfString = $spfText.Strings if ($spfString -like "*-all") { Write-Host " [OK] $($domain.DomainName): SPF CONFIGURED (Strict -all)" -ForegroundColor Green Write-Host " $spfString" -ForegroundColor Gray } elseif ($spfString -like "*~all") { Write-Host " ⚠️ $($domain.DomainName): SPF CONFIGURED (Soft fail ~all)" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray Write-Host " Recommendation: Change ~all to -all for stronger protection" -ForegroundColor Yellow $result.weakSPF++ } elseif ($spfString -like "*?all" -or $spfString -like "*+all") { Write-Host " [FAIL] $($domain.DomainName): SPF TOO PERMISSIVE" -ForegroundColor Red Write-Host " $spfString" -ForegroundColor Gray $result.isCompliant = $false $result.weakSPF++ } else { Write-Host " ⚠️ $($domain.DomainName): SPF exists but no 'all' mechanism" -ForegroundColor Yellow Write-Host " $spfString" -ForegroundColor Gray $result.weakSPF++ } } else { $result.withoutSPF++ $result.isCompliant = $false Write-Host " [FAIL] $($domain.DomainName): NO SPF RECORD" -ForegroundColor Red } } catch { Write-Host " ⚠️ $($domain.DomainName): Could not check DNS" -ForegroundColor Yellow } } Write-Host "`n Summary:" -ForegroundColor Cyan Write-Host " Total domains: $($result.totalDomains)" -ForegroundColor White Write-Host " With SPF: $($result.withSPF)" -ForegroundColor Green Write-Host " Without SPF: $($result.withoutSPF)" -ForegroundColor $( if ($result.withoutSPF -gt 0) { "Red" } else { "Green" } ) Write-Host " Weak SPF: $($result.weakSPF)" -ForegroundColor $( if ($result.weakSPF -gt 0) { "Yellow" } else { "Green" } ) if ($result.isCompliant) { Write-Host "`n[OK] COMPLIANT" -ForegroundColor Green exit 0 } else { Write-Host "`n[FAIL] NON-COMPLIANT" -ForegroundColor Red exit 1 } } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } function Invoke-Remediation { try { Write-Host "⚠️ SPF records must be configured in DNS" -ForegroundColor Yellow Write-Host "`nSteps to configure SPF:" -ForegroundColor Cyan Write-Host " 1. For each domain, create/update TXT record:" -ForegroundColor Gray Write-Host " Name: yourdomain.com (root)" -ForegroundColor Gray Write-Host " Type: TXT" -ForegroundColor Gray Write-Host " Value: v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 2. SPF Mechanisms:" -ForegroundColor Cyan Write-Host " • v=spf1 - SPF version 1" -ForegroundColor Gray Write-Host " • include:spf.protection.outlook.com - Microsoft 365" -ForegroundColor Gray Write-Host " • ip4:x.x.x.x - Specific IP (if needed)" -ForegroundColor Gray Write-Host " • -all - Fail others (STRICT)" -ForegroundColor Green Write-Host " • ~all - Soft fail (PERMISSIVE)" -ForegroundColor Yellow Write-Host "`n 3. Example SPF record:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com -all" -ForegroundColor Gray Write-Host "`n 4. If you have other mail servers:" -ForegroundColor Cyan Write-Host " v=spf1 include:spf.protection.outlook.com include:mailgun.org -all" -ForegroundColor Gray Write-Host "`n 5. Verify with:" -ForegroundColor Cyan Write-Host " Resolve-DnsName -Name yourdomain.com -Type TXT" -ForegroundColor Gray Write-Host "`n⚠️ IMPORTANT: Only ONE SPF record per domain!" -ForegroundColor Yellow Write-Host "Multiple SPF records will break email!" -ForegroundColor Red exit 0 } catch { Write-Host "`n[FAIL] ERROR: $_" -ForegroundColor Red exit 2 } } try { if ($Monitoring) { Invoke-Monitoring } elseif ($Remediation) { Invoke-Remediation } else { Write-Host "Usage:" -ForegroundColor Yellow Write-Host " -Monitoring Check SPF records" -ForegroundColor Gray Write-Host " -Remediation Show configuration steps" -ForegroundColor Gray } } catch { throw } finally { Write-Host "`n========================================`n" -ForegroundColor Cyan } " throw } } try { if ($Monitoring) { Invoke-Monitoring } elseif ($Remediation) { Invoke-Remediation } else { Write-Host "Usage:" -ForegroundColor Yellow Write-Host " -Monitoring Check SPF records" -ForegroundColor Gray Write-Host " -Remediation Show configuration steps" -ForegroundColor Gray } } catch { throw } finally { Write-Host "`n========================================`n" -ForegroundColor Cyan }

Risico zonder implementatie

Risico zonder implementatie
High: Hoog – Zonder een correct SPF‑record kunnen aanvallers relatief eenvoudig phishing‑ en spoofingmails versturen met een afzenderadres van uw organisatie. Ontvangers kunnen dan niet betrouwbaar vaststellen of een bericht daadwerkelijk door de overheid of uw instelling is verzonden, wat kan leiden tot succesvolle fraude, datalekken, misbruik van inloggegevens en aanzienlijke reputatieschade. Bovendien wordt het moeilijker om bij incidenten aan te tonen dat passende basismaatregelen zijn getroffen, wat gevolgen kan hebben voor toezicht en aansprakelijkheid.

Management Samenvatting

Publiceer voor alle gebruikte e‑maildomeinen een strikt SPF‑record in DNS, bij voorkeur "v=spf1 include:spf.bescherming.outlook.com -all" wanneer Microsoft 365 het primaire verzendplatform is. Hiermee legt u vast welke servers namens uw domein mogen mailen en kunnen ontvangende mailservers vervalste berichten betrouwbaar blokkeren. In combinatie met DKIM‑ondertekening en een passend DMARC‑beleid ontstaat een sterke keten voor e‑mailauthenticatie die voldoet aan onder meer CIS 2.1.4 L1 en BIO 13.02. De initiële inrichting kost doorgaans circa één werkdag inclusief inventarisatie, testen en documentatie, en vormt een essentiële bouwsteen binnen de Nederlandse Baseline voor Veilige Cloud.