Now that we have a firewall enabled, we need to focus on better securing our network.
Despite our best intentions, developers make mistakes. We write bugs, leave diagnostic code in a file during a commit, or mistakenly hard-code credentials in a file meant to access an external API. Many of these issues can be discovered and patched during a code review, but they can still crop up. Especially when a team is in a hurry to push a release.
Yesterday’s examples used
ufw to block incoming traffic from a potential attacker. There’s also a chance that your application itself might be the party responsible for a breach. A malicious piece of code might attempt to exfiltrate data to a foreign server. Or an engineer might accidentally upload test content on a staging server that triggers a production API integration.
It’s a good idea to lock down not just what systems can talk to your server; it’s also a good idea to lock down what systems your server can talk to.
Rather than allowing all outgoing connections as we did above, we can lock things down by first blocking all outgoing traffic:
sudo ufw default deny outgoing
You can then whitelist specific outgoing ports to any destination. For example, the following rule allows outgoing DNS queries against any host:
sudo ufw allow out 53
Assume, for example, your server also needs to leverage an API hosted at
api.displace.tech. You know that this API lives at the IP address
220.127.116.11, so you’ll whitelist that IP for only TLS encrypted traffic:
sudo ufw allow out to 18.104.22.168 port 443
By allowing DNS queries, your application can dynamically resolve
22.214.171.124. By unblocking outgoing HTTPS calls to that host, your application can reach out to the server and interact with it remotely. However, the application cannot send requests to
http://api.displace.tech (note the missing
s). Network communication over HTTP uses port 80 rather than 443.
The application similarly cannot send requests to
https://api.maliciousdomain.com (regardless of the TLS specification). The server will be able to resolve the domain, but as the IP address it resolves to is missing from the allow list the server won’t be able to talk to it.