| name | apply-secure-defaults |
| description | Use when configuring a new application, framework, or service — ensuring security is enabled out of the box by setting restrictive defaults for cookies, headers, database connections, and framework security features. |
| source | OWASP Top 10 Proactive Controls C05 C09 (owasp.org/www-project-top-ten/); OWASP Application Security Verification Standard 14.1; CIS Software Supply Chain Security Guide; Django/Rails security configuration documentation |
| tags | ["security","owasp","secure-defaults","configuration","hardening","framework-security","developer"] |
Apply Secure Defaults
Configure frameworks and infrastructure with security enabled by default — HttpOnly/Secure/SameSite cookies, HTTPS enforcement, debug disabled, strong cipher suites, and framework security middleware — preventing entire vulnerability classes through configuration rather than per-feature implementation.
Why This Is Best Practice
Adopted by: OWASP Top 10 Proactive Controls C05 (Secure By Default Configurations) and C09 (Leverage Security Frameworks and Libraries). Django, Rails, Spring Security, and ASP.NET Core all ship with security defaults that must be explicitly disabled — enabling them is zero-effort compared to implementing the equivalent from scratch. OWASP ASVS 14.1 (Build and Deploy) defines the configuration security requirements. Google's BeyondProd and Netflix's "Paved Road" security model both use security-by-default infrastructure as the primary mechanism for consistent security posture across thousands of services.
Impact: The 2021 Log4Shell vulnerability (CVSS 10.0, estimated $6.2B remediation cost) was exploited partly because Java application servers had JNDI lookups enabled by default — disabled by default would have prevented exploitation on most targets without a single line of code change. Django's default DEBUG = False in production prevents stack traces from being served to users; teams that deploy with DEBUG = True expose full database queries, environment variables, and code to anyone who triggers an error. A CIS Benchmark analysis (2022) found that 65% of remediated cloud misconfigurations were default settings that were never reviewed.
Why best: Per-feature security implementation (add CSRF protection here, add XSS escaping there) creates gaps — developers forget or don't know every security requirement. Secure defaults mean a developer who knows nothing about security still gets CSRF protection, secure cookies, and HTTPS enforcement automatically. The alternative (security off by default, enabled per-feature) results in security that's only as good as the developer's security knowledge.
Sources: OWASP Proactive Controls C05, C09; OWASP ASVS 14.1; Django security documentation; Rails security guide; Netflix Paved Road security model
Steps
-
Django: verify all security middleware and settings are enabled:
DEBUG = False
ALLOWED_HOSTS = ["app.company.com"]
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
SESSION_COOKIE_AGE = 1800
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = "Lax"
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
]
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = "DENY"
SECURE_REFERRER_POLICY = "strict-origin-when-cross-origin"
-
Express.js/Node.js: apply Helmet and secure defaults:
import express ;
helmet ;
session ;
app = ();
app.(({
: {
: {
: [],
: [],
: [],
: [],
},
},
: { : , : , : },
}));
app.(({
: process..,
: ,
: ,
: ,
: {
: ,
: ,
: ,
: * * ,
},
}));
app.();
app.( {
.(err);
res.().({ : });
});
Rules
- Run
python manage.py check --deploy (Django) or equivalent framework security check before every production deployment — frameworks detect their own misconfigurations.
- Security middleware must run before application code — placing
SecurityMiddleware after custom middleware means requests bypass security headers.
DEBUG = True in production is a critical misconfiguration — Django, Rails, and Flask all expose credentials and internal state in debug mode.
- Default deny for HTTP methods — explicitly allow GET/POST/PUT/DELETE and reject everything else (HEAD, TRACE, CONNECT, OPTIONS unless needed).
Common Mistakes
- Disabling CSRF protection for "convenience" — CSRF protection is disabled per-view as a shortcut in many tutorials; each disabled view is a vulnerability.
SameSite=None cookies without Secure — SameSite=None requires Secure per the spec; without it, the cookie is rejected by modern browsers and the CSRF protection is lost.
- Framework security docs read once, not maintained — security configurations accumulate technical debt; review against current framework documentation at least annually.
- Permissive CSP as a "starting point" —
Content-Security-Policy: default-src * is worse than no CSP because it gives false assurance; start strict and loosen only as needed.