Merge pull request #2644 from rrgeorge/rrgeorge/csp

Add Content-Security-Policy headers and secure cookies
This commit is contained in:
Mouse Reeve 2023-02-10 16:37:39 -08:00 committed by GitHub
commit 2c2daf5fdf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 33 additions and 15 deletions

View file

@ -101,6 +101,7 @@ MIDDLEWARE = [
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"csp.middleware.CSPMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"bookwyrm.middleware.TimezoneMiddleware",
"bookwyrm.middleware.IPBlocklistMiddleware",
@ -335,6 +336,8 @@ PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
PROTOCOL = "http"
if USE_HTTPS:
PROTOCOL = "https"
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
USE_S3 = env.bool("USE_S3", False)
@ -358,11 +361,17 @@ if USE_S3:
MEDIA_FULL_URL = MEDIA_URL
STATIC_FULL_URL = STATIC_URL
DEFAULT_FILE_STORAGE = "bookwyrm.storage_backends.ImagesStorage"
CSP_DEFAULT_SRC = ("'self'", AWS_S3_CUSTOM_DOMAIN)
CSP_SCRIPT_SRC = ("'self'", AWS_S3_CUSTOM_DOMAIN)
else:
STATIC_URL = "/static/"
MEDIA_URL = "/images/"
MEDIA_FULL_URL = f"{PROTOCOL}://{DOMAIN}{MEDIA_URL}"
STATIC_FULL_URL = f"{PROTOCOL}://{DOMAIN}{STATIC_URL}"
CSP_DEFAULT_SRC = "'self'"
CSP_SCRIPT_SRC = "'self'"
CSP_INCLUDE_NONCE_IN = ["script-src"]
OTEL_EXPORTER_OTLP_ENDPOINT = env("OTEL_EXPORTER_OTLP_ENDPOINT", None)
OTEL_EXPORTER_OTLP_HEADERS = env("OTEL_EXPORTER_OTLP_HEADERS", None)

View file

@ -1,6 +1,6 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
const tour = new Shepherd.Tour({
exitOnEsc: true,
});

View file

@ -1,6 +1,6 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
const tour = new Shepherd.Tour({
exitOnEsc: true,
});

View file

@ -1,6 +1,6 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
const initiateTour = new Shepherd.Tour({
exitOnEsc: true,
});

View file

@ -2,7 +2,7 @@
{% load utilities %}
{% load user_page_tags %}
<script>
<script nonce="{{request.csp_nonce}}">
const tour = new Shepherd.Tour({
exitOnEsc: true,

View file

@ -1,6 +1,6 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
let localResult = document.querySelector(".local-book-search-result");
let remoteResult = document.querySelector(".remote-book-search-result");

View file

@ -1,6 +1,6 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
const tour = new Shepherd.Tour({
exitOnEsc: true,
});

View file

@ -1,6 +1,6 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
const tour = new Shepherd.Tour({
exitOnEsc: true,
});

View file

@ -1,6 +1,6 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
const tour = new Shepherd.Tour({
exitOnEsc: true,
});

View file

@ -183,7 +183,7 @@
{% include 'snippets/footer.html' %}
{% endblock %}
<script>
<script nonce="{{request.csp_nonce}}">
var csrf_token = '{{ csrf_token }}';
</script>

View file

@ -11,7 +11,7 @@
<title>{% block title %}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{% sass_src site_theme %}" rel="stylesheet" type="text/css" />
<script>
<script nonce="{{request.csp_nonce}}">
function closeWindow() {
window.close();
}
@ -32,7 +32,7 @@
</div>
</div>
<script>
<script nonce="{{request.csp_nonce}}">
var csrf_token = '{{ csrf_token }}';
</script>
<script src="{% static 'js/bookwyrm.js' %}?v={{ js_cache }}"></script>

View file

@ -1,5 +1,5 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
var registerStats = new Chart(
document.getElementById('register_stats'),
{

View file

@ -1,5 +1,5 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
var statusStats = new Chart(
document.getElementById('status_stats'),

View file

@ -1,5 +1,5 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
var userStats = new Chart(
document.getElementById('user_stats'),

View file

@ -1,5 +1,5 @@
{% load i18n %}
<script>
<script nonce="{{request.csp_nonce}}">
var worksStats = new Chart(
document.getElementById('works_stats'),

View file

@ -12,6 +12,8 @@ from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views import View
from csp.decorators import csp_update
from bookwyrm import models, settings
from bookwyrm.connectors.abstract_connector import get_data
from bookwyrm.connectors.connector_manager import ConnectorException
@ -27,6 +29,9 @@ from bookwyrm.utils import regex
class Dashboard(View):
"""admin overview"""
@csp_update(
SCRIPT_SRC="https://cdn.jsdelivr.net/npm/chart.js@3.5.1/dist/chart.min.js"
)
def get(self, request):
"""list of users"""
data = get_charts_and_stats(request)

View file

@ -8,6 +8,8 @@ from django.http import JsonResponse
from django.template.response import TemplateResponse
from django.views import View
from csp.decorators import csp_update
from bookwyrm import models
from bookwyrm.connectors import connector_manager
from bookwyrm.book_search import search, format_search_result
@ -21,6 +23,7 @@ from .helpers import handle_remote_webfinger
class Search(View):
"""search users or books"""
@csp_update(IMG_SRC="*")
def get(self, request):
"""that search bar up top"""
if is_api_request(request):

View file

@ -8,6 +8,7 @@ django-compressor==4.3.1
django-imagekit==4.1.0
django-model-utils==4.3.1
django-sass-processor==1.2.2
django-csp==3.7
environs==9.5.0
flower==1.2.0
libsass==0.22.0