---
title: "P19: Database, Mail and DNS Hardening"
canonical: https://openvapt.com/academy/p19.html
html: https://openvapt.com/academy/p19.html
site: OpenVAPT, https://openvapt.com/
license: OpenVAPT Source-Available Licence 1.3, https://openvapt.com/legal/licence-text.html
modified: 2026-10-16
version: 0.1.0-alpha.6
---

# P19: Database, Mail and DNS Hardening

Beyond binding and authentication: the option-file settings that limit what a compromised database credential can do, make mail and database traffic encrypted by rule, and keep DNS honest.

- Level: Practitioner
- Time: about 30 minutes
- Read first: P8

## You Will Be Able To

- Read MySQL, PostgreSQL and Redis option files and name the setting behind each finding.
- Explain why secure_file_priv, symbolic links and Redis administrative commands turn a database credential into a server compromise.
- Move PostgreSQL from md5 to SCRAM-SHA-256 without locking users out.
- Harden Postfix and Dovecot TLS, disable VRFY, and hide the BIND version while keeping DNSSEC validation on.

## When a Database Credential Becomes a Shell

A database server runs as its own user with read and write access to its data folder, and sometimes more. MySQL's LOAD DATA and SELECT ... INTO OUTFILE read and write files with that access; secure_file_priv confines them to one folder or, set to NULL, disables them. With symbolic links allowed, a table can point outside the data directory. Redis CONFIG SET can change the directory and file name it saves to. That is the classic route from an exposed Redis to a cron job or an SSH key. FLUSHALL wipes every key in one command. Renaming those commands, or better an ACL that denies @dangerous for application users, limits what a stolen credential can do.

These are configuration-file signals only. OpenVAPT never connects to the database, so it cannot see anonymous users or a leftover test database; check those with the vendor's own tools under administrator credentials.

## Passwords and Transport

PostgreSQL's md5 method stores a value that works as the password itself, so a copied catalog is a copied set of credentials. The password method sends the password in the clear unless the session is encrypted. SCRAM-SHA-256 fixes both and is the default since PostgreSQL 14. Migrating safely means setting password_encryption first, having every role reset its password so a SCRAM verifier exists, and only then changing the pg_hba.conf methods.

ssl = on in PostgreSQL and require_secure_transport = ON in MySQL make encryption a server rule rather than a client option. skip-name-resolve in MySQL stops grants depending on DNS answers that an attacker on the path can forge. log_error and log_connections turn silent events, including every successful login, into evidence.

## Mail: Offer TLS, Require TLS, Say Nothing Extra

Postfix smtpd_tls_security_level = may with a real certificate is what other mail servers expect; none means every message arrives in the clear. The default protocol list still admits TLS 1.0 and 1.1, so set smtpd_tls_protocols and smtpd_tls_mandatory_protocols to >=TLSv1.2. disable_vrfy_command = yes stops address enumeration. Dovecot ssl = required refuses any command before TLS, which completes the plaintext-authentication control: with ssl = yes a client may still keep the whole session unencrypted.

## DNS: Hide the Version, Validate the Answers

A CHAOS query for version.bind returns the exact BIND release unless options sets a version string. DNSSEC validation (dnssec-validation auto) lets a recursive resolver reject forged answers for signed zones. BIND 9.16 and newer enable it by default. An explicit no is a deliberate weakening and the one state OpenVAPT flags.

## In Summary

Databases, mail and DNS fail the same way: they listen too widely, trust too much and say too much. Bind to what you need, and require strong password verifiers and TLS on the wire. Rename or restrict dangerous commands, and offer and require TLS for mail. Hide the DNS version and validate answers with DNSSEC.

## Apply It

- [NET-DB-014 MySQL Symbolic Links Allowed for Tables](https://openvapt.com/checks/NET-DB-014.md) (medium)
- [NET-DB-015 MySQL secure_file_priv Not Restricted](https://openvapt.com/checks/NET-DB-015.md) (medium)
- [NET-DB-016 MySQL Does Not Require Encrypted Client Connections](https://openvapt.com/checks/NET-DB-016.md) (medium)
- [NET-DB-017 MySQL Error Log Not Configured](https://openvapt.com/checks/NET-DB-017.md) (low)
- [NET-DB-018 MySQL Resolves Client Host Names](https://openvapt.com/checks/NET-DB-018.md) (low)
- [NET-DB-019 PostgreSQL Uses md5 or password Authentication](https://openvapt.com/checks/NET-DB-019.md) (medium)
- [NET-DB-020 PostgreSQL SSL Not Enabled](https://openvapt.com/checks/NET-DB-020.md) (medium)
- [NET-DB-021 PostgreSQL Connection Logging Off](https://openvapt.com/checks/NET-DB-021.md) (low)
- [NET-DB-022 PostgreSQL Password Encryption Not SCRAM](https://openvapt.com/checks/NET-DB-022.md) (medium)
- [NET-DB-023 Redis Dangerous Commands Not Restricted](https://openvapt.com/checks/NET-DB-023.md) (medium)
- [NET-DNS-001 BIND Version String Disclosed](https://openvapt.com/checks/NET-DNS-001.md) (low)
- [NET-DNS-002 BIND DNSSEC Validation Disabled](https://openvapt.com/checks/NET-DNS-002.md) (medium)
- [NET-MAIL-001 Postfix SMTP TLS Not Offered or Has No Certificate](https://openvapt.com/checks/NET-MAIL-001.md) (medium)
- [NET-MAIL-002 Postfix Allows TLS 1.0 or 1.1](https://openvapt.com/checks/NET-MAIL-002.md) (medium)
- [NET-MAIL-003 Postfix VRFY Command Enabled](https://openvapt.com/checks/NET-MAIL-003.md) (low)
- [NET-MAIL-004 Dovecot Does Not Require TLS](https://openvapt.com/checks/NET-MAIL-004.md) (medium)

## Lab

1. `Run: openvapt demo --only NET-DB-,NET-MAIL-,NET-DNS- --out p16 and group the findings into three buckets: limits what a credential can do, makes transport encrypted, produces evidence.`
2. `Read /etc/mysql/conf.d/hardening.cnf, the PostgreSQL files and redis.conf in the hardened lab (internal/lab/fixtures_servers_db_mail.go) and write one sentence per line on what it prevents.`
3. `Write the ordered steps to move a PostgreSQL 13 cluster from md5 to scram-sha-256 without locking out the application, and say what breaks if the order is wrong.`
4. `On a test resolver: dig @127.0.0.1 version.bind txt chaos +short  and  dig @127.0.0.1 dnssec-failed.org a ; explain what each answer shows.`

## Check Yourself

Answer keys are public for every channel (see Teaching With OpenVAPT).

1. What does secure_file_priv = NULL do?
   - A. Disables password checks
   - B. Disables file import and export statements entirely
   - C. Deletes the data directory
   - D. Allows file import and export from any folder
   - Answer: B. NULL turns off LOAD DATA and INTO OUTFILE file access.

2. Why is a PostgreSQL md5 verifier worse than it sounds?
   - A. It is slow
   - B. The stored value itself authenticates, so a leaked catalog is a leaked password set
   - C. It only works over IPv4
   - D. It cannot be used over TLS
   - Answer: B. md5 verifiers are usable directly; SCRAM verifiers are not.

3. What is the correct order when moving to SCRAM-SHA-256?
   - A. Change pg_hba.conf first, then passwords
   - B. Set password_encryption, reset every password, then change pg_hba.conf
   - C. Reinstall PostgreSQL
   - D. Change passwords only; pg_hba.conf does not matter
   - Answer: B. Roles must have a SCRAM verifier before pg_hba.conf demands one.

4. Dovecot has ssl = yes. Can a client read mail without TLS?
   - A. No, yes means mandatory
   - B. Yes, TLS is offered but not required; ssl = required refuses plaintext sessions
   - C. Only on port 993
   - D. Only if the client uses IPv6
   - Answer: B. yes is opportunistic; required is the enforcing value.

5. Why is Redis CONFIG SET dangerous on an exposed Redis?
   - A. It can change where Redis saves its data, a classic route to a cron job or SSH key
   - B. It only changes the memory limit
   - C. It restarts Redis
   - D. It encrypts every key
   - Answer: A. Pointing the save directory at a cron folder or authorized_keys turns a database write into code execution or a login. Rename or restrict the command.

## Key Terms

- SCRAM-SHA-256: A password authentication method that stores a salted, iterated verifier and proves knowledge of the password without sending it; the PostgreSQL default since version 14.
- DNSSEC: Digital signatures on DNS records that let a resolver verify answers came from the zone owner and were not altered in transit.
- STARTTLS: An extension by which a plaintext mail session upgrades to TLS; opportunistic unless the server requires it.
- Least Privilege: Giving every account and process only the access it needs, nothing more.
- Open Relay: A mail server that forwards mail from anyone to anyone, which spammers abuse.
- Hardening: Reducing a system's attack surface and weaknesses through configuration.

## References

- [MySQL 8.4 Reference Manual, Security Guidelines](https://dev.mysql.com/doc/refman/8.4/en/security-guidelines.html)
- [PostgreSQL, Password Authentication](https://www.postgresql.org/docs/current/auth-password.html)
- [Redis Security](https://redis.io/docs/latest/operate/oss_and_stack/management/security/)
- [Postfix TLS Support](https://www.postfix.org/TLS_README.html)
- [Dovecot SSL/TLS Configuration](https://doc.dovecot.org/main/core/config/ssl.html)
- [NIST SP 800-81 Rev. 2, Secure Domain Name System Deployment Guide](https://csrc.nist.gov/pubs/sp/800/81/r2/final)
- [NIST SP 800-177 Rev. 1, Trustworthy Email](https://csrc.nist.gov/pubs/sp/800/177/r1/final)

Offline: `openvapt learn P19`.

---

OpenVAPT is academic, non-commercial, source-available and built by AI Cybersecurity Engineers (AI systems, not people). Free for your own use on machines you own or control, 100% at your own risk; not for sale and not for providing services. This page in HTML: https://openvapt.com/academy/p19.html. Part of OpenVAPT Academy. How to cite: https://openvapt.com/cite.html. Site summary for models: https://openvapt.com/llms.txt.
