# Mail server hardening checklist

## Support status and patching

- [ ] Run `Get-ExchangeServer | Format-List Name, Edition, AdminDisplayVersion` to get the build number
- [ ] Check that build against Microsoft's published Exchange build numbers page to confirm it is still supported
- [ ] Plan the move to Exchange Server Subscription Edition if the server is on Exchange 2016 or 2019
- [ ] Get the server onto a Cumulative Update that still receives Security Updates before applying anything else
- [ ] Run the Exchange Server Health Checker script from the CSS-Exchange repository and fix every red flag
- [ ] Confirm the Exchange Emergency Mitigation service is running and `MitigationsEnabled` is true for both organisation and server

## Cut the attack surface

- [ ] Enable Extended Protection with `ExchangeExtendedProtectionManagement.ps1` from the CSS-Exchange repository
- [ ] Review connectors with `Get-ReceiveConnector | Format-List Name, Bindings, RemoteIPRanges, PermissionGroups, AuthMechanism` and remove wide `AnonymousUsers` permissions
- [ ] Restrict `/ecp` to internal or management addresses at the reverse proxy or in IIS
- [ ] Set POP3 and IMAP4 to `Manual` and stop them unless an application genuinely needs them
- [ ] Check per-mailbox protocol access with `Get-CASMailbox` and turn off what is unused
- [ ] Match antivirus exclusions to Microsoft's published list exactly, with no broad drive or path exclusions

## Authentication and access

- [ ] Create the policy with `New-AuthenticationPolicy -Name "Block Basic Auth"`
- [ ] Apply it to a pilot group with `Set-User -Identity <user> -AuthenticationPolicy "Block Basic Auth"` before going wider
- [ ] Set the organisation default with `Set-OrganizationConfig -DefaultAuthenticationPolicy "Block Basic Auth"`
- [ ] Confirm AMSI integration is active with `Get-SettingOverride` and remove any `BypassBody` override
- [ ] Review `Get-ManagementRoleAssignment` and take Domain Admin accounts out of Exchange administration

## TLS and transport

- [ ] Disable SSL 2.0, SSL 3.0, TLS 1.0 and TLS 1.1 under `HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols`
- [ ] Enable TLS 1.2 in SCHANNEL and set `SystemDefaultTlsVersions` and `SchUseStrongCrypto` to `1` in the .NET Framework keys
- [ ] Change SCHANNEL and .NET together on every server in the DAG, or mail stops flowing between the ones that disagree
- [ ] Test outbound SMTP and Autodiscover with the Remote Connectivity Analyzer at `testconnectivity.microsoft.com`
- [ ] Check certificate expiry with `Get-ExchangeCertificate | Format-List Thumbprint, Services, NotAfter, Subject`
- [ ] Confirm backups are Exchange-aware, restore-tested, and kept where a domain compromise cannot reach them

## SPF, DKIM and DMARC

- [ ] Publish one DNS TXT record starting with `v=spf1` listing every server that sends mail for the domain
- [ ] Keep the total DNS lookups, including nested `include:` entries, at 10 or under to avoid a `permerror`
- [ ] Confirm no second SPF record exists, and merge duplicates into a single record
- [ ] Remove any `ptr` mechanism from the record
- [ ] Give each sending subdomain its own record, and publish `v=spf1 -all` on subdomains that send nothing
- [ ] Sign outbound mail with DKIM and publish DMARC at `p=none` with an `rua=` address before tightening anything

## Verify and keep verifying

- [ ] End the record with `~all` and watch DMARC aggregate reports for a few weeks to catch senders you missed
- [ ] Tighten to `-all` and move DMARC to `p=quarantine`, then `p=reject`, once the reports are clean
- [ ] Validate the live records with the [SPF, DKIM and DMARC checker](/tools/spf-dkim-dmarc-checker/)
- [ ] Keep an inventory of everything that sends mail as the domain, including MFPs, line-of-business apps and monitoring alerts
- [ ] Re-run the Exchange Server Health Checker after every Cumulative Update
- [ ] Monitor the mail server itself for patch state and anti-malware health, not only for uptime
