Man In The Middle on Digitalocean
How Man In The Middle Manifests in Digitalocean
DigitalOcean offers a variety of services — Droplets, Kubernetes (DOKS), App Platform, Managed Databases, Spaces, and Load Balancers — each of which can expose an unauthenticated network path if TLS is not properly enforced. A classic MITM scenario occurs when an attacker positions themselves between a client and a DigitalOcean‑hosted endpoint and can read, modify, or inject traffic because the connection is either unencrypted or uses a certificate that the client does not validate.
- Unencrypted HTTP on Droplets or App Platform: If a developer deploys a web app and forgets to enable the built‑in HTTPS redirect (App Platform) or to terminate TLS at the Load Balancer, the service answers on port 80. An attacker on the same VPC network or on the public internet can perform ARP spoofing or DNS hijacking to capture credentials, session cookies, or API keys.
- Manipulated DNS for Managed Databases: DigitalOcean Managed Databases expose a private endpoint by default, but if a client is configured to use the public hostname without verifying the server’s certificate (e.g.,
sslmode=disablein libpq ortls=falsein the MySQL connector), an attacker who can spoof the DNS response can present a self‑signed certificate and decrypt the traffic. - Spaces API calls over plain HTTP: The S3‑compatible Spaces endpoint supports both HTTP and HTTPS. Using the HTTP endpoint (or setting
endpoint_urltohttp://nyc3.digitaloceanspaces.com) transmits access keys and request bodies in clear text, enabling a network‑level attacker to steal keys and forge requests. - Kubernetes Ingress without TLS: In DOKS, an Ingress resource that omits the
tlsblock or uses a self‑signed certificate will serve traffic over HTTP. An attacker can perform a man‑in‑the‑middle on the node’s external IP and inject malicious JavaScript or steal session tokens.
These patterns share a common root: the absence of verified transport security. DigitalOcean provides the mechanisms (managed TLS, automatic HTTPS redirects, private networking) but they must be explicitly enabled and validated by the developer.
Digitalocean-Specific Detection
Detecting a missing or misconfigured TLS layer can be done passively by observing whether an endpoint presents a valid certificate and enforces HTTPS. middleBrick performs unauthenticated, black‑box checks that map directly to these observations:
- It attempts a TCP connection on port 443 and validates the server’s certificate chain against the system trust store.
- If the service answers on port 80, middleBrick records the absence of TLS and checks for an HTTP‑to‑HTTPS redirect header (
Location: https://…). - For APIs, it sends a benign request (e.g.,
GET /health) and inspects the response for security headers such asStrict-Transport-SecurityandContent-Security-Policy. - When the target is a DigitalOcean App Platform URL, middleBrick also verifies that the certificate is issued by Let’s Encrypt (the default provider) and reports any mismatch or expiration.
Example: scanning a Droplet‑hosted Node.js API with the middleBrick CLI.
# Install the CLI (npm) if not already present
npm i -g middlebrick
# Scan the public IP of a Droplet (replace with your IP or domain)
middlebrick scan http://203.0.113.42/api/status
# Sample output (JSON)
{
"overall_score": 42,
"grade": "F",
"categories": {
"Encryption": {
"score": 20,
"findings": [
{
"severity": "high",
"description": "Service listening on port 80 with no HTTPS redirect",
"remediation": "Enable TLS termination at the Load Balancer or configure the app to redirect HTTP → HTTPS"
}
]
}
}
}
The finding shows that the API is reachable only over plain HTTP, which is a prerequisite for a MITM attack. By running the same scan against the HTTPS endpoint (https://203.0.113.42/api/status) you can confirm whether the issue is resolved.
Digitalocean-Specific Remediation
Remediation focuses on enforcing verified transport security using DigitalOcean’s native capabilities. Below are concrete, language‑agnostic steps and code snippets for common stacks.
1. Enforce HTTPS on App Platform
App Platform provides automatic HTTPS via a managed certificate. Ensure the http_port is not exposed and that the routes section includes a redirect.
# app.yaml (App Platform manifest)
services:
- name: web-api
image: yourrepo/web-api:latest
http_port: 8080 # internal port only
routes:
- path: /
# No explicit port; App Platform terminates TLS on 443
# Add a redirect rule via the UI or via `doctl apps update`
After deployment, verify with:
doctl apps get <app-id> --output json | jq '.spec.services[].routes[] | select(.path=="/")'
2. Force TLS in a Node.js Express Droplet
When you terminate TLS at the Droplet (e.g., using Nginx), you can still enforce HTTPS in the application to defend against mis‑configured front‑ends.
const express = require('express');
const app = express();
// Middleware that redirects HTTP → HTTPS
app.use((req, res, next) => {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(301, `https://${req.headers.host}${req.url}`);
}
next();
});
app.get('/api/status', (req, res) => {
res.json({ status: 'ok' });
});
app.listen(3000, () => console.log('Listening on :3000'));
Deploy the app behind a DigitalOcean Load Balancer that provides the TLS certificate and forwards the X-Forwarded-Proto header.
3. Secure Managed Database Connections
Always verify the server’s certificate. The following Python example uses psycopg2 with SSL enforcement.
import psycopg2
import os
conn = psycopg2.connect(
host=os.getenv('DO_DB_HOST'),
port=25060,
dbname=os.getenv('DO_DB_NAME'),
user=os.getenv('DO_DB_USER'),
password=os.getenv('DO_DB_PASS'),
sslmode='require' # forces verification of the server cert
)
cur = conn.cursor()
cur.execute('SELECT version();')
print(cur.fetchone())
cur.close()
conn.close()
If you use a connection pooler like PgBouncer, keep sslmode=require in the client string.
4. Use HTTPS for Spaces SDK Calls
The official AWS‑compatible SDK defaults to HTTPS; explicitly set the endpoint to avoid accidental HTTP usage.
const AWS = require('aws-sdk');
const spacesEndpoint = new AWS.Endpoint('nyc3.digitaloceanspaces.com');
const s3 = new AWS.S3({
endpoint: spacesEndpoint,
accessKeyId: process.env.DO_SPACES_KEY,
secretAccessKey: process.env.DO_SPACES_SECRET,
// The SDK uses HTTPS by default; do NOT override with http://
});
s3.upload({ Bucket: 'my-bucket', Key: 'test.txt', Body: 'hello' }, (err, data) => {
if (err) console.error(err);
else console.log('Uploaded', data.Location);
});
By ensuring that every network path uses a trusted TLS certificate and that clients validate it, you eliminate the low‑level channel an attacker would need for a MITM on DigitalOcean infrastructure.