XSS prevention added (with tests)

This commit is contained in:
2025-11-27 15:43:41 +01:00
parent fd729b3019
commit f933b7d99a
7 changed files with 65 additions and 12 deletions

View File

@@ -15,7 +15,7 @@ Dieses Dokument bietet einen umfassenden Überblick über alle Tests im vgui-cic
## abschnitte App Tests
Die abschnitte App enthält 32 Tests, die Modelle, Utility-Funktionen, Diagram-Caching und Management-Befehle abdecken.
Die abschnitte App enthält 33 Tests, die Modelle, Utility-Funktionen, Diagram-Caching, Management-Befehle und Sicherheit abdecken.
### Modell-Tests
@@ -58,6 +58,7 @@ Die abschnitte App enthält 32 Tests, die Modelle, Utility-Funktionen, Diagram-C
- **test_render_text_with_footnotes**: Verarbeitet Text, der Fußnoten enthält
- **test_render_abschnitt_without_type**: Behandelt Textabschnitte ohne AbschnittTyp
- **test_render_abschnitt_with_empty_content**: Behandelt Textabschnitte mit leerem Inhalt
- **test_render_textabschnitte_xss_prevention**: Überprüft, dass bösartiger HTML-Code und Skript-Tags aus gerenderten Inhalten bereinigt werden, um XSS-Angriffe zu verhindern
### Diagram-Caching-Tests
@@ -332,8 +333,8 @@ Die stichworte App enthält 18 Tests, die Schlüsselwortmodelle und ihre Sortier
## Test-Statistiken
- **Gesamt-Tests**: 206
- **abschnitte**: 32 Tests
- **Gesamt-Tests**: 207
- **abschnitte**: 33 Tests (einschließlich XSS-Prävention)
- **dokumente**: 116 Tests (98 in tests.py + 9 in test_json.py + 9 JSON-Tests in Haupt-tests.py)
- **pages**: 4 Tests
- **referenzen**: 18 Tests
@@ -348,6 +349,7 @@ Die stichworte App enthält 18 Tests, die Schlüsselwortmodelle und ihre Sortier
4. **Utility-Funktionen**: Textverarbeitung, Caching, Formatierung
5. **Management-Befehle**: CLI-Schnittstelle und Ausgabeverarbeitung
6. **Integration**: App-übergreifende Funktionalität und Datenfluss
7. **Sicherheit**: XSS-Prävention durch HTML-Bereinigung beim Rendern von Inhalten
## Ausführen der Tests

View File

@@ -15,7 +15,7 @@ This document provides a comprehensive overview of all tests in the vgui-cicd Dj
## abschnitte App Tests
The abschnitte app contains 32 tests covering models, utility functions, diagram caching, and management commands.
The abschnitte app contains 33 tests covering models, utility functions, diagram caching, management commands, and security.
### Model Tests
@@ -58,6 +58,7 @@ The abschnitte app contains 32 tests covering models, utility functions, diagram
- **test_render_text_with_footnotes**: Processes text containing footnotes
- **test_render_abschnitt_without_type**: Handles Textabschnitte without AbschnittTyp
- **test_render_abschnitt_with_empty_content**: Handles Textabschnitte with empty content
- **test_render_textabschnitte_xss_prevention**: Verifies that malicious HTML and script tags are sanitized from rendered content to prevent XSS attacks
### Diagram Caching Tests
@@ -332,8 +333,8 @@ The stichworte app contains 18 tests covering keyword models and their ordering.
## Test Statistics
- **Total Tests**: 206
- **abschnitte**: 32 tests
- **Total Tests**: 207
- **abschnitte**: 33 tests (including XSS prevention)
- **dokumente**: 116 tests (98 in tests.py + 9 in test_json.py + 9 JSON tests in main tests.py)
- **pages**: 4 tests
- **referenzen**: 18 tests
@@ -348,6 +349,7 @@ The stichworte app contains 18 tests covering keyword models and their ordering.
4. **Utility Functions**: Text processing, caching, formatting
5. **Management Commands**: CLI interface and output handling
6. **Integration**: Cross-app functionality and data flow
7. **Security**: XSS prevention through HTML sanitization in content rendering
## Running the Tests

View File

@@ -28,12 +28,6 @@ DEBUG = True
ALLOWED_HOSTS = ["10.128.128.144","localhost","127.0.0.1","*"]
TEMPLATES = [
{"BACKEND": "django.template.backends.django.DjangoTemplates",
"APP_DIRS": True,
}
]
# Application definition
INSTALLED_APPS = [

View File

@@ -467,6 +467,32 @@ A -> B
typ, html = result[0]
self.assertEqual(typ, "text")
def test_render_textabschnitte_xss_prevention(self):
"""Test that malicious HTML is sanitized in rendered content"""
from dokumente.models import VorgabeLangtext
# Create content with malicious HTML
malicious_abschnitt = VorgabeLangtext.objects.create(
abschnitt=self.vorgabe,
abschnitttyp=self.typ_text,
inhalt='<script>alert("xss")</script><img src=x onerror=alert(1)>Normal text',
order=1
)
result = render_textabschnitte(VorgabeLangtext.objects.filter(pk=malicious_abschnitt.pk))
self.assertEqual(len(result), 1)
typ, html = result[0]
self.assertEqual(typ, "text")
# Dangerous tags and attributes should be removed or sanitized
self.assertNotIn('<script>', html) # Script tags should not be present unescaped
self.assertNotIn('onerror', html) # Dangerous attributes removed
# Note: 'alert' may still be present in escaped script tags, which is safe
# Safe content should remain
self.assertIn('Normal text', html)
class MdTableToHtmlTest(TestCase):
"""Test cases for md_table_to_html function"""

View File

@@ -4,12 +4,34 @@ import zlib
import re
from textwrap import dedent
from django.conf import settings
import bleach
# Import the caching function
from diagramm_proxy.diagram_cache import get_cached_diagram
DIAGRAMMSERVER="/diagramm"
# Allowed HTML tags for bleach sanitization
ALLOWED_TAGS = [
'p', 'br', 'strong', 'em', 'u', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'ul', 'ol', 'li', 'blockquote', 'code', 'pre', 'hr',
'table', 'thead', 'tbody', 'tr', 'th', 'td',
'img', 'a', 'sup', 'sub', 'span', 'div'
]
ALLOWED_ATTRIBUTES = {
'img': ['src', 'alt', 'width', 'height'],
'a': ['href', 'title'],
'span': ['class'],
'div': ['class'],
'p': ['class'],
'table': ['class'],
'th': ['colspan', 'rowspan', 'class'],
'td': ['colspan', 'rowspan', 'class'],
'pre': ['class'],
'code': ['class'],
}
def render_textabschnitte(queryset):
"""
Converts a queryset of Textabschnitt-like models into a list of (typ, html) tuples.
@@ -52,6 +74,8 @@ def render_textabschnitte(queryset):
html += "</code></pre>"
else:
html = markdown(inhalt, extensions=['tables', 'attr_list','footnotes'])
# Sanitize HTML to prevent XSS
html = bleach.clean(html, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRIBUTES)
output.append((typ, html))
return output

View File

@@ -102,6 +102,7 @@
<li><a href="/dokumente">Standards</a></li>
{% if user.is_staff %}
<li><a href="/dokumente/unvollstaendig/">Unvollständig</a></li>
<li><a href="/autorenumgebung/">Autorenumgebung</a></li>
{% endif %}
<li><a href="/referenzen">Referenzen</a></li>
<li><a href="/stichworte">Stichworte</a></li>
@@ -131,6 +132,9 @@
<li class="dropdown {% if 'unvollstaendig' in request.path %}current{% endif %}">
<a href="/dokumente/unvollstaendig/">Unvollständig</a>
</li>
<li class="dropdown {% if 'autorenumgebung' in request.path %}current{% endif %}">
<a href="/autorenumgebung/">Autorenumgebung</a>
</li>
{% endif %}
<li class="dropdown {% if 'referenzen' in request.path %}current{% endif %}">
<a href="/referenzen">Referenzen</a>

View File

@@ -32,3 +32,4 @@ six==1.17.0
sqlparse==0.5.3
urllib3==2.5.0
wcwidth==0.2.13
bleach==6.1.0