diff --git a/pages/templates/search.html b/pages/templates/search.html
index 684156f..d726ad5 100644
--- a/pages/templates/search.html
+++ b/pages/templates/search.html
@@ -2,6 +2,12 @@
{% block content %}
Suche
+ {% if error_message %}
+
+ Fehler: {{ error_message }}
+
+ {% endif %}
+
diff --git a/pages/views.py b/pages/views.py
index a3afc06..3f25eba 100644
--- a/pages/views.py
+++ b/pages/views.py
@@ -1,6 +1,9 @@
from django.shortcuts import render
+from django.core.exceptions import ValidationError
+from django.utils.html import escape
+import re
from abschnitte.utils import render_textabschnitte
-from dokumente.models import Dokument, VorgabeLangtext, VorgabeKurztext, Geltungsbereich
+from dokumente.models import Dokument, VorgabeLangtext, VorgabeKurztext, Geltungsbereich, Vorgabe
from itertools import groupby
import datetime
import pprint
@@ -9,23 +12,60 @@ def startseite(request):
standards=list(Dokument.objects.filter(aktiv=True))
return render(request, 'startseite.html', {"dokumente":standards,})
+def validate_search_input(search_term):
+ """
+ Validate search input to prevent SQL injection and XSS
+ """
+ if not search_term:
+ raise ValidationError("Suchbegriff darf nicht leer sein")
+
+ # Remove any HTML tags to prevent XSS
+ search_term = re.sub(r'<[^>]*>', '', search_term)
+
+ # Allow only alphanumeric characters, spaces, and basic punctuation
+ # This prevents SQL injection and other malicious input
+ if not re.match(r'^[a-zA-Z0-9äöüÄÖÜß\s\-\.\,\:\;\!\?\(\)\[\]\{\}\"\']+$', search_term):
+ raise ValidationError("Ungültige Zeichen im Suchbegriff")
+
+ # Limit length to prevent DoS attacks
+ if len(search_term) > 200:
+ raise ValidationError("Suchbegriff ist zu lang")
+
+ return search_term.strip()
+
def search(request):
if request.method == "GET":
return render(request, 'search.html')
elif request.method == "POST":
- suchbegriff=request.POST.get("q")
+ raw_search_term = request.POST.get("q", "")
+
+ try:
+ suchbegriff = validate_search_input(raw_search_term)
+ except ValidationError as e:
+ return render(request, 'search.html', {
+ 'error_message': str(e),
+ 'search_term': escape(raw_search_term)
+ })
+
+ # Escape the search term for display in templates
+ safe_search_term = escape(suchbegriff)
result= {"all": {}}
- qs = VorgabeKurztext.objects.filter(inhalt__contains=suchbegriff).exclude(abschnitt__gueltigkeit_bis__lt=datetime.date.today())
+ qs = VorgabeKurztext.objects.filter(inhalt__icontains=suchbegriff).exclude(abschnitt__gueltigkeit_bis__lt=datetime.date.today())
result["kurztext"] = {k: [o.abschnitt for o in g] for k, g in groupby(qs, key=lambda o: o.abschnitt.dokument)}
- qs = VorgabeLangtext.objects.filter(inhalt__contains=suchbegriff).exclude(abschnitt__gueltigkeit_bis__lt=datetime.date.today())
+ qs = VorgabeLangtext.objects.filter(inhalt__icontains=suchbegriff).exclude(abschnitt__gueltigkeit_bis__lt=datetime.date.today())
result['langtext']= {k: [o.abschnitt for o in g] for k, g in groupby(qs, key=lambda o: o.abschnitt.dokument)}
+ qs = Vorgabe.objects.filter(titel__icontains=suchbegriff).exclude(gueltigkeit_bis__lt=datetime.date.today())
+ result['titel']= {k: list(g) for k, g in groupby(qs, key=lambda o: o.dokument)}
for r in result.keys():
for s in result[r].keys():
- result["all"][s] = set(result[r][s])
+ if r == 'titel':
+ result["all"][s] = set(result["all"].get(s, set()) | set(result[r][s]))
+ else:
+ result["all"][s] = set(result["all"].get(s, set()) | set(result[r][s]))
result["geltungsbereich"]={}
- geltungsbereich=set(list([x.geltungsbereich for x in Geltungsbereich.objects.filter(inhalt__contains=suchbegriff)]))
+ geltungsbereich=set(list([x.geltungsbereich for x in Geltungsbereich.objects.filter(inhalt__icontains=suchbegriff)]))
for s in geltungsbereich:
result["geltungsbereich"][s]=render_textabschnitte(s.geltungsbereich_set.order_by("order"))
pprint.pp (result)
- return render(request,"results.html",{"suchbegriff":suchbegriff,"resultat":result})
+ return render(request,"results.html",{"suchbegriff":safe_search_term,"resultat":result})