MongoDB Security
Introduction
A MongoDB instance on 0.0.0.0 without authentication is an open database—bots scan for it constantly. This chapter enables SCRAM authentication, assigns least-privilege roles, hardens network binding, prevents NoSQL injection in application code, and aligns with Atlas security and Git secrets hygiene.
Prerequisites
- Installation and mongosh
- MongoDB Atlas — cloud defaults
- Basic Linux service concepts — Linux track
Enable Authentication (Self-Hosted)
Create admin user (first time, auth off)
use admin
db.createUser({
user: "adminUser",
pwd: "ReplaceWithStrongPassword",
roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
})Edit mongod.conf:
security:
authorization: enabled
net:
bindIp: 127.0.0.1
port: 27017Restart mongod. Connect with credentials:
mongosh "mongodb://adminUser:ReplaceWithStrongPassword@127.0.0.1:27017/admin"Warning
Never Expose Unauthenticated MongoDB
Historical breaches involved bindIp: 0.0.0.0 with no auth. Atlas enforces auth + TLS by default.
Application User (Least Privilege)
Create a user only for your app database:
use hello_demo
db.createUser({
user: "app_user",
pwd: "AppOnlyStrongPassword",
roles: [{ role: "readWrite", db: "hello_demo" }]
})Connection URI:
mongodb://app_user:AppOnlyStrongPassword@127.0.0.1:27017/hello_demo?authSource=hello_demo| Role | Scope |
|---|---|
read | Read data |
readWrite | Read + write data |
dbAdmin | Indexes, stats (no data read by default on some ops) |
userAdmin | Manage users on one DB |
clusterAdmin | Cluster-wide—avoid for apps |
Never use root or clusterAdmin in application MONGODB_URI.
Built-In Roles Quick Reference
// Read-only analytics user
db.createUser({
user: "report_user",
pwd: "...",
roles: [{ role: "read", db: "hello_demo" }]
})Custom roles (advanced): combine actions on specific collections.
TLS / Encryption in Transit
Atlas: TLS on by default with mongodb+srv://.
Self-hosted: enable net.tls with certificate files—required for production over public networks. See MongoDB docs for tlsCertificateKeyFile.
Encryption at rest: disk encryption on cloud volumes or Atlas storage encryption.
Network Hardening
| Control | Purpose |
|---|---|
bindIp: 127.0.0.1 | Local apps only |
| Firewall (ufw/security group) | Block 27017 from internet |
| VPC / private link (Atlas) | No public IP |
| IP access list (Atlas) | Allow known IPs only |
App servers in same VPC connect privately; developers use VPN or bastion.
NoSQL Injection Prevention
Attackers trick apps into passing user input as query operators.
Vulnerable pattern (do not do this)
# DANGEROUS — user controls query shape
username = request.args.get("username")
user = db.users.find_one({"username": username})
# If username = {"$ne": ""} → returns first user (auth bypass attempt)Safe pattern
# Treat username as string only
username = request.args.get("username", "").strip()
if not username or len(username) > 80:
raise ValueError("Invalid username")
user = db.users.find_one({"username": username})Rules:
- Validate types in API layer (Pydantic, Marshmallow)
- Build filters with literal keys—never
evalor string-as-code - Use driver methods with typed parameters
- Reject keys starting with
$in user-supplied field names
Same mindset as SQL injection prevention — MySQL parameterized queries.
Secrets Management
# .env — gitignored
MONGODB_URI=mongodb://app_user:secret@127.0.0.1:27017/hello_demo- Rotate passwords after leaks
- Use secret managers in production (AWS Secrets Manager, Vault)
- Never log full connection strings
Field-Level Encryption (Awareness)
MongoDB supports Client-Side Field Level Encryption (CSFLE) for highly sensitive fields (SSN, card tokens). Keys stay outside database; queries on encrypted fields are limited. Enterprise/Atlas feature set—know it exists for compliance discussions.
Audit Logging (Awareness)
Atlas and Enterprise offer audit logs (who connected, what command). Open-source community edition: use application logs + mongod log verbosity for ops.
Security Checklist
- Authentication enabled on self-hosted
mongod - App uses
readWriteon one database only -
bindIpnot0.0.0.0without firewall + auth - Atlas IP list restricted; no
0.0.0.0/0in production - Inputs validated; no user-controlled
$operators -
MONGODB_URIin.env, not in Git
FAQ
authSource in URI?
Database where user credentials are stored—often admin for admin users, hello_demo for app users.
Disable auth for local Docker?
Acceptable on isolated laptop; still use auth before sharing network.
Compare Redis AUTH?
Redis requirepass protects one shared secret; MongoDB has per-user RBAC — Redis security.
LDAP / Kerberos?
Enterprise auth integrations—Atlas supports SAML/OIDC for UI; DB auth often SCRAM.
Penetration test findings?
Common: open port 27017, weak MONGO_INITDB_ROOT_PASSWORD, injection in legacy PHP apps.