The Actually Useful Security Checklist

A security checklist you can actually use

πŸ“– Checklists

This checklist is a personal reference tool for me, as well as a useful tool if you got a penetration test report saying vague stuff like β€œsecure configuration” and β€œhardening” and you want to actually find out what to type into your keyboard.


πŸ—„οΈ Servers


Expand...

πŸ—„οΈ Database Services


πŸ—„οΈ MariaDB

Expand...

Common Port(s): 3306


πŸ—„οΈ MySQL

Expand...

Common Port(s): 3306

The best way to quickly harden a MySQL installation is to run the built-in mysql_secure_installation script and follow all the instructions it gives you, but manual hardening steps are provided below.

πŸ“Œ Disable Remote Root Login

Expand...
🐧 Debian/Ubuntu:
sudo mysql -e "DELETE FROM mysql.user WHERE User='root' AND Host!='localhost'; FLUSH PRIVILEGES;"

πŸ“Œ Remove Anonymous Accounts

Expand...
🐧 Debian/Ubuntu:
mysql -u root -p

SELECT User, Host FROM mysql.user WHERE User = '';

DELETE FROM mysql.user WHERE User = '';

FLUSH PRIVILEGES;

exit;

πŸ“Œ Set Strong Root Password

Expand...
🐧 Debian/Ubuntu:
sudo mysql

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{password}';
FLUSH PRIVILEGES;

exit;

πŸ”’ Secure Shell (SSH) Services


πŸ”’ OpenSSH Server

Expand...

Package Name(s): openssh-server (apt)
Common Port(s): 22 (SSH)

Unless otherwise stated, most of the configuration changes below will require you to reload or restart the service to fully apply them.

πŸ“Œ Disable Insecure Ciphers

Expand...
🐧 Debian/Ubuntu:
(editor) /etc/ssh/sshd_config

MACs hmac-sha2-256,hmac-sha2-512,umac-64-etm@openssh.com,umac-128-etm@openssh.com
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,chacha20-poly1305@openssh.com

πŸ“Œ Disable Root Login

Expand...
🐧 Debian/Ubuntu:
(editor) /etc/ssh/sshd_config

PermitRootLogin no

πŸ“Œ Enforce Strong Passwords

Expand...

You can enforce strong SSH passwords using PAM.

🐧 Debian/Ubuntu:

Install the PAM package:

apt install libpam-pwquality

Then enable PAM in the SSH configuration file:

(editor) /etc/ssh/sshd_config

UsePAM yes
PasswordAuthentication yes

Then set your password requirements in the PAM configuration file:

(editor) /etc/pam.d/common-password

password requisite pam_pwquality.so retry=3 minlen={minimum length} ucredit=-{number of uppercase letters} lcredit=-{number of lowercase letters} dcredit=-{number of digits} ocredit=-{number of special characters}

Make sure the settings also match in this configuration file:

(editor) /etc/security/pwquality.conf

minlen = {minimum length}
ucredit = -{number of uppercase letters}
lcredit = -{number of lowercase letters}
dcredit = -{number of digits}
ocredit = -{number of special characters}

You can also block common passwords like this:

(editor) /etc/pam.d/common-password

password requisite ... dictcheck=1 (add to the end of the existing line)
(editor) /etc/security/pwquality.conf

dictcheck = 1
dictpath = /usr/share/dict/cracklib-small (or a custom wordlist you made)

Some recommended β€œbad passwords” to block if you make a custom wordlist are:

1234
123456
admin
letmein
password
qwerty

βœ… Verification: Change a user’s password with passwd (sudo passwd {user}) and verify that you can’t set a password that does not conform to the configured requirements.

πŸ“Œ Whitelist Access

Expand...

The OpenSSH service should only be accessible to a limited range of IP addresses, ideally off a whitelist that is enforced by the local firewall and/or by the OpenSSH service configuration file. You can use the AllowUsers and AllowGroups directives to make access as granular as possible.

🐧 Debian/Ubuntu:
(editor) /etc/ssh/sshd_config

Match Address {ip,ip,ip...}
    AllowUsers {user} {user} {user}...

🌎 Web (HTTP/HTTPS) Services


🌎 Apache HTTP

Expand...

Package Name(s): apache2 (apt), httpd (yum)
Common Port(s): 80 (HTTP), 443 (HTTPS), 8080 (Alternate HTTP), 8443 (Alternate HTTPS)

Unless otherwise stated, most of the Apache configuration changes below will require you to reload or restart Apache to fully apply them, i.e.:

service apache2 restart

systemctl restart apache2

File locations may also vary depending on how you set up your web server. You may also need to install or enable certain modules (mod_headers, mod_rewrite, mod_status) using a2enmod where needed.

πŸ“Œ Disable SSLv2/SSLv3/TLSv1/TLSv1.1

Expand...
🐧 Debian/Ubuntu:
(editor) /etc/apache2/sites-enabled/(ssl config files)

SSLProtocol all -SSLv3 -SSLv2 -TLSv1 -TLSv1.1

πŸ“Œ Disable TRACE

Expand...
🐧 Debian/Ubuntu:
(editor) /etc/apache2/conf-enabled/security.conf

TraceEnable Off

βœ… Verification: Use nmap with the http-methods script to scan open HTTP/HTTPS ports (usually 80/443) and verify that the TRACE method doesn’t appear in the list of supported methods.

πŸ“Œ Enable Custom Error Page

Expand...

The default Apache error page exposes version information and shows exactly what version and build of Apache you have on your server. To conceal this information, you should create a custom error page and set it as the default error page for 403 Forbidden, 404 Not Found, etc. in the Apache configuration file.

🐧 Debian/Ubuntu:
(editor) /etc/apache2/sites-enabled/(config files)

ErrorDocument 403 {file}
ErrorDocument 404 {file}

βœ… Verification: Browse to a nonexistent directory and verify that you get the custom error page.

πŸ“Œ Hide Server Information

Expand...
🐧 Debian/Ubuntu:
(editor) /etc/apache2/conf-enabled/security.conf

ServerSignature Off
ServerTokens Prod

βœ… Verification: Use nmap with the service detection flag (-sV) to scan open HTTP/HTTPS ports (usually 80/443) and verify that the banner grab shows β€œApache” instead of β€œApache x.x.x”.

πŸ“Œ Remove Unnecessary Files/Directories

Expand...

Remove or conceal the following dotfile (hidden by default on Linux unless listed with ls -la) directories and files from /var/www/html (or whichever file location is tied to your web server setup):

  • .cache
  • .config
  • .env (can leak hardcoded secrets)
  • .eslintrc
  • .git (can leak hardcoded secrets)
    • /config (can leak hardcoded secrets)
  • .gitattributes
  • .github
  • .gitignore
  • .gitinfo
  • .gitmodules
  • .gnupg (contains PGP information)
  • .jshintrc
  • .nvmrc
  • .travis.yml
  • .viminfo

Remove or conceal the following other directories and files:

  • composer.json
  • composer.lock
  • docker-compose.yml (exposes Docker configuration information and services)
  • Gruntfile.js
  • npm-shrinkwrap.json (exposes dependencies and version information)
  • package.json (exposes dependencies and version information)
  • phpinfo (exposes PHP version information)
  • phpinfo.php (exposes PHP version information)

If desired, you can entirely block specific sensitive file types from being browsed in /etc/apache2/conf-enabled/security.conf (or wherever your Apache configuration files are):

RedirectMatch 404 /\.git
RedirectMatch 404 /\.svn

βœ… Verification: Browse to these directories and files in any web browser and verify that you receive either a 403 Forbidden or a 404 Not Found response. You can also use curl.

πŸ“Œ mod_headers: Enforce HTTP Strict Transport Security (HSTS) Header

Expand...

The maximum age value can vary depending on your preferences, but the default value of 31536000 I usually use has never caused any issues.

🐧 Debian/Ubuntu:
(editor) /etc/apache2/sites-enabled/(config files)

Header always set Strict-Transport-Security max-age=31536000

βœ… Verification: Browse to the site and verify that you receive a Strict-Transport-Security header in the HTTP response, and that it has the configured age value. You can see it using your web browser’s Developer Tools (Network -> Headers), or through nmap and other header grabber tools.

πŸ“Œ mod_rewrite: Enforce HTTP To HTTPS Rewrite

Expand...
🐧 Debian/Ubuntu:
(editor) /etc/apache2/sites-enabled/(config files)

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

πŸ“Œ mod_status: Restrict Access To Server Status Page

Expand...
🐧 Debian/Ubuntu:
(editor) /etc/apache2/mods-enabled/status.conf

<Location /server-status>
    SetHandler server-status
    Require local
    Require ip {ip ip ip...}
</Location>

🌎 Apache Tomcat

Expand...

Common Port(s): 80 (HTTP), 443 (HTTPS), 8080 (Alternate HTTP), 8443 (Alternate HTTPS)

Unless otherwise stated, you will usually have to run the Tomcat shutdown and startup scripts (or restart the service if it’s configured as one) to fully apply these changes.

$CATALINA_HOME on most installations is something like /home/tomcat/ or /opt/tomcat/ (Debian/Ubuntu). If you need to manually tell the server where it is, you can do it like this:

export CATALINA_HOME={directory}

πŸ“Œ Restrict Access To Manager Application

Expand...

The context.xml file controls access to the Manager Application that comes bundled with Tomcat. You will usually want to restrict this to only localhost access (127.0.0.1).

🐧 Debian/Ubuntu:
(editor) $CATALINA_HOME/webapps/manager/META-INF/context.xml

<Context antiResourceLocking="false" privileged="true">
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
           allow="127\.\d+\.\d+\.\d+|::1" />
</Context>

If you want to also allow a specific IP address, i.e. [1].[2].[3].[4], format it like [1]\.[2]\.[3]\.[4] and add it to the allow statement with an β€œor” operator (|).

You can also configure a login requirement and a specific user that is authorized to view the page after entering a password:

(editor) $CATALINA_HOME/conf/tomcat-users.xml

<tomcat-users>
  <user username="admin" password="{password}" roles="manager-gui"/>
</tomcat-users>

βœ… Verification: Browse to /manager/html on your site and verify that you get a 403 Access Denied error page if you are not on the whitelist.


🌎 PHP

Expand...

Common Port(s): 80 (HTTP), 443 (HTTPS), 8080 (Alternate HTTP), 8443 (Alternate HTTPS)


🧩 Software


Expand...

πŸ–₯️ Workstations


Expand...

πŸͺŸ Windows


🐧 Linux