Modern DNS Security on a small network can be divided into two areas of defense.
The first is DNSSEC (DNS Security Extensions) used to ensuring that resolved results can be trusted and the second is DNS Transport security, usually DNS over TLS for name resolution, to ensure your own privacy when using the internet. DNS over TLS also mitigates against results being modified in transit. For Business’s and Website owners setting up DNSSEC is becoming imperative to ensure clients only receive your signed DNS records (Assuming they have DNSSEC configured on their resolver).
DNSSEC is a trust chain of signatures and digests going from the queried domain all the way up to the global top-level name servers.
DNS Can be enabled on the “DNS Resolver” on pfsense (which is unbound under the hood)(note not the “DNS Forwarder” service).
PiHole supports it too.
When either of these resolvers resolve a DNS query into a result they will check record signatures the whole way up the chain for each result. And will cache known DNSKEYS to improve resolution time. Results from a domain that does not have DNSSEC enabled are still returned, they are just considered insecure/unsigned. Results from a domain with DNSSEC Enabled, even for records that don’t exist, are verified by the resolver and if it passes the results are returned to the client and can be considered secure. Clients can also query the signing results and verify them individually. cli programs like ‘delv’ do this automatically, can also be run with dig. On the other end of the scale results from a domain that has DNSSEC enabled but the signatures cannot be verified are considered bogus and are dropped. The client who sent the request will receive a nxdomain result back as if the query has not record.
Ensure that if you have an internet domains, with local host overrides configured have the bypass mode enabled in your resolver or the resolver will not trust the host overrides.
DNS over TLS
Similar to the way HTTPS is replacing HTTP. DNS over TLS is replacing vanilla DNS. Both services return the same results. One is just encrypted in transit, protects your privacy and ensures youre connecting to the actual DNS service you intended to and are not being subject to a MitM attack. Upstream DNS Servers use internet standard TLS certificates to authenticate themselves and for key handover when the connection is being established. DNS over TLS uses TCP port 853.
Again it can be enabled in the resolver on pfsense and in PiHole.
To ensure no “DNS Leaks” (Where devices might talk direct to a public resolver, ahem….google devices including nest and chromecasts.). Blocking outbound DNS queries (53 and 853) for all devices in a LAN except your DNS resolver can be warranted. Certain devices still wont use the DNS server provided to them in their DHCP lease (Again nest/chromecasts). For these case you may require to setup a dns-redirection on your NAT gateway back to your resolver. A step-by-step for this is available as a ‘recipe’ from the pfsense group. https://docs.netgate.com/pfsense/en/latest/recipes/dns-redirect.html
EDIT: Testing your setup
Cloudflare has a Test Suite. The Secure DNS and DNSSEC tests within the link bellow will tell you if DNS is being resolved over a secure method, such as DNS over TLS and DNSSEC will ensure that you’re resolver is confirming DNSSEC entries where they exist. The later two, TLS 1.3 and Secure SNI are both system/browser level items. Link: https://www.cloudflare.com/ssl/encrypted-sni/
For cli type testing dig has some +DNSSEC and +sigchase switches that may suit what you need.
But the updated version of dig from the ISC group is ‘delv’. See https://kb.isc.org/docs/aa-01152 for info. Its a lot more DNSSEC aware and can help you test/validate bringing in DNSSEC to your owned domain.
(google.com check, no DNSSEC configured by Google) ~# delv google.com A ; unsigned answer google.com. 159 IN A 184.108.40.206 (basic test of this sites URL) ~# delv blog.mqbx.nl A ; fully validated blog.mqbx.nl. 27 IN A 220.127.116.11 blog.mqbx.nl. 27 IN RRSIG A 13 3 300 20220908053210 20220908032710 8974 mqbx.nl. QyXXbSyIn9E1BJanjpzBoWzdkODttWko+tp/B3nJEbkVxLE5pvaAh+y2 4FBLFEVLwh13Ps25FxG/Vz6dlnQWfA== (detailed +vtrace check of same, note how it describes the entire validation process) ~# delv +vtrace blog.mqbx.nl A ;; fetch: blog.mqbx.nl/A ;; validating blog.mqbx.nl/A: starting ;; validating blog.mqbx.nl/A: attempting positive response validation ;; fetch: mqbx.nl/DNSKEY ;; validating mqbx.nl/DNSKEY: starting ;; validating mqbx.nl/DNSKEY: attempting positive response validation ;; fetch: mqbx.nl/DS ;; validating mqbx.nl/DS: starting ;; validating mqbx.nl/DS: attempting positive response validation ;; fetch: nl/DNSKEY ;; validating nl/DNSKEY: starting ;; validating nl/DNSKEY: attempting positive response validation ;; fetch: nl/DS ;; validating nl/DS: starting ;; validating nl/DS: attempting positive response validation ;; fetch: ./DNSKEY ;; validating ./DNSKEY: starting ;; validating ./DNSKEY: attempting positive response validation ;; validating ./DNSKEY: verify rdataset (keyid=20326): success ;; validating ./DNSKEY: marking as secure (DS) ;; validating nl/DS: in fetch_callback_dnskey ;; validating nl/DS: keyset with trust secure ;; validating nl/DS: resuming validate ;; validating nl/DS: verify rdataset (keyid=20826): success ;; validating nl/DS: marking as secure, noqname proof not needed ;; validating nl/DNSKEY: in fetch_callback_ds ;; validating nl/DNSKEY: dsset with trust secure ;; validating nl/DNSKEY: verify rdataset (keyid=34112): success ;; validating nl/DNSKEY: marking as secure (DS) ;; validating mqbx.nl/DS: in fetch_callback_dnskey ;; validating mqbx.nl/DS: keyset with trust secure ;; validating mqbx.nl/DS: resuming validate ;; validating mqbx.nl/DS: verify rdataset (keyid=53551): success ;; validating mqbx.nl/DS: marking as secure, noqname proof not needed ;; validating mqbx.nl/DNSKEY: in fetch_callback_ds ;; validating mqbx.nl/DNSKEY: dsset with trust secure ;; validating mqbx.nl/DNSKEY: verify rdataset (keyid=9732): success ;; validating mqbx.nl/DNSKEY: marking as secure (DS) ;; validating blog.mqbx.nl/A: in fetch_callback_dnskey ;; validating blog.mqbx.nl/A: keyset with trust secure ;; validating blog.mqbx.nl/A: resuming validate ;; validating blog.mqbx.nl/A: verify rdataset (keyid=8974): success ;; validating blog.mqbx.nl/A: marking as secure, noqname proof not needed ; fully validated blog.mqbx.nl. 198 IN A 18.104.22.168 blog.mqbx.nl. 198 IN RRSIG A 13 3 300 20220908054015 20220908033515 8974 mqbx.nl. VqEIUZTFi+J43B5kqPkuSAhC1q69idvlgNMZ52pwqAaaCUnco5LXZZCH 0VCUtmiLQNymWuqd8hfX5+moip8f2Q==
Verisign Labs DNSSEC Analyzer is also very helpful. https://dnssec-analyzer.verisignlabs.com/
https://22.214.171.124/help also gives some useful information.