So sichern Sie Ihre Django-Anwendung mit einer Content Security Policy

Der Autor hat Girls Who Code ausgewählt, um eine Spende im Rahmen des Write for Donations-Programms zu erhalten.

Einführung

Wenn Sie eine Website besuchen, werden verschiedene Ressourcen zum Laden und Rendern verwendet. Wenn Sie beispielsweise zu https://www.digitalocean.com gehen, lädt Ihr Browser das HTML und CSS direkt von digitalocean.com herunter. Bilder und andere Assets werden jedoch von assets.digitalocean.com heruntergeladen, und Analyse-Skripte werden von ihren jeweiligen Domains geladen.

Einige Websites verwenden eine Vielzahl verschiedener Dienste, Stile und Skripte zum Laden und Rendern ihrer Inhalte, und Ihr Browser führt all dies aus. Ein Browser weiß nicht, ob Code bösartig ist, daher ist es die Verantwortung des Entwicklers, Benutzer zu schützen. Da auf einer Website viele Ressourcen vorhanden sein können, ist es eine gute Idee, eine Funktion im Browser zu haben, die nur genehmigte Ressourcen zulässt, um sicherzustellen, dass Benutzer nicht gefährdet werden. Dafür sind Content-Sicherheitsrichtlinien (CSPs) da.

Mit einem CSP-Header kann ein Entwickler bestimmte Ressourcen explizit zulassen, während alle anderen verhindert werden können. Da die meisten Websites mehr als 100 Ressourcen haben können und jede einzelne für die spezifische Kategorie von Ressourcen genehmigt werden muss, kann die Implementierung eines CSP eine mühsame Aufgabe sein. Eine Website mit einem CSP wird jedoch sicherer sein, da nur genehmigte Ressourcen ausgeführt werden dürfen.

In diesem Tutorial werden Sie eine CSP in einer grundlegenden Django-Anwendung implementieren. Sie werden die CSP anpassen, um bestimmten Domänen und Inline-Ressourcen die Ausführung zu ermöglichen. Optional können Sie auch Sentry verwenden, um Verstöße zu protokollieren.

Voraussetzungen

Um dieses Tutorial abzuschließen, benötigen Sie:

Schritt 1 – Erstellen einer Demo-Ansicht

In diesem Schritt werden Sie ändern, wie Ihre Anwendung Ansichten behandelt, damit Sie CSP-Unterstützung hinzufügen können.

Als Voraussetzung haben Sie Django installiert und ein Beispielprojekt eingerichtet. Die Standardansicht in Django ist zu einfach, um alle Möglichkeiten des CSP-Middleware zu demonstrieren, daher erstellen Sie eine einfache HTML-Seite für dieses Tutorial.

Navigieren Sie zum Projektordner, den Sie in den Voraussetzungen erstellt haben:

  1. cd django-apps

Während du dich im Verzeichnis django-apps befindest, erstelle deine virtuelle Umgebung. Wir werden sie die generische env nennen, aber du solltest einen Namen verwenden, der für dich und dein Projekt sinnvoll ist.

  1. virtualenv env

Aktiviere nun die virtuelle Umgebung mit dem folgenden Befehl:

  1. . env/bin/activate

Innerhalb der virtuellen Umgebung erstelle eine views.py-Datei in deinem Projektordner mit nano oder deinem bevorzugten Texteditor:

  1. nano django-apps/testsite/testsite/views.py

Füge nun eine grundlegende Ansicht hinzu, die ein index.html-Template rendern wird, das du als nächstes erstellen wirst. Füge dazu folgendes zu views.py hinzu:

django-apps/testsite/testsite/views.py
from django.shortcuts import render

def index(request):
    return render(request, "index.html")

Speichere und schließe die Datei, wenn du fertig bist.

Erstelle ein index.html-Template in einem neuen templates-Verzeichnis:

mkdir django-apps/testsite/testsite/templates
nano django-apps/testsite/testsite/templates/index.html

Füge folgendes zu index.html hinzu:

django-apps/testsite/testsite/templates/index.html
<!DOCTYPE html>
<html>
    <head>
        <title>Hello world!</title>
        <link rel="preconnect" href="https://fonts.googleapis.com" />
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
        <link
            href="https://fonts.googleapis.com/css2?family=Yellowtail&display=swap"
            rel="stylesheet"
        />
        <style>
            h1 {
                font-family: "Yellowtail", cursive;
                margin: 0.5em 0 0 0;
                color: #0069ff;
                font-size: 4em;
                line-height: 0.6;
            }

            img {
                border-radius: 100%;
                border: 6px solid #0069ff;
            }

            .center {
                text-align: center;
                position: absolute;
                top: 50vh;
                left: 50vw;
                transform: translate(-50%, -50%);
            }
        </style>
    </head>
    <body>
        <div class="center">
            <img src="https://html.sammy-codes.com/images/small-profile.jpeg" />
            <h1>Hello, Sammy!</h1>
        </div>
    </body>
</html>

Die von uns erstellte Ansicht wird diese einfache HTML-Seite rendern. Es wird den Text Hallo, Sammy! sowie ein Bild von Sammy dem Hai anzeigen.

Speichere und schließe die Datei, wenn du fertig bist.

Um auf diese Ansicht zuzugreifen, musst du urls.py aktualisieren:

  1. nano django-apps/testsite/testsite/urls.py

Importiere die Datei views.py und füge eine neue Route hinzu, indem du die hervorgehobenen Zeilen hinzufügst:

django-apps/testsite/testsite/urls.py
from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.index),
]

Die neue Ansicht, die du gerade erstellt hast, ist nun sichtbar, wenn du / besuchst (wenn die Anwendung läuft).

Speichere und schließe die Datei.

Zum Schluss musst du INSTALLED_APPS aktualisieren, um testsite in settings.py einzuschließen:

  1. nano django-apps/testsite/testsite/settings.py
django-apps/testsite/testsite/settings.py
# ...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'testsite',
]
# ...

Hier fügen Sie testsite zur Liste der Anwendungen in settings.py hinzu, damit Django einige Annahmen über die Struktur Ihres Projekts treffen kann. In diesem Fall wird angenommen, dass der Ordner templates Django-Templates enthält, die Sie zum Rendern von Ansichten verwenden können.

Vom Stammverzeichnis des Projekts (testsite) aus starten Sie den Django-Entwicklungsserver mit dem folgenden Befehl und ersetzen dabei Ihre-Server-IP durch die IP-Adresse Ihres eigenen Servers.

  1. cd ~/django-apps/testsite
  2. python manage.py runserver your-server-ip:8000

Öffnen Sie einen Browser und besuchen Sie Ihre-Server-IP:8000. Die Seite sollte ähnlich aussehen wie folgt:

Zu diesem Zeitpunkt wird auf der Seite ein Profilbild von Sammy dem Hai angezeigt. Unter dem Bild befindet sich der Text Hallo, Sammy! in blauer Schrift.

Um den Django-Entwicklungsserver zu stoppen, drücken Sie CONTROL-C.

In diesem Schritt haben Sie eine grundlegende Ansicht erstellt, die als Startseite Ihres Django-Projekts fungiert. Als nächstes fügen Sie Ihrer Anwendung CSP-Unterstützung hinzu.

Schritt 2 — Installieren des CSP-Middleware

In diesem Schritt installieren und implementieren Sie eine CSP-Middleware, damit Sie CSP-Header hinzufügen und mit CSP-Funktionen in Ihren Ansichten arbeiten können. Middleware fügt jeder Anfrage oder Antwort, die Django verarbeitet, zusätzliche Funktionalität hinzu. In diesem Fall fügt die Django-CSP-Middleware CSP-Unterstützung zu Django-Antworten hinzu.

Zuerst installieren Sie das Mozilla CSP Middleware in Ihrem Django-Projekt mit pip, dem Paketmanager von Python. Verwenden Sie den folgenden Befehl, um das erforderliche Paket aus dem PyPi, dem Python Package Index, zu installieren. Um den Befehl auszuführen, können Sie entweder den Django-Entwicklungsserver mit CONTROL-C stoppen oder einen neuen Tab in Ihrem Terminal öffnen:

  1. pip install django-csp

Nächstens fügen Sie das Middleware zu den Einstellungen Ihres Django-Projekts hinzu. Öffnen Sie settings.py:

  1. nano testsite/testsite/settings.py

Mit django-csp installiert, können Sie jetzt das Middleware in settings.py hinzufügen. Dadurch werden CSP-Header zu Ihren Antworten hinzugefügt.
Fügen Sie die folgende Zeile zum MIDDLEWARE-Konfigurationsarray hinzu:

testsite/testsite/settings.py
MIDDLEWARE = [
    'csp.middleware.CSPMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Speichern und schließen Sie die Datei, wenn Sie fertig sind. Ihr Django-Projekt unterstützt jetzt CSPs. Im nächsten Schritt beginnen Sie damit, CSP-Header hinzuzufügen.

Schritt 3 — Implementierung eines CSP-Headers

Jetzt, da Ihr Projekt CSPs unterstützt, ist es bereit, abgesichert zu werden. Dazu konfigurieren Sie das Projekt so, dass CSP-Header zu Ihren Antworten hinzugefügt werden. Ein CSP-Header gibt an, wie sich der Browser verhalten soll, wenn er auf einen bestimmten Inhaltstyp trifft. Wenn der Header also sagt, dass nur Bilder von einer bestimmten Domain erlaubt sind, wird der Browser nur Bilder von dieser Domain zulassen.

Öffnen Sie mit nano oder Ihrem bevorzugten Texteditor settings.py:

  1. nano testsite/testsite/settings.py

Definieren Sie die folgenden Variablen irgendwo in der Datei:

testsite/testsite/settings.py
# Inhalts-Sicherheitsrichtlinie

CSP_IMG_SRC = ("'self'")

CSP_STYLE_SRC = ("'self'")

CSP_SCRIPT_SRC = ("'self'")

Diese Regeln sind die Vorlage für Ihre CSP. Diese Zeilen zeigen an, welche Quellen für Bilder, Stylesheets und Skripte erlaubt sind. Derzeit enthalten sie alle den String 'self', was bedeutet, dass nur Ressourcen von Ihrer eigenen Domain erlaubt sind.

Speichern und schließen Sie die Datei, wenn Sie fertig sind.

Führen Sie Ihr Django-Projekt mit dem folgenden Befehl aus:

  1. python manage.py runserver your-server-ip:8000

Wenn Sie Ihre-Server-IP:8000 besuchen, sehen Sie, dass die Website kaputt ist:

Wie erwartet erscheint das Bild nicht und der Text erscheint im Standard-Stil (fett schwarz). Dies bedeutet, dass der CSP-Header durchgesetzt wird und unsere Seite jetzt sicherer ist. Da die von Ihnen zuvor erstellte Ansicht Stylesheets und Bilder von Domains referenziert, die nicht Ihre eigenen sind, blockiert der Browser sie.

Ihr Projekt hat jetzt eine funktionierende CSP, die dem Browser sagt, Ressourcen zu blockieren, die nicht von Ihrer Domain stammen. Als nächstes werden Sie die CSP ändern, um bestimmte Ressourcen zuzulassen, was das fehlende Bild und Styling auf der Startseite beheben wird.

Schritt 4 — Ändern der CSP, um externe Ressourcen zuzulassen

Jetzt, da Sie eine grundlegende CSP haben, werden Sie diese basierend auf dem ändern, was Sie auf Ihrer Website verwenden. Als Beispiel benötigt eine Website, die Adobe Fonts und eingebettete YouTube-Videos verwendet, diese Ressourcen. Wenn Ihre Website jedoch nur Bilder aus Ihrem eigenen Domain anzeigt, können Sie die Bildereinstellungen auf ihre restriktiven Standardeinstellungen belassen.

Der erste Schritt besteht darin, jede Ressource zu finden, die Sie genehmigen müssen. Sie können dazu die Entwicklertools Ihres Browsers verwenden. Öffnen Sie den Netzwerkmonitor in der Elementinspektion, aktualisieren Sie die Seite und sehen Sie sich die blockierten Ressourcen an:

Das Netzwerkprotokoll zeigt, dass zwei Ressourcen durch die CSP blockiert werden: ein Stylesheet von fonts.googleapis.com und ein Bild von html.sammy-codes.com. Um diese Ressourcen im CSP-Header zu erlauben, müssen Sie die Variablen in settings.py ändern.

Um Ressourcen von externen Domains zuzulassen, fügen Sie die Domain zum Teil der CSP hinzu, der dem Dateityp entspricht. Um also ein Bild von html.sammy-codes.com zuzulassen, fügen Sie html.sammy-codes.com zu CSP_STYLE_SRC hinzu.

Öffnen Sie settings.py und fügen Sie folgendes zur Variable CSP_STYLE_SRC hinzu:

testsite/testsite/settings.py
CSP_IMG_SRC = ("'self'", 'https://html.sammy-codes.com')

Jetzt erlaubt die Website statt nur Bilder von Ihrer Domain auch Bilder von html.sammy-codes.com.

Die Indexansicht verwendet Google Fonts. Google liefert Ihre Website mit den Schriftarten (von https://fonts.gstatic.com) und mit einem Stylesheet, um sie anzuwenden (von https://fonts.googleapis.com). Um die Schriftarten laden zu können, fügen Sie dem CSP folgendes hinzu:

testsite/testsite/settings.py
CSP_STYLE_SRC = ("'self'", 'https://fonts.googleapis.com')

CSP_FONT_SRC = ("'self'", 'https://fonts.gstatic.com/')

Ähnlich wie bei der Erlaubnis von Bildern von html.sammy-codes.com, erlauben Sie auch Stylesheets von fonts.googleapis.com und Schriftarten von fonts.gstatic.com. Zur Erläuterung: Das Stylesheet, das von fonts.googleapis.com geladen wird, wird verwendet, um die Schriftarten anzuwenden. Die Schriftarten selbst werden von fonts.gstatic.com geladen.

Datei speichern und schließen.

Warnung: Ähnlich wie bei self gibt es andere Schlüsselwörter wie unsafe-inline, unsafe-eval oder unsafe-hashes, die in einem CSP verwendet werden können. Es wird dringend empfohlen, diese Regeln in Ihrem CSP zu vermeiden. Obwohl sie die Implementierung erleichtern, können sie dazu verwendet werden, den CSP zu umgehen und ihn nutzlos zu machen.

Weitere Informationen finden Sie in der Mozilla-Produktdokumentation für „Unsicheres Inline-Skript“.

Jetzt dürfen Google Fonts Styles und Schriftarten auf Ihrer Website laden und html.sammy-codes.com darf Bilder laden. Wenn Sie jedoch eine Seite auf Ihrem Server besuchen, werden Sie möglicherweise feststellen, dass nur noch Bilder geladen werden. Das liegt daran, dass die Inline-Styles im HTML, die verwendet werden, um die Schriftarten anzuwenden, nicht erlaubt sind. Das werden Sie im nächsten Schritt beheben.

Schritt 5 – Arbeiten mit Inline-Skripten und -Stilen

Zu diesem Zeitpunkt haben Sie die CSP so geändert, dass externe Ressourcen erlaubt sind. Inline-Ressourcen wie Styles und Skripte in Ihrer Ansicht sind jedoch immer noch nicht erlaubt. In diesem Schritt werden Sie diese so einrichten, dass Sie Schriftarten anwenden können.

Es gibt zwei Möglichkeiten, Inline-Skripte und -Stile zuzulassen: Nonces und Hashes. Wenn Sie feststellen, dass Sie Inline-Skripte und -Stile häufig ändern, verwenden Sie Nonces, um häufige Änderungen an Ihrer CSP zu vermeiden. Wenn Sie Inline-Skripte und -Stile selten aktualisieren, ist die Verwendung von Hashes ein vernünftiger Ansatz.

Verwendung von nonce zum Zulassen von Inline-Skripten

Zunächst werden Sie den Nonce-Ansatz verwenden. Ein Nonce ist ein zufällig generiertes Token, das für jede Anfrage eindeutig ist. Wenn zwei Personen Ihre Website besuchen, erhalten sie jeweils einen eindeutigen Nonce, der in den von Ihnen genehmigten Inline-Skripten und -Stilen eingebettet ist. Denken Sie an Nonce als ein Einmalpasswort, das bestimmte Teile einer Website für eine einzelne Sitzung genehmigt.

Um die Unterstützung für Nonce in Ihrem Projekt hinzuzufügen, aktualisieren Sie Ihre CSP in settings.py. Öffnen Sie die Datei zum Bearbeiten:

  1. nano testsite/testsite/settings.py

Fügen Sie script-src in CSP_INCLUDE_NONCE_IN in der Datei settings.py hinzu.

Definieren Sie CSP_INCLUDE_NONCE_IN irgendwo in der Datei und fügen Sie 'script-src' hinzu:

testsite/testsite/settings.py
# Inhaltsicherheitsrichtlinie

CSP_INCLUDE_NONCE_IN = ['script-src']

CSP_INCLUDE_NONCE_IN gibt an, für welche Inline-Skripte Sie nonce-Attribute hinzufügen dürfen. CSP_INCLUDE_NONCE_IN wird als Array behandelt, da mehrere Datenquellen Nonces unterstützen (zum Beispiel style-src).

Speichern und schließen Sie die Datei.

Nonces dürfen jetzt generiert werden für Inline-Skripte, wenn Sie das nonce-Attribut in Ihrer Ansichtsvorlage hinzufügen. Um dies auszuprobieren, verwenden Sie ein einfaches JavaScript-Snippet.

Öffnen Sie index.html zum Bearbeiten:

  1. nano testsite/testsite/templates/index.html

Fügen Sie das folgende Snippet im <head> des HTML-Dokuments hinzu:

testsite/testsite/templates/index.html
<script>
    console.log("Hello from the console!");
</script>

Dieses Snippet druckt Hallo aus der Konsole!" in die Browserkonsole. Da Ihr Projekt jedoch eine CSP hat, die nur Inline-Skripte erlaubt, wenn sie ein nonce haben, wird dieses Skript nicht ausgeführt und stattdessen einen Fehler produzieren.

Sie können diesen Fehler in der Browserkonsole sehen, wenn Sie die Seite aktualisieren:

Das Bild wird geladen, weil Sie externe Ressourcen im vorherigen Schritt erlaubt haben. Wie erwartet ist das Styling derzeit standardmäßig, weil Sie Inline-Styles noch nicht zugelassen haben. Auch wie erwartet, wurde die Konsolennachricht nicht gedruckt und es wurde ein Fehler zurückgegeben. Sie müssen ihm ein nonce geben, um es zu genehmigen.

Das können Sie tun, indem Sie nonce="{{request.csp_nonce}}" diesem Skript als Attribut hinzufügen. Öffnen Sie index.html zur Bearbeitung und fügen Sie den markierten Teil wie hier gezeigt hinzu:

testsite/testsite/templates/index.html
<script nonce="{{request.csp_nonce}}">
    console.log("Hello from the console!");
</script>

Speichern Sie Ihre Datei und schließen Sie sie, wenn Sie fertig sind.

Wenn Sie die Seite aktualisieren, wird das Skript nun ausgeführt:

Wenn Sie in Element untersuchen nachsehen, werden Sie feststellen, dass kein Wert für das Attribut vorhanden ist:

Der Wert erscheint aus Sicherheitsgründen nicht. Der Browser hat den Wert bereits verarbeitet. Er ist verborgen, damit Skripte, die auf das DOM zugreifen können, nicht darauf zugreifen und ihn auf ein anderes Skript anwenden können. Wenn Sie stattdessen Seitenquelle anzeigen, erhalten Sie Folgendes, was der Browser erhalten hat:

Beachten Sie, dass sich der nonce-Wert jedes Mal ändert, wenn Sie die Seite aktualisieren. Dies liegt daran, dass das CSP-Middleware in unserem Projekt für jede Anfrage einen neuen nonce generiert.

Diese nonce-Werte werden dem CSP-Header angehängt, wenn der Browser die Antwort erhält:

Jede Anfrage, die der Browser an Ihre Seite sendet, hat einen eindeutigen nonce-Wert für dieses Skript. Da der nonce im CSP-Header bereitgestellt wird, bedeutet dies, dass der Django-Server dieses bestimmte Skript genehmigt hat, um ausgeführt zu werden.

Sie haben Ihr Projekt aktualisiert, um mit Nonce zu arbeiten, das auf mehrere Ressourcen angewendet werden kann. Sie können es beispielsweise auch auf Styles anwenden, indem Sie CSP_INCLUDE_NONCE_IN aktualisieren, um style-src zu erlauben. Es gibt jedoch einen einfacheren Ansatz, um Inline-Ressourcen zu genehmigen, und das ist das, was Sie als nächstes tun werden.

Verwendung von Hashes zur Zulassung von Inline-Styles

Ein weiterer Ansatz zur Zulassung von Inline-Skripten und -Styles ist mit Hashes. Ein Hash ist ein eindeutiger Bezeichner für eine bestimmte Inline-Ressource.

Als Beispiel dies ist der Inline-Style in unserer Vorlage:

testsite/testsite/templates/index.html
<style>
    h1 {
        font-family: "Yellowtail", cursive;
        margin: 0.5em 0 0 0;
        color: #0069ff;
        font-size: 4em;
        line-height: 0.6;
    }

    img {
        border-radius: 100%;
        border: 6px solid #0069ff;
    }

    .center {
        text-align: center;
        position: absolute;
        top: 50vh;
        left: 50vw;
        transform: translate(-50%, -50%);
    }
</style>

Derzeit funktionieren die Styles jedoch nicht. Wenn Sie die Website im Browser anzeigen, werden die Bilder erfolgreich geladen, aber die Schriftarten und Styles werden nicht angewendet:

Im Konsolenfenster des Browsers finden Sie einen Fehler, dass ein Inline-Style gegen die CSP verstößt. (Es können auch andere Fehler auftreten, aber suchen Sie nach dem Fehler zum Inline-Style.)

Der Fehler wird verursacht, weil der Style nicht von unserer CSP genehmigt wird. Beachten Sie jedoch, dass der Fehler den Hash bereitstellt, der erforderlich ist, um den Style-Schnipsel zu genehmigen. Dieser Hash ist eindeutig für diesen spezifischen Style-Schnipsel. Keine anderen Schnipsel werden jemals denselben Hash haben. Wenn dieser Hash in die CSP eingefügt wird, wird jedes Mal, wenn dieser spezifische Style geladen wird, er genehmigt. Wenn Sie jedoch diese Styles jemals ändern, müssen Sie den neuen Hash erhalten und den alten durch ihn in der CSP ersetzen.

Sie wenden den Hash nun an, indem Sie ihn zu CSP_STYLE_SRC in settings.py hinzufügen, wie folgt:

  1. nano testsite/testsite/settings.py
testsite/testsite/settings.py
CSP_STYLE_SRC = ("'self' 'sha256-r5bInLZB0y6ZxHFpmz7cjyYrndjwCeDLDu/1KeMikHA='", 'https://fonts.googleapis.com')

Das Hinzufügen des sha256-... Hashes zur CSP_STYLE_SRC-Liste ermöglicht es dem Browser, das Stylesheet ohne Fehler zu laden.

Speichern und schließen Sie die Datei.

Jetzt laden Sie die Website im Browser neu, und die Schriften und Stile sollten erfolgreich geladen werden:

Inline-Styles und Skripte funktionieren jetzt korrekt. In diesem Schritt haben Sie zwei verschiedene Ansätze verwendet, Nonces und Hashes, um Inline-Styles und Skripte zu erlauben.

Aber es gibt ein wichtiges Problem zu lösen. CSPs sind mühsam zu pflegen, besonders für große Websites. Möglicherweise benötigen Sie eine Möglichkeit, zu verfolgen, wann der CSP eine Ressource blockiert, damit Sie feststellen können, ob es sich um eine bösartige Ressource oder einfach um einen defekten Teil Ihrer Website handelt. Im nächsten Schritt werden Sie Sentry verwenden, um alle Verstöße gegen Ihren CSP zu protokollieren und zu verfolgen.

Schritt 6 – Meldung von Verstößen mit Sentry (Optional)

Angesichts der strengen CSPs ist es gut zu wissen, wann Inhalte blockiert werden – insbesondere, da das Blockieren von Inhalten wahrscheinlich bedeutet, dass einige Funktionen auf Ihrer Website nicht funktionieren. Tools wie Sentry können Sie darüber informieren, wenn der CSP Anfragen von Benutzern blockiert. In diesem Schritt werden Sie Sentry konfigurieren, um CSP-Verstöße zu protokollieren und zu melden.

Als Voraussetzung haben Sie sich für ein Konto bei Sentry angemeldet. Jetzt werden Sie ein Projekt erstellen.

In der oberen linken Ecke des Sentry-Dashboards klicken Sie auf die Registerkarte Projekte:

In der oberen rechten Ecke klicken Sie auf die Schaltfläche Projekt erstellen:

Sie sehen eine Reihe von Logos mit einem Titel, der besagt Wählen Sie eine Plattform aus. Wählen Sie Django:

Dann, unten, benennen Sie Ihr Projekt (für dieses Beispiel verwenden wir sammys-tutorial) und klicken Sie auf die Schaltfläche Projekt erstellen:

Sentry wird Ihnen einen Code-Schnipsel geben, den Sie zu Ihrer settings.py-Datei hinzufügen müssen. Speichern Sie diesen Schnipsel, um ihn später hinzuzufügen.

Installieren Sie im Terminal das Sentry SDK:

  1. pip install --upgrade sentry-sdk

Öffnen Sie settings.py wie folgt:

  1. nano testsite/testsite/settings.py

Fügen Sie am Ende der Datei folgendes hinzu und ersetzen Sie SENTRY_DSN durch den Wert aus dem Dashboard:

testsite/testsite/settings.py
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration

sentry_sdk.init(
    dsn="SENTRY_DSN",
    integrations=[DjangoIntegration()],

    # Setzen Sie traces_sample_rate auf 1.0, um 100% zu erfassen
    # der Transaktionen für die Leistungsüberwachung.
    # Wir empfehlen, diesen Wert in der Produktion anzupassen.
    traces_sample_rate=1.0,

    # Wenn Sie Benutzer mit Fehlern verknüpfen möchten (vorausgesetzt, Sie verwenden
    # django.contrib.auth), können Sie die Übermittlung von PII-Daten aktivieren.
    send_default_pii=True
)

Dieser Code wird von Sentry bereitgestellt, damit es Fehler, die in Ihrer Anwendung auftreten, protokollieren kann. Es handelt sich um die Standardkonfiguration für Sentry und initialisiert Sentry zur Protokollierung von Problemen auf unserem Server. Technisch gesehen müssen Sie Sentry auf Ihrem Server nicht für CSP-Verletzungen initialisieren, aber für den seltenen Fall, dass es Probleme beim Rendern von Nonces oder Hashes gibt, werden diese Fehler an Sentry protokolliert.

Speichern Sie die Datei und schließen Sie sie.

Als nächstes gehen Sie zurück zum Dashboard für Ihr Projekt und klicken Sie auf das Zahnradsymbol, um zu Einstellungen zu gelangen:

Gehen Sie zum Tab Sicherheits-Header:

Kopieren Sie das report-uri:

Fügen Sie es Ihrem CSP wie folgt hinzu:

testsite/testsite/settings.py
# Inhalts-Sicherheitsrichtlinie

CSP_REPORT_URI = "your-report-uri"

Vergewissern Sie sich, dass Sie Ihr-Report-URI durch den Wert ersetzen, den Sie vom Dashboard kopiert haben.

Speichern und schließen Sie Ihre Datei. Jetzt, wenn die CSP-Durchsetzung einen Verstoß verursacht, wird Sentry ihn an diese URI protokollieren. Sie können dies ausprobieren, indem Sie eine Domain oder einen Hash aus Ihrem CSP entfernen oder den nonce aus dem Skript entfernen, den Sie zuvor hinzugefügt haben. Laden Sie die Seite im Browser, und Sie sehen den Fehler auf der Probleme-Seite von Sentry:

Wenn Sie feststellen, dass Sie von der Anzahl der Protokolle überwältigt sind, können Sie auch CSP_REPORT_PERCENTAGE in settings.py definieren, um nur einen Prozentsatz der Protokolle an Sentry zu senden.

testsite/testsite/settings.py
# Inhalts-Sicherheitsrichtlinie
# Senden Sie 10% der Protokolle an Sentry
CSP_REPORT_PERCENTAGE = 0.1

Jetzt werden Sie bei einem Verstoß gegen die CSP benachrichtigt und können den Fehler in Sentry anzeigen.

Fazit

In diesem Artikel haben Sie Ihre Django-Anwendung mit einer Inhaltsicherheitsrichtlinie abgesichert. Sie haben Ihre Richtlinie aktualisiert, um externe Ressourcen zu erlauben, und verwenden Nonces und Hashes, um Inline-Skripte und -Styles zu erlauben. Sie haben es auch konfiguriert, um Verstöße an Sentry zu senden. Als nächster Schritt schauen Sie sich die Django CSP-Dokumentation an, um mehr darüber zu erfahren, wie Sie Ihre CSP durchsetzen können.

Source:
https://www.digitalocean.com/community/tutorials/how-to-secure-your-django-application-with-a-content-security-policy