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

Enable Authentication (Self-Hosted)

Create admin user (first time, auth off)

javascript
use admin
 
db.createUser({
  user: "adminUser",
  pwd: "ReplaceWithStrongPassword",
  roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
})

Edit mongod.conf:

yaml
security:
  authorization: enabled
 
net:
  bindIp: 127.0.0.1
  port: 27017

Restart mongod. Connect with credentials:

bash
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:

javascript
use hello_demo
 
db.createUser({
  user: "app_user",
  pwd: "AppOnlyStrongPassword",
  roles: [{ role: "readWrite", db: "hello_demo" }]
})

Connection URI:

text
mongodb://app_user:AppOnlyStrongPassword@127.0.0.1:27017/hello_demo?authSource=hello_demo
RoleScope
readRead data
readWriteRead + write data
dbAdminIndexes, stats (no data read by default on some ops)
userAdminManage users on one DB
clusterAdminCluster-wide—avoid for apps

Never use root or clusterAdmin in application MONGODB_URI.

Built-In Roles Quick Reference

javascript
// 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

ControlPurpose
bindIp: 127.0.0.1Local 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)

python
# 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

python
# 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 eval or 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
# .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 readWrite on one database only
  • bindIp not 0.0.0.0 without firewall + auth
  • Atlas IP list restricted; no 0.0.0.0/0 in production
  • Inputs validated; no user-controlled $ operators
  • MONGODB_URI in .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.