How do you keep django-debug-toolbar and django-silk out of a Django production deployment, and what leaks if one slips through?
answer
- development settings module
- toolbar guards: DEBUG and IPs
- silk has no DEBUG check
- open /silk/ by default
- proxy address in INTERNAL_IPS
basics
~20 sInstall both only in a development settings module and dependency group. The toolbar's default guard needs DEBUG and INTERNAL_IPS, but silk has none: it records bodies and SQL and serves /silk/ to anyone unless its authentication settings are on.
solid answer
~40 sThe reliable approach is structural: both packages live in a development dependency group, and a `settings/dev.py` adds `debug_toolbar` and `silk` to `INSTALLED_APPS` and `MIDDLEWARE`, with the URLs included only when the app is installed. The toolbar has guards of its own: the default `SHOW_TOOLBAR_CALLBACK` needs `DEBUG = True` and `REMOTE_ADDR` in `INTERNAL_IPS`, and `debug_toolbar_urls()` returns nothing without `DEBUG`. They fail if `DEBUG` is on in production, if a custom callback returns `True`, or if a proxy's address sits in `INTERNAL_IPS`, since every visitor then arrives from it. Silk has **no** `DEBUG` check: it keeps recording, stores bodies, headers and SQL, and serves `/silk/` to anyone unless `SILKY_AUTHENTICATION` and `SILKY_AUTHORISATION` are `True`. Its masking only covers keys matching `SILKY_SENSITIVE_KEYS`, so a `card_number` field is stored in clear.
code
python · 25 lines# settings/dev.py
from .base import * # noqa: F403
DEBUG = True
INTERNAL_IPS = ["127.0.0.1"]
INSTALLED_APPS = [*INSTALLED_APPS, "debug_toolbar", "silk"] # noqa: F405
MIDDLEWARE = [
"debug_toolbar.middleware.DebugToolbarMiddleware",
"silk.middleware.SilkyMiddleware",
*MIDDLEWARE, # noqa: F405 (no GZipMiddleware in this project)
]
# urls.py
from django.apps import apps
from django.urls import include, path
urlpatterns = [
# ... the project's own routes ...
]
if apps.is_installed("debug_toolbar"):
from debug_toolbar.toolbar import debug_toolbar_urls
urlpatterns += debug_toolbar_urls()
if apps.is_installed("silk"):
urlpatterns += [path("silk/", include("silk.urls", namespace="silk"))]go deeper
Remember that both tools are for development only and belong in development settings, never in production.
Explain the toolbar's DEBUG and INTERNAL_IPS guard and why silk, lacking any such guard, is the more dangerous one to leave installed.
Spot the ways guards get defeated, such as proxy addresses, permissive callbacks and copied settings, and lock silk down when a shared environment needs it.
Set a policy that development tooling never ships in the production artefact and that changes to its gating settings get security review.
## What each tool exposes Both tools exist to show internals, which is exactly what must not reach the public. | Tool | What an outsider could see or do | |---|---| | django-debug-toolbar | every SQL statement with its parameters, template context, request data and session, headers, cache keys, signal receivers, settings (filtered through Django's `SafeExceptionReporterFilter`), stack traces with file paths; and the SQL panel's endpoints re-run `SELECT` statements and `EXPLAIN`, which on PostgreSQL is `EXPLAIN ANALYZE` and executes the query | | django-silk | stored request and response bodies and headers for thousands of past requests, every SQL query with parameters, profiles; a UI at `/silk/` to browse them | ## The toolbar's own guards django-debug-toolbar is built to stay dark outside development: - the default `SHOW_TOOLBAR_CALLBACK`, `debug_toolbar.middleware.show_toolbar`, returns `False` unless `settings.DEBUG` is `True`, and then requires `REMOTE_ADDR` to be in `INTERNAL_IPS`; - `debug_toolbar_urls()` returns an empty list when `DEBUG` is `False`. How teams defeat those guards anyway: 1. **`DEBUG = True` in production.** That alone is a serious leak through Django's own error pages, and it re-arms the toolbar. 2. **A permissive callback.** `"SHOW_TOOLBAR_CALLBACK": lambda request: True` to see the toolbar on staging stays when the settings are copied. 3. **The proxy's address in `INTERNAL_IPS`.** Behind a reverse proxy or load balancer, `REMOTE_ADDR` is the proxy for every visitor, so listing it makes every visitor internal. 4. **`show_toolbar_with_docker` outside a container.** Its docs warn that its gateway guess can then match another machine on the network. ## django-silk has no such guard Silk never looks at `DEBUG`. If `silk` is in `INSTALLED_APPS` and `SilkyMiddleware` in `MIDDLEWARE`, it records. Its defaults are development defaults: - `SILKY_AUTHENTICATION` and `SILKY_AUTHORISATION` are `False`, so **anybody** can open `/silk/`; with both `True`, the default `SILKY_PERMISSIONS` admits staff users only; - `SILKY_INTERCEPT_PERCENT` is `100`, so every request is written to the database; - `SILKY_MAX_RECORDED_REQUESTS` is `10**4`, trimmed on a share of requests, so the tables hold a large history; - masking is by key name: `SILKY_SENSITIVE_KEYS` defaults to `username`, `api`, `token`, `key`, `secret`, `password` and `signature`, matched against body keys and header names, with cookies hidden by `SILKY_HIDE_COOKIES`. A body field called `card_number` or `iban` is stored as is, and SQL parameters are stored unmasked; - `SILKY_ANALYZE_QUERIES` is `False`, and should stay so: silk's docs warn that turning it on can execute queries a second time. ## Keeping them out, structurally - **Dependencies**: install both only in a development dependency group, so the production image cannot import them. - **Settings**: a `settings/dev.py` that imports the base settings and appends the apps and middleware; production settings never mention them. - **URLs**: include the toolbar's and silk's URLs only when the app is installed, using `django.apps.apps.is_installed()`. - **Tests**: skip the toolbar during tests; its `debug_toolbar.E001` check flags setups likely to break there. - **Review**: treat any change to `INTERNAL_IPS`, `SHOW_TOOLBAR_CALLBACK` or silk's settings in shared settings files as a security-relevant change. ## If silk must run on a shared environment Sometimes a team wants recordings from staging. Then turn on `SILKY_AUTHENTICATION` and `SILKY_AUTHORISATION`, sample with `SILKY_INTERCEPT_PERCENT` or `SILKY_INTERCEPT_FUNC`, cap bodies with `SILKY_MAX_REQUEST_BODY_SIZE` and `SILKY_MAX_RESPONSE_BODY_SIZE`, extend `SILKY_SENSITIVE_KEYS` with your own field names, and clear old data with the `silk_clear_request_log` management command. Staging with real customer data is still production data. ## A quick pre-release check 1. Build the production image and list its installed packages: neither tool should be there. 2. Start it with production settings and request `/__debug__/` and `/silk/`: both should return 404. 3. Grep shared settings for `INTERNAL_IPS`, `SHOW_TOOLBAR_CALLBACK` and `SILKY_`. Three minutes of checking closes a leak that would otherwise hand an attacker the database's queries and every recorded request body.
- Behind a reverse proxy, how would you let only developers see django-debug-toolbar on a staging Django site?Do not add the proxy's address to `INTERNAL_IPS`, because every request arrives from it. Write a `SHOW_TOOLBAR_CALLBACK` that requires `DEBUG` and an authenticated staff user, or reach staging over a private network where `REMOTE_ADDR` is the developer's own address. Keep that callback in the staging settings only.
- Why is django-silk riskier than the toolbar if it is accidentally left in a production Django deployment?The toolbar's default callback still requires `DEBUG = True` and an internal address, so it usually stays dark. Silk checks neither: it records every request's bodies, headers and SQL into the database and, with its authentication settings off by default, serves them to anyone who opens `/silk/`.
saying these in an interview costs you the question
- django-silk stops recording automatically when DEBUG is False
- Adding the load balancer's IP to INTERNAL_IPS is a safe staging trick
- The /silk/ UI requires a staff login by default
- SILKY_SENSITIVE_KEYS masks every personal field in stored bodies
- debug_toolbar_urls() keeps mounting the toolbar views when DEBUG is off