Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Failing after 30s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 21s
CI / test-python-dsms-gateway (push) Successful in 17s
- Ruff: 144 auto-fixes (unused imports, == None → is None), F821/F811/F841 manuell - CVEs: python-multipart>=0.0.22, weasyprint>=68.0, pillow>=12.1.1, npm audit fix (0 vulns) - TS: 5 tote Drafting-Engine-Dateien entfernt, allowed-facts/sanitizer/StepHeader/context fixes - Tests: +104 (ISMS 58, Evidence 18, VVT 14, Generation 14) → 1449 passed - Refactoring: collect_ci_evidence (F→A), row_to_response (E→A), extract_requirements (E→A) - Dead Code: pca-platform, 7 Go-Handler, dsr_api.py, duplicate Schemas entfernt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
875 lines
67 KiB
Python
875 lines
67 KiB
Python
"""
|
|
Compliance Regulation Scraper Service.
|
|
|
|
Extracts requirements and audit aspects from:
|
|
- EU-Lex regulations (GDPR, AI Act, CRA, NIS2, etc.)
|
|
- BSI Technical Guidelines (TR-03161)
|
|
- German laws (TDDDG, etc.)
|
|
|
|
Similar pattern to edu-search and zeugnisse-crawler.
|
|
"""
|
|
|
|
import logging
|
|
import re
|
|
from datetime import datetime
|
|
from typing import Dict, List, Any, Optional
|
|
from enum import Enum
|
|
|
|
import httpx
|
|
from bs4 import BeautifulSoup
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ..db.models import (
|
|
RegulationDB,
|
|
RequirementDB,
|
|
RegulationTypeEnum,
|
|
)
|
|
from ..db.repository import (
|
|
RegulationRepository,
|
|
RequirementRepository,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SourceType(str, Enum):
|
|
EUR_LEX = "eur_lex"
|
|
BSI_PDF = "bsi_pdf"
|
|
GESETZE_IM_INTERNET = "gesetze_im_internet"
|
|
MANUAL = "manual"
|
|
|
|
|
|
class ScraperStatus(str, Enum):
|
|
IDLE = "idle"
|
|
RUNNING = "running"
|
|
COMPLETED = "completed"
|
|
ERROR = "error"
|
|
|
|
|
|
class RegulationScraperService:
|
|
"""
|
|
Scrapes and extracts requirements from regulatory sources.
|
|
|
|
Supported sources:
|
|
- EUR-Lex: https://eur-lex.europa.eu/eli/reg/{year}/{number}/oj/eng
|
|
- BSI: Local PDF parsing
|
|
- Gesetze-im-Internet: German law portal
|
|
"""
|
|
|
|
# EUR-Lex patterns for article extraction
|
|
ARTICLE_PATTERN = re.compile(
|
|
r'Article\s+(\d+[a-z]?)\s*\n\s*(.+?)(?=\nArticle\s+\d|$)',
|
|
re.DOTALL | re.IGNORECASE
|
|
)
|
|
|
|
# BSI TR pattern for test aspects
|
|
BSI_ASPECT_PATTERN = re.compile(
|
|
r'(O\.[A-Za-z_]+[\d]*)\s+(.+?)(?=\nO\.|$)',
|
|
re.DOTALL
|
|
)
|
|
|
|
# Known regulation URLs - All 19 regulations from seed data
|
|
KNOWN_SOURCES = {
|
|
# A. Datenschutz & Datenuebermittlung
|
|
"GDPR": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32016R0679",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
"EPRIVACY": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32002L0058",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_DIRECTIVE,
|
|
},
|
|
"SCC": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32021D0914",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
"DPF": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32023D1795",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
# B. KI-Regulierung
|
|
"AIACT": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=OJ:L_202401689",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
# C. Cybersecurity & Produktsicherheit
|
|
"CRA": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=OJ:L_202402847",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
"NIS2": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32022L2555",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_DIRECTIVE,
|
|
},
|
|
"EUCSA": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32019R0881",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
# D. Datenoekonomie & Interoperabilitaet
|
|
"DATAACT": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32023R2854",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
"DGA": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32022R0868",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
# E. Plattform-Pflichten
|
|
"DSA": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32022R2065",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
# F. Barrierefreiheit
|
|
"EAA": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32019L0882",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_DIRECTIVE,
|
|
},
|
|
# G. IP & Urheberrecht
|
|
"DSM": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32019L0790",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_DIRECTIVE,
|
|
},
|
|
# H. Produkthaftung
|
|
"PLD": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32024L2853",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_DIRECTIVE,
|
|
},
|
|
"GPSR": {
|
|
"url": "https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:32023R0988",
|
|
"type": SourceType.EUR_LEX,
|
|
"regulation_type": RegulationTypeEnum.EU_REGULATION,
|
|
},
|
|
# I. BSI-Standards (Deutschland)
|
|
"BSI-TR-03161-1": {
|
|
"url": "/docs/BSI-TR-03161-1.pdf",
|
|
"type": SourceType.BSI_PDF,
|
|
"regulation_type": RegulationTypeEnum.BSI_STANDARD,
|
|
},
|
|
"BSI-TR-03161-2": {
|
|
"url": "/docs/BSI-TR-03161-2.pdf",
|
|
"type": SourceType.BSI_PDF,
|
|
"regulation_type": RegulationTypeEnum.BSI_STANDARD,
|
|
},
|
|
"BSI-TR-03161-3": {
|
|
"url": "/docs/BSI-TR-03161-3.pdf",
|
|
"type": SourceType.BSI_PDF,
|
|
"regulation_type": RegulationTypeEnum.BSI_STANDARD,
|
|
},
|
|
}
|
|
|
|
def __init__(self, db: Session):
|
|
self.db = db
|
|
self.reg_repo = RegulationRepository(db)
|
|
self.req_repo = RequirementRepository(db)
|
|
self.status = ScraperStatus.IDLE
|
|
self.current_source: Optional[str] = None
|
|
self.last_error: Optional[str] = None
|
|
self.stats = {
|
|
"sources_processed": 0,
|
|
"requirements_extracted": 0,
|
|
"errors": 0,
|
|
"last_run": None,
|
|
}
|
|
|
|
async def get_status(self) -> Dict[str, Any]:
|
|
"""Get current scraper status."""
|
|
return {
|
|
"status": self.status.value,
|
|
"current_source": self.current_source,
|
|
"last_error": self.last_error,
|
|
"stats": self.stats,
|
|
"known_sources": list(self.KNOWN_SOURCES.keys()),
|
|
}
|
|
|
|
async def scrape_all(self) -> Dict[str, Any]:
|
|
"""Scrape all known regulation sources."""
|
|
self.status = ScraperStatus.RUNNING
|
|
self.stats["last_run"] = datetime.utcnow().isoformat()
|
|
|
|
results = {
|
|
"success": [],
|
|
"failed": [],
|
|
"skipped": [],
|
|
}
|
|
|
|
for code, source_info in self.KNOWN_SOURCES.items():
|
|
try:
|
|
self.current_source = code
|
|
|
|
# Check if already scraped recently
|
|
existing = self.reg_repo.get_by_code(code)
|
|
if existing and existing.requirements:
|
|
results["skipped"].append({
|
|
"code": code,
|
|
"reason": "already_has_requirements",
|
|
"requirement_count": len(existing.requirements),
|
|
})
|
|
continue
|
|
|
|
# Scrape based on source type
|
|
if source_info["type"] == SourceType.EUR_LEX:
|
|
count = await self._scrape_eurlex(code, source_info)
|
|
elif source_info["type"] == SourceType.BSI_PDF:
|
|
count = await self._scrape_bsi_pdf(code, source_info)
|
|
else:
|
|
results["skipped"].append({
|
|
"code": code,
|
|
"reason": "unknown_source_type",
|
|
})
|
|
continue
|
|
|
|
results["success"].append({
|
|
"code": code,
|
|
"requirements_extracted": count,
|
|
})
|
|
self.stats["sources_processed"] += 1
|
|
self.stats["requirements_extracted"] += count
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error scraping {code}: {e}")
|
|
results["failed"].append({
|
|
"code": code,
|
|
"error": str(e),
|
|
})
|
|
self.stats["errors"] += 1
|
|
self.last_error = str(e)
|
|
|
|
self.status = ScraperStatus.COMPLETED
|
|
self.current_source = None
|
|
return results
|
|
|
|
async def scrape_single(self, code: str, force: bool = False) -> Dict[str, Any]:
|
|
"""Scrape a single regulation source."""
|
|
if code not in self.KNOWN_SOURCES:
|
|
raise ValueError(f"Unknown regulation code: {code}")
|
|
|
|
source_info = self.KNOWN_SOURCES[code]
|
|
self.status = ScraperStatus.RUNNING
|
|
self.current_source = code
|
|
|
|
try:
|
|
# Check existing
|
|
existing = self.reg_repo.get_by_code(code)
|
|
if existing and existing.requirements and not force:
|
|
self.status = ScraperStatus.COMPLETED
|
|
return {
|
|
"code": code,
|
|
"status": "skipped",
|
|
"reason": "already_has_requirements",
|
|
"requirement_count": len(existing.requirements),
|
|
}
|
|
|
|
# Delete existing requirements if force
|
|
if existing and force:
|
|
for req in existing.requirements:
|
|
self.db.delete(req)
|
|
self.db.commit()
|
|
|
|
# Scrape
|
|
if source_info["type"] == SourceType.EUR_LEX:
|
|
count = await self._scrape_eurlex(code, source_info)
|
|
elif source_info["type"] == SourceType.BSI_PDF:
|
|
count = await self._scrape_bsi_pdf(code, source_info)
|
|
else:
|
|
raise ValueError(f"Unknown source type: {source_info['type']}")
|
|
|
|
self.status = ScraperStatus.COMPLETED
|
|
return {
|
|
"code": code,
|
|
"status": "success",
|
|
"requirements_extracted": count,
|
|
}
|
|
|
|
except Exception as e:
|
|
self.status = ScraperStatus.ERROR
|
|
self.last_error = str(e)
|
|
raise
|
|
finally:
|
|
self.current_source = None
|
|
|
|
async def _scrape_eurlex(self, code: str, source_info: Dict) -> int:
|
|
"""Scrape EUR-Lex regulation page."""
|
|
url = source_info["url"]
|
|
logger.info(f"Scraping EUR-Lex: {code} from {url}")
|
|
|
|
async with httpx.AsyncClient(timeout=60.0) as client:
|
|
response = await client.get(url, follow_redirects=True)
|
|
response.raise_for_status()
|
|
|
|
html = response.text
|
|
soup = BeautifulSoup(html, 'html.parser')
|
|
|
|
# Get or create regulation
|
|
regulation = self.reg_repo.get_by_code(code)
|
|
if not regulation:
|
|
regulation = RegulationDB(
|
|
code=code,
|
|
name=code,
|
|
regulation_type=source_info["regulation_type"],
|
|
source_url=url,
|
|
is_active=True,
|
|
)
|
|
self.db.add(regulation)
|
|
self.db.commit()
|
|
self.db.refresh(regulation)
|
|
|
|
# Extract articles
|
|
requirements_created = 0
|
|
|
|
# Find all article elements (EUR-Lex structure varies)
|
|
articles = soup.find_all('div', class_='eli-subdivision')
|
|
if not articles:
|
|
articles = soup.find_all('p', class_='oj-ti-art')
|
|
|
|
for article_elem in articles:
|
|
try:
|
|
# Extract article number and title
|
|
article_id = article_elem.get('id', '')
|
|
if not article_id:
|
|
title_elem = article_elem.find(['span', 'p'], class_=['oj-ti-art', 'eli-title'])
|
|
if title_elem:
|
|
text = title_elem.get_text(strip=True)
|
|
match = re.search(r'Article\s+(\d+[a-z]?)', text, re.IGNORECASE)
|
|
if match:
|
|
article_id = f"art_{match.group(1)}"
|
|
|
|
if not article_id:
|
|
continue
|
|
|
|
# Extract article text
|
|
article_text = article_elem.get_text(separator='\n', strip=True)
|
|
|
|
# Parse article number and title
|
|
lines = article_text.split('\n')
|
|
article_num = None
|
|
title = None
|
|
|
|
for line in lines[:3]:
|
|
art_match = re.search(r'Article\s+(\d+[a-z]?)', line, re.IGNORECASE)
|
|
if art_match:
|
|
article_num = f"Art. {art_match.group(1)}"
|
|
elif not article_num:
|
|
continue
|
|
elif not title and len(line) > 3 and not line.startswith('Article'):
|
|
title = line[:200]
|
|
break
|
|
|
|
if not article_num:
|
|
continue
|
|
|
|
# Check if requirement already exists
|
|
existing = self.db.query(RequirementDB).filter(
|
|
RequirementDB.regulation_id == regulation.id,
|
|
RequirementDB.article == article_num
|
|
).first()
|
|
|
|
if existing:
|
|
continue
|
|
|
|
# Create requirement
|
|
requirement = RequirementDB(
|
|
regulation_id=regulation.id,
|
|
article=article_num,
|
|
title=title or f"{code} {article_num}",
|
|
requirement_text=article_text[:5000], # Limit length
|
|
source_section=article_id,
|
|
is_applicable=True,
|
|
priority=2,
|
|
)
|
|
self.db.add(requirement)
|
|
requirements_created += 1
|
|
|
|
except Exception as e:
|
|
logger.warning(f"Error parsing article in {code}: {e}")
|
|
continue
|
|
|
|
# Alternative: extract from raw text with regex
|
|
if requirements_created == 0:
|
|
text = soup.get_text()
|
|
matches = self.ARTICLE_PATTERN.findall(text)
|
|
|
|
for art_num, art_text in matches[:50]: # Limit to 50 articles
|
|
article_num = f"Art. {art_num}"
|
|
|
|
existing = self.db.query(RequirementDB).filter(
|
|
RequirementDB.regulation_id == regulation.id,
|
|
RequirementDB.article == article_num
|
|
).first()
|
|
|
|
if existing:
|
|
continue
|
|
|
|
# Extract first line as title
|
|
lines = art_text.strip().split('\n')
|
|
title = lines[0][:200] if lines else f"{code} {article_num}"
|
|
|
|
requirement = RequirementDB(
|
|
regulation_id=regulation.id,
|
|
article=article_num,
|
|
title=title,
|
|
requirement_text=art_text[:5000],
|
|
is_applicable=True,
|
|
priority=2,
|
|
)
|
|
self.db.add(requirement)
|
|
requirements_created += 1
|
|
|
|
# Fallback: If scraping failed (e.g., WAF protection), use seed requirements
|
|
if requirements_created == 0:
|
|
logger.info(f"Scraping returned 0 results for {code}, using seed requirements")
|
|
seed_reqs = self._get_eurlex_seed_requirements(code)
|
|
for seed in seed_reqs:
|
|
existing = self.db.query(RequirementDB).filter(
|
|
RequirementDB.regulation_id == regulation.id,
|
|
RequirementDB.article == seed["article"]
|
|
).first()
|
|
|
|
if existing:
|
|
continue
|
|
|
|
requirement = RequirementDB(
|
|
regulation_id=regulation.id,
|
|
article=seed["article"],
|
|
title=seed["title"],
|
|
description=seed.get("description"),
|
|
requirement_text=seed.get("requirement_text"),
|
|
is_applicable=True,
|
|
priority=seed.get("priority", 2),
|
|
)
|
|
self.db.add(requirement)
|
|
requirements_created += 1
|
|
|
|
self.db.commit()
|
|
logger.info(f"Extracted {requirements_created} requirements from {code}")
|
|
return requirements_created
|
|
|
|
def _get_eurlex_seed_requirements(self, code: str) -> List[Dict[str, Any]]:
|
|
"""
|
|
Returns seed requirements for EUR-Lex regulations when scraping fails.
|
|
|
|
These are the key articles relevant for Breakpilot compliance.
|
|
"""
|
|
if code == "NIS2":
|
|
return [
|
|
{"article": "Art. 6", "title": "Risikobewertung", "description": "Risikobewertung fuer Cybersicherheit", "requirement_text": "Einrichtungen muessen eine Risikobewertung fuer Cybersicherheit durchfuehren.", "priority": 1},
|
|
{"article": "Art. 7", "title": "Nationale Cybersicherheitsstrategie", "description": "Umsetzung nationaler Vorgaben", "requirement_text": "Einhaltung der nationalen Cybersicherheitsstrategie.", "priority": 2},
|
|
{"article": "Art. 20", "title": "Governance", "description": "Leitungsorgane muessen Cybersicherheit beaufsichtigen", "requirement_text": "Leitungsorgane muessen Cybersicherheitsmassnahmen genehmigen und deren Umsetzung beaufsichtigen.", "priority": 1},
|
|
{"article": "Art. 21", "title": "Risikomanagementmassnahmen", "description": "Technische und organisatorische Massnahmen", "requirement_text": "Geeignete und verhaeltnismaessige technische, operative und organisatorische Massnahmen zur Beherrschung von Cybersicherheitsrisiken.", "priority": 1},
|
|
{"article": "Art. 21(2)(a)", "title": "Risikoanalyse und Sicherheitskonzepte", "description": "Konzepte fuer Risikoanalyse", "requirement_text": "Konzepte fuer die Risikoanalyse und Sicherheit von Informationssystemen.", "priority": 1},
|
|
{"article": "Art. 21(2)(b)", "title": "Bewertung von Sicherheitsvorfaellen", "description": "Incident Handling", "requirement_text": "Bewertung der Wirksamkeit von Risikomanagementmassnahmen.", "priority": 1},
|
|
{"article": "Art. 21(2)(c)", "title": "Business Continuity", "description": "Betriebskontinuitaet sicherstellen", "requirement_text": "Aufrechterhaltung des Betriebs, Backup-Management und Krisenmanagement.", "priority": 1},
|
|
{"article": "Art. 21(2)(d)", "title": "Lieferkettensicherheit", "description": "Sicherheit in der Lieferkette", "requirement_text": "Sicherheit der Lieferkette einschliesslich Beziehungen zu Lieferanten.", "priority": 1},
|
|
{"article": "Art. 21(2)(e)", "title": "Sicherheit bei Entwicklung", "description": "Sichere Entwicklung", "requirement_text": "Sicherheit bei Erwerb, Entwicklung und Wartung von Systemen.", "priority": 1},
|
|
{"article": "Art. 21(2)(f)", "title": "Schwachstellenmanagement", "description": "Umgang mit Schwachstellen", "requirement_text": "Konzepte zur Bewertung der Wirksamkeit von Massnahmen.", "priority": 1},
|
|
{"article": "Art. 21(2)(g)", "title": "Cyberhygiene und Schulungen", "description": "Grundlegende Cyberhygiene-Praktiken", "requirement_text": "Grundlegende Cyberhygiene-Praktiken und Schulungen.", "priority": 1},
|
|
{"article": "Art. 21(2)(h)", "title": "Kryptografie", "description": "Einsatz von Verschluesselung", "requirement_text": "Konzepte und Verfahren fuer Kryptografie und Verschluesselung.", "priority": 1},
|
|
{"article": "Art. 21(2)(i)", "title": "Personalsicherheit", "description": "HR-Security", "requirement_text": "Sicherheit des Personals, Zugangskontrollen und Asset-Management.", "priority": 1},
|
|
{"article": "Art. 21(2)(j)", "title": "MFA und sichere Authentifizierung", "description": "Multi-Faktor-Authentifizierung", "requirement_text": "Multi-Faktor-Authentifizierung und sichere Kommunikation.", "priority": 1},
|
|
{"article": "Art. 23", "title": "Meldepflichten", "description": "Meldung von Sicherheitsvorfaellen", "requirement_text": "Erhebliche Sicherheitsvorfaelle muessen den zustaendigen Behoerden gemeldet werden.", "priority": 1},
|
|
{"article": "Art. 24", "title": "Europaeische Schwachstellendatenbank", "description": "CVE-Datenbank nutzen", "requirement_text": "Nutzung der europaeischen Schwachstellendatenbank.", "priority": 2},
|
|
]
|
|
|
|
elif code == "DATAACT":
|
|
return [
|
|
{"article": "Art. 3", "title": "Datenzugang fuer Nutzer", "description": "Nutzer koennen auf ihre Daten zugreifen", "requirement_text": "Daten, die durch Nutzung vernetzter Produkte generiert werden, muessen dem Nutzer zugaenglich gemacht werden.", "priority": 1},
|
|
{"article": "Art. 4", "title": "Recht auf Datenzugang", "description": "Unentgeltlicher Zugang", "requirement_text": "Nutzer haben das Recht auf unentgeltlichen Zugang zu ihren Daten.", "priority": 1},
|
|
{"article": "Art. 5", "title": "Recht auf Datenweitergabe", "description": "Daten an Dritte weitergeben", "requirement_text": "Nutzer koennen verlangen, dass Daten an Dritte weitergegeben werden.", "priority": 1},
|
|
{"article": "Art. 6", "title": "Pflichten des Dateninhabers", "description": "Daten zeitnah bereitstellen", "requirement_text": "Dateninhaber muessen Daten unverzueglich und in geeignetem Format bereitstellen.", "priority": 1},
|
|
{"article": "Art. 8", "title": "Faire Vertragsbedingungen", "description": "Keine unfairen Klauseln", "requirement_text": "Vertragsbedingungen fuer Datenzugang muessen fair und nicht-diskriminierend sein.", "priority": 2},
|
|
{"article": "Art. 14", "title": "Cloud-Switching", "description": "Wechsel zwischen Cloud-Anbietern", "requirement_text": "Unterstuetzung beim Wechsel zwischen Cloud-Diensten und Datenportabilitaet.", "priority": 1},
|
|
{"article": "Art. 23", "title": "Technische Schutzmassnahmen", "description": "Schutz nicht-personenbezogener Daten", "requirement_text": "Angemessene technische Schutzmassnahmen fuer nicht-personenbezogene Daten.", "priority": 1},
|
|
{"article": "Art. 25", "title": "Geschaeftsgeheimnisse", "description": "Schutz von Geschaeftsgeheimnissen", "requirement_text": "Massnahmen zum Schutz von Geschaeftsgeheimnissen bei Datenzugang.", "priority": 2},
|
|
]
|
|
|
|
elif code == "DGA":
|
|
return [
|
|
{"article": "Art. 5", "title": "Bedingungen fuer Weiterverwendung", "description": "Weiterverwendung oeffentlicher Daten", "requirement_text": "Bedingungen fuer die Weiterverwendung geschuetzter Daten oeffentlicher Stellen.", "priority": 2},
|
|
{"article": "Art. 7", "title": "Technische Anforderungen", "description": "Sichere Verarbeitungsumgebungen", "requirement_text": "Sichere Verarbeitungsumgebungen fuer Zugang zu geschuetzten Daten.", "priority": 1},
|
|
{"article": "Art. 10", "title": "Datenvermittlungsdienste", "description": "Registrierung von Vermittlungsdiensten", "requirement_text": "Datenvermittlungsdienste muessen registriert und reguliert werden.", "priority": 2},
|
|
{"article": "Art. 12", "title": "Bedingungen fuer Datenvermittlung", "description": "Neutralitaet wahren", "requirement_text": "Datenvermittler muessen neutral handeln und duerfen Daten nicht fuer eigene Zwecke nutzen.", "priority": 1},
|
|
{"article": "Art. 16", "title": "Datenaltruismus", "description": "Freiwillige Datenspende", "requirement_text": "Registrierung als Organisation fuer Datenaltruismus moeglich.", "priority": 3},
|
|
{"article": "Art. 21", "title": "Einwilligungsformular", "description": "Europaeisches Einwilligungsformular", "requirement_text": "Verwendung des europaeischen Einwilligungsformulars fuer Datenaltruismus.", "priority": 3},
|
|
]
|
|
|
|
elif code == "DSA":
|
|
return [
|
|
{"article": "Art. 6", "title": "Haftungsausschluss Hosting", "description": "Bedingungen fuer Haftungsausschluss", "requirement_text": "Hosting-Dienste haften nicht, wenn sie keine Kenntnis von rechtswidrigen Inhalten haben.", "priority": 1},
|
|
{"article": "Art. 11", "title": "Kontaktstelle", "description": "Behoerdenkontakt", "requirement_text": "Anbieter muessen eine Kontaktstelle fuer Behoerden benennen.", "priority": 2},
|
|
{"article": "Art. 12", "title": "Rechtsvertreter", "description": "Vertreter in der EU", "requirement_text": "Nicht-EU-Anbieter muessen einen Rechtsvertreter in der EU benennen.", "priority": 2},
|
|
{"article": "Art. 13", "title": "AGB-Transparenz", "description": "Transparente Nutzungsbedingungen", "requirement_text": "AGB muessen klar, verstaendlich und leicht zugaenglich sein.", "priority": 1},
|
|
{"article": "Art. 14", "title": "Transparenzberichte", "description": "Jaehrliche Berichte", "requirement_text": "Jaehrliche Transparenzberichte ueber Content-Moderation veroeffentlichen.", "priority": 2},
|
|
{"article": "Art. 16", "title": "Melde- und Abhilfeverfahren", "description": "Notice and Action", "requirement_text": "Leicht zugaengliches System fuer Meldung rechtswidriger Inhalte.", "priority": 1},
|
|
{"article": "Art. 17", "title": "Begruendungspflicht", "description": "Entscheidungen begruenden", "requirement_text": "Nutzer muessen ueber Content-Moderation-Entscheidungen informiert werden.", "priority": 1},
|
|
{"article": "Art. 20", "title": "Internes Beschwerdemanagement", "description": "Beschwerden bearbeiten", "requirement_text": "Internes System zur Bearbeitung von Beschwerden ueber Content-Moderation.", "priority": 1},
|
|
{"article": "Art. 26", "title": "Werbetransparenz", "description": "Werbung kennzeichnen", "requirement_text": "Online-Werbung muss klar als solche erkennbar sein.", "priority": 1},
|
|
{"article": "Art. 27", "title": "Empfehlungssysteme", "description": "Algorithmen erklaeren", "requirement_text": "Transparenz ueber Parameter von Empfehlungsalgorithmen.", "priority": 2},
|
|
]
|
|
|
|
elif code == "EUCSA":
|
|
return [
|
|
{"article": "Art. 46", "title": "Cybersicherheitszertifizierung", "description": "EU-Zertifizierungsrahmen", "requirement_text": "Freiwillige europaeische Zertifizierung fuer IKT-Produkte und -Dienste.", "priority": 2},
|
|
{"article": "Art. 51", "title": "Sicherheitsziele", "description": "Ziele der Zertifizierung", "requirement_text": "Schutz von Daten vor unbefugtem Zugriff, Manipulation und Zerstoerung.", "priority": 1},
|
|
{"article": "Art. 52", "title": "Vertrauenswuerdigkeitsstufen", "description": "Basic, Substantial, High", "requirement_text": "Drei Stufen: Basic, Substantial, High - je nach Risiko.", "priority": 1},
|
|
{"article": "Art. 54", "title": "Konformitaetsbewertung", "description": "Selbstbewertung oder Drittbewertung", "requirement_text": "Je nach Stufe Selbstbewertung oder unabhaengige Bewertung.", "priority": 2},
|
|
{"article": "Art. 56", "title": "Zertifizierungsstellen", "description": "Akkreditierte Stellen", "requirement_text": "Zertifizierung durch akkreditierte Konformitaetsbewertungsstellen.", "priority": 2},
|
|
]
|
|
|
|
elif code == "EAA":
|
|
return [
|
|
{"article": "Art. 3", "title": "Barrierefreiheitsanforderungen", "description": "Produkte barrierefrei gestalten", "requirement_text": "Produkte und Dienstleistungen muessen die Barrierefreiheitsanforderungen erfuellen.", "priority": 1},
|
|
{"article": "Art. 4", "title": "Bestehende Rechtsvorschriften", "description": "Verhaeltnis zu anderen Vorschriften", "requirement_text": "Ergaenzung zu bestehenden Barrierefreiheitsvorschriften.", "priority": 3},
|
|
{"article": "Art. 13", "title": "Konformitaetsvermutung", "description": "Harmonisierte Normen", "requirement_text": "Konformitaet bei Einhaltung harmonisierter Normen vermutet.", "priority": 2},
|
|
{"article": "Art. 14", "title": "Gemeinsame technische Spezifikationen", "description": "Falls keine Normen existieren", "requirement_text": "EU-Kommission kann technische Spezifikationen festlegen.", "priority": 3},
|
|
{"article": "Anhang I", "title": "Barrierefreiheitsanforderungen fuer Produkte", "description": "WCAG-konforme Webseiten", "requirement_text": "Webseiten, Apps und E-Books muessen WCAG 2.1 Level AA erfuellen.", "priority": 1},
|
|
]
|
|
|
|
elif code == "DSM":
|
|
return [
|
|
{"article": "Art. 3", "title": "Text and Data Mining (Forschung)", "description": "TDM fuer Forschung erlaubt", "requirement_text": "Text- und Data-Mining fuer wissenschaftliche Forschung ist erlaubt.", "priority": 2},
|
|
{"article": "Art. 4", "title": "Text and Data Mining (Allgemein)", "description": "TDM-Ausnahme", "requirement_text": "TDM erlaubt, wenn Rechteinhaber nicht widersprochen haben.", "priority": 1},
|
|
{"article": "Art. 15", "title": "Leistungsschutzrecht Presse", "description": "Verguetung fuer Presseverleger", "requirement_text": "Online-Nutzung von Presseveroeffentlichungen erfordert Lizenz.", "priority": 2},
|
|
{"article": "Art. 17", "title": "Upload-Filter", "description": "Plattformhaftung fuer Uploads", "requirement_text": "Plattformen haften fuer urheberrechtsverletzende Uploads ihrer Nutzer.", "priority": 1},
|
|
{"article": "Art. 17(7)", "title": "Overblocking verhindern", "description": "Legitime Nutzung schuetzen", "requirement_text": "Massnahmen duerfen nicht zu ungerechtfertigter Sperrung fuehren.", "priority": 1},
|
|
]
|
|
|
|
elif code == "PLD":
|
|
return [
|
|
{"article": "Art. 4", "title": "Produktbegriff", "description": "Software als Produkt", "requirement_text": "Software gilt als Produkt im Sinne der Produkthaftung.", "priority": 1},
|
|
{"article": "Art. 6", "title": "Fehlerhaftes Produkt", "description": "Definition Produktfehler", "requirement_text": "Ein Produkt ist fehlerhaft, wenn es nicht die erwartete Sicherheit bietet.", "priority": 1},
|
|
{"article": "Art. 7", "title": "KI-Systeme", "description": "Haftung fuer KI", "requirement_text": "Haftung gilt auch fuer durch KI verursachte Schaeden.", "priority": 1},
|
|
{"article": "Art. 9", "title": "Haftung des Herstellers", "description": "Verschuldensunabhaengige Haftung", "requirement_text": "Hersteller haften verschuldensunabhaengig fuer Produktfehler.", "priority": 1},
|
|
{"article": "Art. 10", "title": "Softwareaktualisierungen", "description": "Pflicht zu Updates", "requirement_text": "Fehlende Sicherheitsupdates koennen Haftung begruenden.", "priority": 1},
|
|
]
|
|
|
|
elif code == "GPSR":
|
|
return [
|
|
{"article": "Art. 5", "title": "Allgemeine Sicherheitsanforderung", "description": "Produkte muessen sicher sein", "requirement_text": "Nur sichere Produkte duerfen in Verkehr gebracht werden.", "priority": 1},
|
|
{"article": "Art. 8", "title": "Pflichten der Hersteller", "description": "Sicherheitsbewertung durchfuehren", "requirement_text": "Hersteller muessen Risikoanalyse und Sicherheitsbewertung durchfuehren.", "priority": 1},
|
|
{"article": "Art. 9", "title": "Technische Dokumentation", "description": "Dokumentationspflicht", "requirement_text": "Technische Dokumentation zur Konformitaet erstellen und aufbewahren.", "priority": 1},
|
|
{"article": "Art. 10", "title": "EU-Konformitaetserklaerung", "description": "CE-Kennzeichnung", "requirement_text": "Konformitaetserklaerung und CE-Kennzeichnung erforderlich.", "priority": 1},
|
|
{"article": "Art. 14", "title": "Produktrueckrufe", "description": "Rueckrufverfahren", "requirement_text": "Bei Sicherheitsrisiken muessen Produkte zurueckgerufen werden.", "priority": 1},
|
|
]
|
|
|
|
elif code == "CRA":
|
|
return [
|
|
{"article": "Art. 5", "title": "Wesentliche Anforderungen", "description": "Cybersicherheit bei Entwurf", "requirement_text": "Produkte muessen so entworfen werden, dass sie ein angemessenes Cybersicherheitsniveau gewaehrleisten.", "priority": 1},
|
|
{"article": "Art. 6", "title": "Sicherheitsupdates", "description": "Updates bereitstellen", "requirement_text": "Hersteller muessen Sicherheitsupdates fuer die erwartete Produktlebensdauer bereitstellen.", "priority": 1},
|
|
{"article": "Art. 10", "title": "Schwachstellenbehandlung", "description": "Vulnerability Handling", "requirement_text": "Hersteller muessen ein koordiniertes Schwachstellenmanagement implementieren.", "priority": 1},
|
|
{"article": "Art. 11", "title": "Meldepflicht", "description": "Schwachstellen melden", "requirement_text": "Aktiv ausgenutzte Schwachstellen muessen innerhalb von 24 Stunden gemeldet werden.", "priority": 1},
|
|
{"article": "Art. 13", "title": "SBOM", "description": "Software Bill of Materials", "requirement_text": "Eine SBOM muss fuer das Produkt erstellt und gepflegt werden.", "priority": 1},
|
|
{"article": "Art. 15", "title": "Support-Zeitraum", "description": "Mindest-Support-Dauer", "requirement_text": "Mindestens 5 Jahre Support oder erwartete Produktlebensdauer.", "priority": 1},
|
|
{"article": "Anhang I.1", "title": "Sichere Standardkonfiguration", "description": "Secure by Default", "requirement_text": "Produkte muessen mit sicheren Standardeinstellungen ausgeliefert werden.", "priority": 1},
|
|
{"article": "Anhang I.2", "title": "Schutz vor unbefugtem Zugriff", "description": "Access Control", "requirement_text": "Mechanismen zum Schutz vor unbefugtem Zugriff implementieren.", "priority": 1},
|
|
{"article": "Anhang I.3", "title": "Datenintegritaet", "description": "Integritaetsschutz", "requirement_text": "Schutz der Integritaet von Daten und Konfiguration.", "priority": 1},
|
|
{"article": "Anhang I.4", "title": "Verfuegbarkeit", "description": "Resilienz", "requirement_text": "Schutz vor DoS-Angriffen und Sicherstellung der Verfuegbarkeit.", "priority": 1},
|
|
]
|
|
|
|
elif code == "EPRIVACY":
|
|
return [
|
|
{"article": "Art. 5", "title": "Vertraulichkeit der Kommunikation", "description": "Kommunikation schuetzen", "requirement_text": "Vertraulichkeit der Kommunikation und Verkehrsdaten gewaehrleisten.", "priority": 1},
|
|
{"article": "Art. 6", "title": "Verkehrsdaten", "description": "Umgang mit Verkehrsdaten", "requirement_text": "Verkehrsdaten muessen nach Abschluss geloescht oder anonymisiert werden.", "priority": 1},
|
|
{"article": "Art. 9", "title": "Standortdaten", "description": "Nur mit Einwilligung", "requirement_text": "Standortdaten nur mit ausdruecklicher Einwilligung verarbeiten.", "priority": 1},
|
|
{"article": "Art. 13", "title": "Unerbetene Nachrichten", "description": "Opt-in fuer Marketing", "requirement_text": "Direktwerbung per E-Mail nur mit vorheriger Einwilligung.", "priority": 1},
|
|
]
|
|
|
|
elif code == "SCC":
|
|
return [
|
|
{"article": "Klausel 8", "title": "Datenschutzgarantien", "description": "Garantien dokumentieren", "requirement_text": "Datenimporteur muss angemessene Datenschutzgarantien gewaehrleisten.", "priority": 1},
|
|
{"article": "Klausel 10", "title": "Betroffenenrechte", "description": "Rechte durchsetzen", "requirement_text": "Betroffene koennen ihre Rechte auch gegenueber Datenimporteur geltend machen.", "priority": 1},
|
|
{"article": "Klausel 14", "title": "Lokale Rechtsvorschriften", "description": "Rechtslage pruefen", "requirement_text": "Parteien muessen pruefen, ob lokale Gesetze die Einhaltung verhindern.", "priority": 1},
|
|
{"article": "Klausel 15", "title": "Behoerdenzugriff", "description": "Transparenz bei Anfragen", "requirement_text": "Datenimporteur muss ueber Behoerdenanfragen informieren.", "priority": 1},
|
|
]
|
|
|
|
elif code == "DPF":
|
|
return [
|
|
{"article": "Prinzip 1", "title": "Notice", "description": "Informationspflicht", "requirement_text": "Betroffene muessen ueber Datenverarbeitung informiert werden.", "priority": 1},
|
|
{"article": "Prinzip 2", "title": "Choice", "description": "Wahlmoeglichkeit", "requirement_text": "Betroffene muessen der Weitergabe widersprechen koennen.", "priority": 1},
|
|
{"article": "Prinzip 4", "title": "Security", "description": "Sicherheitsmassnahmen", "requirement_text": "Angemessene Sicherheitsmassnahmen zum Schutz der Daten.", "priority": 1},
|
|
{"article": "Prinzip 5", "title": "Data Integrity", "description": "Datenintegritaet", "requirement_text": "Daten muessen richtig, vollstaendig und aktuell sein.", "priority": 1},
|
|
{"article": "Prinzip 6", "title": "Access", "description": "Auskunftsrecht", "requirement_text": "Betroffene haben Recht auf Zugang zu ihren Daten.", "priority": 1},
|
|
]
|
|
|
|
return []
|
|
|
|
async def _scrape_bsi_pdf(self, code: str, source_info: Dict) -> int:
|
|
"""
|
|
Scrape BSI Technical Guideline PDF.
|
|
|
|
Note: Full PDF parsing requires PyMuPDF or pdfplumber.
|
|
This is a placeholder that creates seed requirements.
|
|
"""
|
|
logger.info(f"Processing BSI TR: {code}")
|
|
|
|
# Get or create regulation
|
|
regulation = self.reg_repo.get_by_code(code)
|
|
if not regulation:
|
|
regulation = RegulationDB(
|
|
code=code,
|
|
name=f"BSI {code}",
|
|
full_name=f"BSI Technical Guideline {code}",
|
|
regulation_type=source_info["regulation_type"],
|
|
local_pdf_path=source_info["url"],
|
|
is_active=True,
|
|
)
|
|
self.db.add(regulation)
|
|
self.db.commit()
|
|
self.db.refresh(regulation)
|
|
|
|
# Known BSI TR-03161 test aspects (Pruefaspekte)
|
|
# These are the key security requirements from the TR
|
|
bsi_aspects = self._get_bsi_aspects(code)
|
|
|
|
requirements_created = 0
|
|
for aspect in bsi_aspects:
|
|
existing = self.db.query(RequirementDB).filter(
|
|
RequirementDB.regulation_id == regulation.id,
|
|
RequirementDB.article == aspect["id"]
|
|
).first()
|
|
|
|
if existing:
|
|
continue
|
|
|
|
requirement = RequirementDB(
|
|
regulation_id=regulation.id,
|
|
article=aspect["id"],
|
|
title=aspect["title"],
|
|
description=aspect.get("description"),
|
|
requirement_text=aspect.get("requirement_text"),
|
|
breakpilot_interpretation=aspect.get("interpretation"),
|
|
is_applicable=aspect.get("is_applicable", True),
|
|
priority=aspect.get("priority", 2),
|
|
source_page=aspect.get("page"),
|
|
source_section=aspect.get("section"),
|
|
)
|
|
self.db.add(requirement)
|
|
requirements_created += 1
|
|
|
|
self.db.commit()
|
|
logger.info(f"Created {requirements_created} BSI requirements from {code}")
|
|
return requirements_created
|
|
|
|
def _get_bsi_aspects(self, code: str) -> List[Dict[str, Any]]:
|
|
"""
|
|
Returns comprehensive BSI TR-03161 test aspects (Pruefaspekte).
|
|
|
|
These are the actual test aspects from BSI TR-03161:
|
|
- Part 1: Allgemeine Anforderungen (~45 Aspekte)
|
|
- Part 2: Web-Anwendungen (~40 Aspekte)
|
|
- Part 3: Hintergrundsysteme (~35 Aspekte)
|
|
|
|
Total: ~120 Pruefaspekte
|
|
"""
|
|
if code == "BSI-TR-03161-1":
|
|
# Teil 1: Allgemeine Anforderungen
|
|
return [
|
|
# Zweckbindung & Datenminimierung
|
|
{"id": "O.Purp_1", "title": "Zweckbindung", "description": "Anwendungszweck klar definiert", "requirement_text": "Die Anwendung muss einen klar definierten und dokumentierten Zweck haben.", "priority": 1, "section": "4.1"},
|
|
{"id": "O.Purp_2", "title": "Zweckdokumentation", "description": "Zweck fuer Nutzer einsehbar", "requirement_text": "Der Zweck muss fuer Nutzer transparent und einsehbar dokumentiert sein.", "priority": 2, "section": "4.1"},
|
|
{"id": "O.Data_1", "title": "Datenminimierung", "description": "Nur notwendige Daten erheben", "requirement_text": "Es duerfen nur die fuer den definierten Zweck erforderlichen Daten erhoben werden.", "priority": 1, "section": "4.2"},
|
|
{"id": "O.Data_2", "title": "Datenerforderlichkeit", "description": "Erforderlichkeit pruefen", "requirement_text": "Vor jeder Datenerhebung muss die Erforderlichkeit geprueft und dokumentiert werden.", "priority": 1, "section": "4.2"},
|
|
{"id": "O.Data_3", "title": "Datenkategorien", "description": "Datenkategorien klassifizieren", "requirement_text": "Alle verarbeiteten Datenkategorien muessen klassifiziert und dokumentiert sein.", "priority": 2, "section": "4.2"},
|
|
{"id": "O.Data_4", "title": "Besondere Kategorien", "description": "Art. 9 DSGVO Daten identifizieren", "requirement_text": "Besondere Kategorien personenbezogener Daten (Art. 9 DSGVO) muessen identifiziert und besonders geschuetzt werden.", "priority": 1, "section": "4.2"},
|
|
|
|
# Authentifizierung
|
|
{"id": "O.Auth_1", "title": "Authentifizierungsmechanismus", "description": "Sichere Authentifizierung", "requirement_text": "Die Anwendung muss sichere Authentifizierungsmechanismen implementieren.", "priority": 1, "section": "4.3"},
|
|
{"id": "O.Auth_2", "title": "Passwortrichtlinie", "description": "Starke Passwoerter erzwingen", "requirement_text": "Passwortrichtlinien muessen Mindestlaenge (12 Zeichen), Komplexitaet und Historie durchsetzen.", "priority": 1, "section": "4.3"},
|
|
{"id": "O.Auth_3", "title": "Passwort-Hashing", "description": "Sichere Hash-Algorithmen", "requirement_text": "Passwoerter muessen mit aktuellen Algorithmen (bcrypt, Argon2) gehasht werden.", "priority": 1, "section": "4.3"},
|
|
{"id": "O.Auth_4", "title": "Multi-Faktor-Authentifizierung", "description": "MFA fuer sensitive Bereiche", "requirement_text": "Fuer administrative und sensitive Funktionen muss MFA verfuegbar sein.", "priority": 1, "section": "4.3"},
|
|
{"id": "O.Auth_5", "title": "Brute-Force-Schutz", "description": "Rate Limiting bei Login", "requirement_text": "Nach mehreren fehlgeschlagenen Anmeldeversuchen muss Account-Lockout oder Rate-Limiting greifen.", "priority": 1, "section": "4.3"},
|
|
{"id": "O.Auth_6", "title": "Sichere Passwort-Wiederherstellung", "description": "Reset-Prozess absichern", "requirement_text": "Der Passwort-Reset-Prozess muss gegen Enumeration und Manipulation geschuetzt sein.", "priority": 1, "section": "4.3"},
|
|
|
|
# Autorisierung
|
|
{"id": "O.Authz_1", "title": "Zugriffskontrolle", "description": "Rollenbasierte Zugriffskontrolle", "requirement_text": "Ein rollenbasiertes Zugriffskonzept (RBAC) muss implementiert sein.", "priority": 1, "section": "4.4"},
|
|
{"id": "O.Authz_2", "title": "Least Privilege", "description": "Minimale Rechte", "requirement_text": "Benutzer sollen nur die minimal notwendigen Berechtigungen erhalten.", "priority": 1, "section": "4.4"},
|
|
{"id": "O.Authz_3", "title": "Rechtetrennung", "description": "Funktionale Trennung", "requirement_text": "Administrative und operative Rollen muessen getrennt sein.", "priority": 1, "section": "4.4"},
|
|
{"id": "O.Authz_4", "title": "Autorisierungspruefung", "description": "Serverseitige Pruefung", "requirement_text": "Jede Ressource muss serverseitig auf Zugriffsberechtigung geprueft werden.", "priority": 1, "section": "4.4"},
|
|
|
|
# Kryptografie
|
|
{"id": "O.Cryp_1", "title": "TLS-Verschluesselung", "description": "TLS 1.2+ fuer Transport", "requirement_text": "Alle Daten muessen bei der Uebertragung mit TLS 1.2 oder hoeher verschluesselt werden.", "priority": 1, "section": "4.5"},
|
|
{"id": "O.Cryp_2", "title": "Verschluesselung at Rest", "description": "Sensible Daten verschluesseln", "requirement_text": "Sensible Daten muessen bei der Speicherung verschluesselt werden (AES-256 oder vergleichbar).", "priority": 1, "section": "4.5"},
|
|
{"id": "O.Cryp_3", "title": "HSTS", "description": "HTTP Strict Transport Security", "requirement_text": "HSTS-Header muessen gesetzt sein um HTTPS zu erzwingen.", "priority": 1, "section": "4.5"},
|
|
{"id": "O.Cryp_4", "title": "Zertifikatvalidierung", "description": "Zertifikate pruefen", "requirement_text": "TLS-Zertifikate muessen vollstaendig validiert werden (Chain, Revocation, Hostname).", "priority": 1, "section": "4.5"},
|
|
{"id": "O.Cryp_5", "title": "Key Management", "description": "Sichere Schluesselverwaltung", "requirement_text": "Kryptographische Schluessel muessen sicher generiert, gespeichert und rotiert werden.", "priority": 1, "section": "4.5"},
|
|
{"id": "O.Cryp_6", "title": "Aktuelle Algorithmen", "description": "Keine veralteten Algorithmen", "requirement_text": "Es duerfen nur aktuelle, als sicher geltende kryptographische Algorithmen verwendet werden.", "priority": 1, "section": "4.5"},
|
|
|
|
# Datenschutz
|
|
{"id": "O.Priv_1", "title": "Datenschutzerklaerung", "description": "Transparente Information", "requirement_text": "Eine vollstaendige Datenschutzerklaerung muss vor Nutzung einsehbar sein.", "priority": 1, "section": "4.6"},
|
|
{"id": "O.Priv_2", "title": "Einwilligung", "description": "Wirksame Einwilligung", "requirement_text": "Einwilligungen muessen freiwillig, informiert, spezifisch und dokumentiert sein.", "priority": 1, "section": "4.6"},
|
|
{"id": "O.Priv_3", "title": "Betroffenenrechte", "description": "Auskunft, Loeschung, etc.", "requirement_text": "Technische Prozesse fuer Betroffenenrechte (Art. 15-21 DSGVO) muessen implementiert sein.", "priority": 1, "section": "4.6"},
|
|
{"id": "O.Priv_4", "title": "Loeschkonzept", "description": "Aufbewahrungsfristen", "requirement_text": "Ein dokumentiertes Loeschkonzept mit definierten Aufbewahrungsfristen muss umgesetzt sein.", "priority": 1, "section": "4.6"},
|
|
{"id": "O.Priv_5", "title": "Datenschutz durch Technik", "description": "Privacy by Design", "requirement_text": "Datenschutz muss bereits bei der Entwicklung beruecksichtigt werden (Art. 25 DSGVO).", "priority": 1, "section": "4.6"},
|
|
|
|
# Logging & Audit
|
|
{"id": "O.Log_1", "title": "Security Logging", "description": "Sicherheitsereignisse protokollieren", "requirement_text": "Sicherheitsrelevante Ereignisse (Login, Fehler, Zugriffsverletzungen) muessen protokolliert werden.", "priority": 1, "section": "4.7"},
|
|
{"id": "O.Log_2", "title": "Audit Trail", "description": "Nachvollziehbarkeit", "requirement_text": "Aenderungen an personenbezogenen Daten muessen nachvollziehbar protokolliert werden.", "priority": 1, "section": "4.7"},
|
|
{"id": "O.Log_3", "title": "Log-Integritaet", "description": "Logs vor Manipulation schuetzen", "requirement_text": "Logs muessen vor unbefugter Aenderung oder Loeschung geschuetzt sein.", "priority": 2, "section": "4.7"},
|
|
{"id": "O.Log_4", "title": "Keine PII in Logs", "description": "Keine personenbezogenen Daten loggen", "requirement_text": "Logs duerfen keine personenbezogenen Daten im Klartext enthalten.", "priority": 1, "section": "4.7"},
|
|
|
|
# Software-Entwicklung
|
|
{"id": "O.Dev_1", "title": "Secure SDLC", "description": "Sicherer Entwicklungsprozess", "requirement_text": "Ein dokumentierter sicherer Entwicklungsprozess (Secure SDLC) muss etabliert sein.", "priority": 1, "section": "4.8"},
|
|
{"id": "O.Dev_2", "title": "Code Review", "description": "Sicherheits-Review von Code", "requirement_text": "Sicherheitsrelevanter Code muss vor Release einem Review unterzogen werden.", "priority": 2, "section": "4.8"},
|
|
{"id": "O.Dev_3", "title": "Dependency Management", "description": "Abhaengigkeiten pruefen", "requirement_text": "Externe Abhaengigkeiten muessen auf bekannte Schwachstellen geprueft werden.", "priority": 1, "section": "4.8"},
|
|
{"id": "O.Dev_4", "title": "Penetration Testing", "description": "Regelmaessige Sicherheitstests", "requirement_text": "Regelmaessige Penetrationstests oder Schwachstellenscans muessen durchgefuehrt werden.", "priority": 2, "section": "4.8"},
|
|
|
|
# Betrieb
|
|
{"id": "O.Ops_1", "title": "Patch Management", "description": "Zeitnahes Patchen", "requirement_text": "Sicherheitspatches muessen zeitnah (kritisch: 24-72h) eingespielt werden.", "priority": 1, "section": "4.9"},
|
|
{"id": "O.Ops_2", "title": "Backup", "description": "Regelmaessige Datensicherung", "requirement_text": "Regelmaessige, getestete Backups muessen vorhanden sein.", "priority": 1, "section": "4.9"},
|
|
{"id": "O.Ops_3", "title": "Incident Response", "description": "Vorfallsmanagement", "requirement_text": "Ein dokumentierter Incident-Response-Prozess muss etabliert sein.", "priority": 1, "section": "4.9"},
|
|
{"id": "O.Ops_4", "title": "Monitoring", "description": "Systemueberwachung", "requirement_text": "Kritische Systeme und Dienste muessen kontinuierlich ueberwacht werden.", "priority": 2, "section": "4.9"},
|
|
|
|
# Dokumentation
|
|
{"id": "O.Doc_1", "title": "Technische Dokumentation", "description": "Systemarchitektur dokumentiert", "requirement_text": "Die Systemarchitektur und Datenflüsse muessen dokumentiert sein.", "priority": 2, "section": "4.10"},
|
|
{"id": "O.Doc_2", "title": "Verarbeitungsverzeichnis", "description": "Art. 30 DSGVO", "requirement_text": "Ein vollstaendiges Verzeichnis von Verarbeitungstaetigkeiten muss gefuehrt werden.", "priority": 1, "section": "4.10"},
|
|
{"id": "O.Doc_3", "title": "TOMs", "description": "Technisch-organisatorische Massnahmen", "requirement_text": "Technisch-organisatorische Massnahmen (Art. 32 DSGVO) muessen dokumentiert sein.", "priority": 1, "section": "4.10"},
|
|
]
|
|
|
|
elif code == "BSI-TR-03161-2":
|
|
# Teil 2: Web-Anwendungen
|
|
return [
|
|
# Session Management
|
|
{"id": "O.Sess_1", "title": "Session-Timeout", "description": "Automatische Sitzungsbeendigung", "requirement_text": "Sessions muessen nach Inaktivitaet automatisch beendet werden (max. 30 Min).", "priority": 1, "section": "5.1"},
|
|
{"id": "O.Sess_2", "title": "Session-ID Sicherheit", "description": "Sichere Session-IDs", "requirement_text": "Session-IDs muessen kryptographisch sicher generiert werden (min. 128 Bit Entropie).", "priority": 1, "section": "5.1"},
|
|
{"id": "O.Sess_3", "title": "Session-Regeneration", "description": "ID nach Login erneuern", "requirement_text": "Nach erfolgreicher Authentifizierung muss eine neue Session-ID generiert werden.", "priority": 1, "section": "5.1"},
|
|
{"id": "O.Sess_4", "title": "Secure Cookie Flags", "description": "HttpOnly, Secure, SameSite", "requirement_text": "Session-Cookies muessen mit Secure, HttpOnly und SameSite-Flags gesetzt werden.", "priority": 1, "section": "5.1"},
|
|
{"id": "O.Sess_5", "title": "Session-Binding", "description": "Session an Client binden", "requirement_text": "Sessions sollten an Client-Eigenschaften (User-Agent, IP) gebunden werden.", "priority": 2, "section": "5.1"},
|
|
{"id": "O.Sess_6", "title": "Logout-Funktionalitaet", "description": "Vollstaendiges Logout", "requirement_text": "Beim Logout muss die Session vollstaendig invalidiert werden.", "priority": 1, "section": "5.1"},
|
|
|
|
# Eingabevalidierung
|
|
{"id": "O.Input_1", "title": "Serverseitige Validierung", "description": "Alle Eingaben serverseitig pruefen", "requirement_text": "Alle Benutzereingaben muessen serverseitig validiert werden.", "priority": 1, "section": "5.2"},
|
|
{"id": "O.Input_2", "title": "Whitelist-Validierung", "description": "Erlaubte Zeichen definieren", "requirement_text": "Eingabevalidierung sollte auf Whitelist-Basis erfolgen.", "priority": 1, "section": "5.2"},
|
|
{"id": "O.Input_3", "title": "Encoding", "description": "Korrekte Zeichenkodierung", "requirement_text": "Einheitliche Zeichenkodierung (UTF-8) muss durchgesetzt werden.", "priority": 2, "section": "5.2"},
|
|
{"id": "O.Input_4", "title": "Datei-Upload Validierung", "description": "Uploads pruefen", "requirement_text": "Datei-Uploads muessen auf Typ, Groesse und Inhalt validiert werden.", "priority": 1, "section": "5.2"},
|
|
|
|
# Injection-Schutz
|
|
{"id": "O.SQL_1", "title": "SQL-Injection Schutz", "description": "Prepared Statements", "requirement_text": "SQL-Anfragen muessen parametrisiert sein (Prepared Statements).", "priority": 1, "section": "5.3"},
|
|
{"id": "O.SQL_2", "title": "ORM Nutzung", "description": "Abstraktionsschicht nutzen", "requirement_text": "Es sollte ein ORM oder Query Builder verwendet werden.", "priority": 2, "section": "5.3"},
|
|
{"id": "O.Cmd_1", "title": "Command Injection Schutz", "description": "Keine Shell-Befehle mit Eingaben", "requirement_text": "Benutzereingaben duerfen nicht in Shell-Befehlen verwendet werden.", "priority": 1, "section": "5.3"},
|
|
{"id": "O.LDAP_1", "title": "LDAP Injection Schutz", "description": "LDAP-Queries absichern", "requirement_text": "LDAP-Queries muessen gegen Injection geschuetzt sein.", "priority": 1, "section": "5.3"},
|
|
{"id": "O.XML_1", "title": "XML Injection Schutz", "description": "XXE verhindern", "requirement_text": "XML-Parser muessen gegen XXE-Angriffe konfiguriert sein.", "priority": 1, "section": "5.3"},
|
|
|
|
# XSS-Schutz
|
|
{"id": "O.XSS_1", "title": "Output Encoding", "description": "Kontextabhaengiges Escaping", "requirement_text": "Ausgaben muessen kontextabhaengig (HTML, JS, CSS, URL) escaped werden.", "priority": 1, "section": "5.4"},
|
|
{"id": "O.XSS_2", "title": "Content Security Policy", "description": "CSP-Header setzen", "requirement_text": "Ein restriktiver Content-Security-Policy-Header muss gesetzt sein.", "priority": 1, "section": "5.4"},
|
|
{"id": "O.XSS_3", "title": "DOM-basiertes XSS", "description": "DOM-Manipulation absichern", "requirement_text": "JavaScript-DOM-Manipulationen muessen sicher implementiert sein.", "priority": 1, "section": "5.4"},
|
|
{"id": "O.XSS_4", "title": "Template-Engine Escaping", "description": "Auto-Escaping aktivieren", "requirement_text": "Template-Engines muessen mit aktiviertem Auto-Escaping verwendet werden.", "priority": 1, "section": "5.4"},
|
|
|
|
# CSRF-Schutz
|
|
{"id": "O.CSRF_1", "title": "Anti-CSRF Token", "description": "Token bei State-Changes", "requirement_text": "Zustandsaendernde Anfragen muessen mit Anti-CSRF-Token geschuetzt sein.", "priority": 1, "section": "5.5"},
|
|
{"id": "O.CSRF_2", "title": "SameSite Cookie", "description": "SameSite-Attribut setzen", "requirement_text": "Cookies sollten das SameSite-Attribut (Strict oder Lax) haben.", "priority": 1, "section": "5.5"},
|
|
{"id": "O.CSRF_3", "title": "Referer-Pruefung", "description": "Origin validieren", "requirement_text": "Bei kritischen Aktionen sollte der Origin/Referer-Header geprueft werden.", "priority": 2, "section": "5.5"},
|
|
|
|
# Security Headers
|
|
{"id": "O.Head_1", "title": "X-Content-Type-Options", "description": "nosniff setzen", "requirement_text": "Der X-Content-Type-Options: nosniff Header muss gesetzt sein.", "priority": 1, "section": "5.6"},
|
|
{"id": "O.Head_2", "title": "X-Frame-Options", "description": "Clickjacking-Schutz", "requirement_text": "X-Frame-Options oder CSP frame-ancestors muss Clickjacking verhindern.", "priority": 1, "section": "5.6"},
|
|
{"id": "O.Head_3", "title": "X-XSS-Protection", "description": "Browser XSS-Filter", "requirement_text": "X-XSS-Protection sollte aktiviert sein (oder CSP nutzen).", "priority": 2, "section": "5.6"},
|
|
{"id": "O.Head_4", "title": "Referrer-Policy", "description": "Referrer einschraenken", "requirement_text": "Eine restriktive Referrer-Policy sollte gesetzt sein.", "priority": 2, "section": "5.6"},
|
|
{"id": "O.Head_5", "title": "Permissions-Policy", "description": "Browser-Features einschraenken", "requirement_text": "Nicht benoetigte Browser-APIs sollten per Permissions-Policy deaktiviert werden.", "priority": 3, "section": "5.6"},
|
|
|
|
# Fehlerbehandlung
|
|
{"id": "O.Err_1", "title": "Generische Fehlermeldungen", "description": "Keine technischen Details", "requirement_text": "Fehlermeldungen an Benutzer duerfen keine technischen Details enthalten.", "priority": 1, "section": "5.7"},
|
|
{"id": "O.Err_2", "title": "Custom Error Pages", "description": "Eigene Fehlerseiten", "requirement_text": "Standard-Fehlerseiten des Servers muessen durch eigene ersetzt werden.", "priority": 2, "section": "5.7"},
|
|
{"id": "O.Err_3", "title": "Exception Handling", "description": "Alle Exceptions abfangen", "requirement_text": "Unbehandelte Exceptions muessen abgefangen und geloggt werden.", "priority": 1, "section": "5.7"},
|
|
|
|
# API-Sicherheit
|
|
{"id": "O.API_1", "title": "API-Authentifizierung", "description": "API-Keys oder OAuth", "requirement_text": "APIs muessen authentifiziert werden (API-Keys, OAuth, JWT).", "priority": 1, "section": "5.8"},
|
|
{"id": "O.API_2", "title": "Rate Limiting", "description": "Anfragen begrenzen", "requirement_text": "APIs muessen Rate-Limiting implementieren.", "priority": 1, "section": "5.8"},
|
|
{"id": "O.API_3", "title": "Input-Validierung API", "description": "Request-Body validieren", "requirement_text": "API-Request-Bodies muessen gegen ein Schema validiert werden.", "priority": 1, "section": "5.8"},
|
|
{"id": "O.API_4", "title": "Versionierung", "description": "API-Versionen", "requirement_text": "APIs sollten versioniert sein um Breaking Changes zu vermeiden.", "priority": 3, "section": "5.8"},
|
|
|
|
# Client-Sicherheit
|
|
{"id": "O.JS_1", "title": "JavaScript Sicherheit", "description": "Sichere JS-Praktiken", "requirement_text": "JavaScript muss sicher implementiert sein (kein eval, innerHTML mit Vorsicht).", "priority": 1, "section": "5.9"},
|
|
{"id": "O.JS_2", "title": "Third-Party Scripts", "description": "Externe Scripts absichern", "requirement_text": "Third-Party Scripts muessen mit SRI oder CSP abgesichert werden.", "priority": 1, "section": "5.9"},
|
|
{"id": "O.Store_1", "title": "Lokale Speicherung", "description": "LocalStorage sicher nutzen", "requirement_text": "Sensible Daten duerfen nicht im LocalStorage/SessionStorage gespeichert werden.", "priority": 1, "section": "5.9"},
|
|
]
|
|
|
|
elif code == "BSI-TR-03161-3":
|
|
# Teil 3: Hintergrundsysteme (Backend)
|
|
return [
|
|
# Systemarchitektur
|
|
{"id": "O.Arch_1", "title": "Defense in Depth", "description": "Mehrschichtige Sicherheit", "requirement_text": "Eine mehrschichtige Sicherheitsarchitektur (Defense in Depth) muss implementiert sein.", "priority": 1, "section": "6.1"},
|
|
{"id": "O.Arch_2", "title": "Segmentierung", "description": "Netzwerksegmentierung", "requirement_text": "Das Netzwerk muss segmentiert sein (DMZ, interne Zonen).", "priority": 1, "section": "6.1"},
|
|
{"id": "O.Arch_3", "title": "Microservices Isolation", "description": "Services isolieren", "requirement_text": "Microservices sollten minimal gekoppelt und isoliert sein.", "priority": 2, "section": "6.1"},
|
|
{"id": "O.Arch_4", "title": "Zero Trust", "description": "Kein implizites Vertrauen", "requirement_text": "Interne Kommunikation sollte nach Zero-Trust-Prinzipien abgesichert sein.", "priority": 2, "section": "6.1"},
|
|
|
|
# Datenspeicherung
|
|
{"id": "O.DB_1", "title": "Datenbank-Sicherheit", "description": "DB abhaerten", "requirement_text": "Datenbanken muessen gehaertet sein (keine Default-Credentials, minimale Rechte).", "priority": 1, "section": "6.2"},
|
|
{"id": "O.DB_2", "title": "Verschluesselung in DB", "description": "Sensible Felder verschluesseln", "requirement_text": "Sensible Daten sollten in der Datenbank verschluesselt gespeichert werden.", "priority": 1, "section": "6.2"},
|
|
{"id": "O.DB_3", "title": "Backup-Verschluesselung", "description": "Backups verschluesseln", "requirement_text": "Datenbank-Backups muessen verschluesselt sein.", "priority": 1, "section": "6.2"},
|
|
{"id": "O.DB_4", "title": "Zugriffskontrolle DB", "description": "DB-Zugriffe beschraenken", "requirement_text": "Der Datenbankzugriff muss auf notwendige Dienste beschraenkt sein.", "priority": 1, "section": "6.2"},
|
|
{"id": "O.Store_2", "title": "Dateispeicher-Sicherheit", "description": "Uploads isolieren", "requirement_text": "Hochgeladene Dateien muessen isoliert und mit Malware-Scanning verarbeitet werden.", "priority": 1, "section": "6.2"},
|
|
|
|
# Container & Infrastruktur
|
|
{"id": "O.Cont_1", "title": "Container-Sicherheit", "description": "Images scannen", "requirement_text": "Container-Images muessen auf Schwachstellen gescannt werden.", "priority": 1, "section": "6.3"},
|
|
{"id": "O.Cont_2", "title": "Rootless Container", "description": "Nicht als Root laufen", "requirement_text": "Container sollten nicht als Root-User ausgefuehrt werden.", "priority": 1, "section": "6.3"},
|
|
{"id": "O.Cont_3", "title": "Image-Herkunft", "description": "Vertrauenswuerdige Images", "requirement_text": "Es duerfen nur Images aus vertrauenswuerdigen Quellen verwendet werden.", "priority": 1, "section": "6.3"},
|
|
{"id": "O.Cont_4", "title": "Read-Only Filesystem", "description": "Unveraenderliches Dateisystem", "requirement_text": "Container sollten mit Read-Only Root-Filesystem laufen wo moeglich.", "priority": 2, "section": "6.3"},
|
|
{"id": "O.Cont_5", "title": "Resource Limits", "description": "CPU/Memory begrenzen", "requirement_text": "Container muessen Resource-Limits (CPU, Memory) konfiguriert haben.", "priority": 2, "section": "6.3"},
|
|
|
|
# Secrets Management
|
|
{"id": "O.Sec_1", "title": "Secrets Management", "description": "Zentrale Secrets-Verwaltung", "requirement_text": "Sensible Konfiguration (Passwoerter, Keys) muss zentral und sicher verwaltet werden.", "priority": 1, "section": "6.4"},
|
|
{"id": "O.Sec_2", "title": "Keine Hardcoded Secrets", "description": "Secrets nicht im Code", "requirement_text": "Secrets duerfen nicht im Quellcode oder in Git-Repositories stehen.", "priority": 1, "section": "6.4"},
|
|
{"id": "O.Sec_3", "title": "Secret Rotation", "description": "Regelmaessige Rotation", "requirement_text": "Secrets und API-Keys sollten regelmaessig rotiert werden.", "priority": 2, "section": "6.4"},
|
|
{"id": "O.Sec_4", "title": "Vault Integration", "description": "Secrets-Vault nutzen", "requirement_text": "Ein Secrets-Management-System (HashiCorp Vault o.ae.) sollte verwendet werden.", "priority": 2, "section": "6.4"},
|
|
|
|
# Kommunikation
|
|
{"id": "O.Comm_1", "title": "Service-to-Service TLS", "description": "Interne Verschluesselung", "requirement_text": "Auch interne Service-Kommunikation sollte verschluesselt sein (mTLS).", "priority": 2, "section": "6.5"},
|
|
{"id": "O.Comm_2", "title": "Message Queue Sicherheit", "description": "Queue-Zugriff absichern", "requirement_text": "Message Queues muessen authentifiziert und autorisiert werden.", "priority": 1, "section": "6.5"},
|
|
{"id": "O.Comm_3", "title": "API Gateway", "description": "Zentraler Zugangspunkt", "requirement_text": "Ein API Gateway sollte als zentraler Zugangspunkt dienen.", "priority": 2, "section": "6.5"},
|
|
|
|
# Monitoring & Logging
|
|
{"id": "O.Mon_1", "title": "Zentrale Logs", "description": "Log-Aggregation", "requirement_text": "Logs aller Services muessen zentral aggregiert werden.", "priority": 1, "section": "6.6"},
|
|
{"id": "O.Mon_2", "title": "Security Monitoring", "description": "Anomalie-Erkennung", "requirement_text": "Sicherheitsrelevante Ereignisse muessen ueberwacht und alarmiert werden.", "priority": 1, "section": "6.6"},
|
|
{"id": "O.Mon_3", "title": "Metriken", "description": "Performance-Monitoring", "requirement_text": "System-Metriken (CPU, Memory, Latenz) sollten erfasst und ueberwacht werden.", "priority": 2, "section": "6.6"},
|
|
{"id": "O.Mon_4", "title": "Alerting", "description": "Alarmierung konfigurieren", "requirement_text": "Kritische Schwellwerte muessen definiert und alarmiert werden.", "priority": 1, "section": "6.6"},
|
|
|
|
# CI/CD Sicherheit
|
|
{"id": "O.CI_1", "title": "Pipeline-Sicherheit", "description": "CI/CD absichern", "requirement_text": "CI/CD-Pipelines muessen abgesichert sein (Secrets, Zugriffsrechte).", "priority": 1, "section": "6.7"},
|
|
{"id": "O.CI_2", "title": "SAST/DAST", "description": "Automatisierte Security-Tests", "requirement_text": "Statische und dynamische Sicherheitsanalysen sollten in die Pipeline integriert sein.", "priority": 2, "section": "6.7"},
|
|
{"id": "O.CI_3", "title": "Dependency Scanning", "description": "Abhaengigkeiten pruefen", "requirement_text": "Abhaengigkeiten muessen automatisiert auf Schwachstellen geprueft werden.", "priority": 1, "section": "6.7"},
|
|
{"id": "O.CI_4", "title": "SBOM", "description": "Software Bill of Materials", "requirement_text": "Ein SBOM (Software Bill of Materials) sollte generiert und gepflegt werden.", "priority": 2, "section": "6.7"},
|
|
|
|
# Disaster Recovery
|
|
{"id": "O.DR_1", "title": "Backup-Strategie", "description": "3-2-1 Backup-Regel", "requirement_text": "Backups sollten der 3-2-1-Regel folgen (3 Kopien, 2 Medien, 1 offsite).", "priority": 1, "section": "6.8"},
|
|
{"id": "O.DR_2", "title": "Recovery-Tests", "description": "Restore regelmaessig testen", "requirement_text": "Die Wiederherstellung aus Backups muss regelmaessig getestet werden.", "priority": 1, "section": "6.8"},
|
|
{"id": "O.DR_3", "title": "RTO/RPO", "description": "Recovery-Ziele definieren", "requirement_text": "Recovery Time Objective (RTO) und Recovery Point Objective (RPO) muessen definiert sein.", "priority": 2, "section": "6.8"},
|
|
]
|
|
|
|
return []
|
|
|
|
def get_known_sources(self) -> List[Dict[str, Any]]:
|
|
"""Get list of known regulation sources with metadata."""
|
|
sources = []
|
|
for code, info in self.KNOWN_SOURCES.items():
|
|
# Check database for existing data
|
|
regulation = self.reg_repo.get_by_code(code)
|
|
requirement_count = 0
|
|
if regulation:
|
|
requirement_count = self.db.query(RequirementDB).filter(
|
|
RequirementDB.regulation_id == regulation.id
|
|
).count()
|
|
|
|
sources.append({
|
|
"code": code,
|
|
"url": info["url"],
|
|
"source_type": info["type"].value,
|
|
"regulation_type": info["regulation_type"].value,
|
|
"has_data": regulation is not None,
|
|
"requirement_count": requirement_count,
|
|
})
|
|
|
|
return sources
|