Skip to main content

Command Palette

Search for a command to run...

Implementing Strict Content Security Policy ( CSP ) in Vue.js & Django with Nginx

Increase the security of your Vue.js app with CSP

Updated
4 min read
Implementing Strict Content Security Policy ( CSP ) in Vue.js & Django with Nginx
S

Hi, I’m a self-taught backend developer with 3+ years of experience, currently working at a tech startup based in The Bahamas. I mostly work with Python and Django, building APIs, designing database models, and improving performance when needed. I enjoy learning new tools and technologies as projects require.

Introduction

Content Security Policy (CSP) is a security standard that helps prevent cross-site scripting (XSS), clickjacking, and other code-injection attacks by whitelisting trusted sources of content. When correctly configured, CSP ensures that only approved scripts, styles, images, and connections can be loaded by the browser.

Why CSP Matters

Without a strict CSP, an attacker could inject malicious scripts into your application, steal user credentials, or redirect users to phishing pages:

How CSP Works

When the browser receives HTML along with a CSP header, it enforces each directive on every resource request:

Browser Enforcement Flow

This diagram shows how the browser enforces CSP on resources like scripts, styles, images, and XHR/fetch requests:

Configuring CSP in Nginx for Vue.js

In your Nginx server block for the Vue.js static build, add a CSP header:

server {
    listen 80;
    server_name yourdomain.com;

    root /var/www/vue-dist;
    index index.html;

    add_header Content-Security-Policy "
      default-src 'self';
      script-src 'self' https://cdn.jsdelivr.net;
      style-src 'self' 'unsafe-inline';
      img-src 'self' data:;
      font-src 'self' https://fonts.gstatic.com;
      connect-src 'self' https://api.yourdomain.com;
    " always;

    location / {
        try_files $uri $uri/ /index.html;
    }
}
  • default-src: Fallback for all resource types.
  • script-src: Whitelist your own bundle and trusted CDNs.
  • style-src: Allow inline styles for runtime libraries like Floating-UI.
  • img-src: Permit data URIs for base64 images.
  • font-src: Load web fonts from trusted providers.
  • connect-src: Ensure the SPA can communicate with the Django API.

Configuring CSP in Django

Use the django-csp middleware or a custom header:

Using django-csp

# settings.py
MIDDLEWARE = [
    # ...
    'csp.middleware.CSPMiddleware',
]

CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC  = ("'self'", "https://cdn.jsdelivr.net")
CSP_STYLE_SRC   = ("'self'", "'unsafe-inline'")
CSP_IMG_SRC     = ("'self'", "data:")
CSP_CONNECT_SRC = ("'self'", "https://api.yourdomain.com")

Custom Middleware

# middleware.py
from django.utils.deprecation import MiddlewareMixin

class ContentSecurityPolicyMiddleware(MiddlewareMixin):
    def process_response(self, request, response):
        policy = (
            "default-src 'self'; "
            "script-src 'self' https://cdn.jsdelivr.net; "
            "style-src 'self' 'unsafe-inline'; "
            "img-src 'self' data:; "
            "connect-src 'self' https://api.yourdomain.com;"
        )
        response['Content-Security-Policy'] = policy
        return response

Note: If your Django project only serves API endpoints (no HTML responses or templates), you typically don't need to configure CSP on the Django side. Simply enforce CSP at your Nginx or frontend layer.

Inline Script Handling

When an attacker tries to inject inline <script> tags via URL parameters or form inputs, CSP will block execution:

Testing & Troubleshooting

  1. Check the browser console for “Refused to load” errors.
  2. Whitelisting: Add missing domains in the right directive (e.g., connect-src vs. script-src).
  3. Certificate permissions: Ensure Nginx can read SSL cert files if using HTTPS.
  4. Disable Rocket Loader (Cloudflare) if you must avoid 'unsafe-inline' for scripts.

Conclusion

Implementing a strict Content Security Policy via Nginx and Django dramatically reduces the risk of XSS and resource injection attacks. By carefully whitelisting only trusted sources and monitoring violations, you harden both your Vue.js frontend and Django backend against a wide range of threats.