Was Sie über OSCAL für den Import wissen müssen
OSCAL, die Open Security Controls Assessment Language, ist eine von NIST geführte Initiative für maschinenlesbare Formate in XML, JSON und YAML. Die Modelle sind in Schichten geordnet: Control Layer mit Katalog, Profil und Control Mapping, Implementation Layer mit Komponentendefinition und System Security Plan, Assessment Layer mit Prüfplan, Prüfergebnissen und Maßnahmenplan. Jede Schicht nutzt die Informationen der darunterliegenden, und dieselben Inhalte lassen sich ohne Verlust zwischen XML, JSON und YAML umwandeln (NIST, Projektseite und Seite „OSCAL Models“). Für den Import des Grundschutz++-Katalogs brauchen Sie davon wenig: das Katalogmodell, das Profil, aus dem der aufgelöste Katalog entsteht, und für den Altbestand das Mapping-Modell.
Die Bibliothek ordnet ihre Dateien entsprechend in Schichten: Im Control Layer liegen Kataloge, Profile, aufgelöste Kataloge und Mappings, im Implementation Layer Komponentendefinitionen; der Assessment Layer ist laut README für künftige Artefakte zu Prüfungen vorgesehen. Laut README können aufgelöste Kataloge „direkt in einer Institution verwendet werden“.
Für einen sauberen Import zählen vor allem die Kennungen. Jede Ebene hat eigene, und nicht alle bleiben zwischen zwei Builds gleich:
Welche Datei wofür dient, beschreibt die Seite Anwenderkatalog Grundschutz++; hier geht es um den technischen Umgang mit ihr.
| Kennung | Wo im JSON | Wert im Build 2026-10-29 | Verhalten zwischen Builds |
|---|---|---|---|
| Dokumentkennung | catalog.metadata.document-ids[0].identifier | ebe77c16-3ddc-42ce-8d53-eff5b6e23334 | im Build vom 22.10.2026 gleich; das BSI-Schema beschreibt sie als versionsübergreifend stabil |
| Katalog-UUID | catalog.uuid | d3fb98e5-14c6-4522-975c-a9a605e46a37 | neu je Build (22.10.2026: 81573937-…) |
| Version | catalog.metadata.version | Zeitstempel 2026-10-29T08:03:12.736989+00:00 | neu je Build; keine fortlaufende Versionsnummer |
| OSCAL-Version | catalog.metadata.oscal-version | 1.1.3 | das Mapping IT-Grundschutz 2023 nutzt dagegen 1.2.1 |
| Kennung der Anforderung | controls[].id | z. B. BER.3.11 | kann umgehängt werden (siehe Mapping unten) |
| UUID der Anforderung | controls[].props[name=alt-identifier] | genau eine je Anforderung, 1.000 verschiedene | bleibt gleich; der richtige Schlüssel für Abgleiche |
| Titel | controls[].title | z. B. „Verfahren und Regelungen“ | ändert sich und ist nicht eindeutig: 14 Titel teilen sich 89 Anforderungen |
Schritt 1: den Katalog reproduzierbar beziehen
Laden Sie die Datei immer von einem festen Commit und notieren Sie die Prüfsumme; der Stand main ändert sich mit jeder Veröffentlichung. Nur so lässt sich später zeigen, auf welchen Text sich ein Anforderungspaket, eine Zählung oder ein Prüfergebnis bezieht.
C=c3f37859fdf302394de39e89252eb3e72a45953c
P='control_layer/Grundschutz++/Grundschutz++-resolved_catalog.json'
curl -fsSL -o katalog.json "https://raw.githubusercontent.com/BSI-Bund/Stand-der-Technik-Bibliothek/$C/$P"
sha256sum katalog.json
# 592410c513691c18631402db3982dda6a4530dd6f2960868a6999017d311fa28 katalog.json
Drei Eigenheiten der Bibliothek sollten Sie kennen:
- Build-Datum und Commit-Datum liegen auseinander. Der Build vom 29.10.2026 (Feld
last-modified) kam am 30.10.2026 ins Repository. Das BSI veröffentlicht die Dateien über Pull Requests mit dem Titel „chore: publish rolling artifacts“. Notieren Sie beides. - Pfade haben sich geändert. Mit dem Commit „Migrate public library to layer-based structure“ vom 27.07.2026 bekam die Bibliothek ihre heutige Ordnerstruktur. Wer ältere Stände abruft, braucht die damaligen Pfade.
- Die Datei ist groß, aber nicht riesig. Im Stand c3f37859 hat der aufgelöste Katalog 5.401.489 Byte. Das reicht für jedes Skript, ist aber zu viel, um Änderungen von Hand zu vergleichen.
Schritt 2: Schema und Inhalt validieren
Validieren heißt hier zweierlei: Passt die Datei zum Schema, und ist ihr Inhalt plausibel? Für das Schema veröffentlicht das BSI im Repository die Datei documentation/datamodel/oscal_satzschablone_schema.json, beschrieben als JSON-Schema für BSI-OSCAL-Kataloge „based on OSCAL 1.1.3 with BSI-specific extensions“. Es prüft die Struktur und lässt für Eigenschaften nur die bekannten Namen zu, darunter die BSI-eigenen wie modal_verb, sec_level und threats. Ihre Werte prüft es nicht, und es verlangt nicht, dass eine Anforderung diese Felder hat; dafür sind die inhaltlichen Prüfungen unten da.
Unser Test am 01.11.2026: Der aufgelöste Katalog aus Commit c3f37859 besteht die Prüfung gegen dieses Schema ohne Fehler (Python-Bibliothek jsonschema 4.10.3, Validator für JSON Schema Draft 7). Ein Fallstrick: Das Feld $id im Schema verweist auf den Pfad „Dokumentation/datamodel/…“, unter dem GitHub am 01.11.2026 nichts auslieferte (HTTP 404); die Datei liegt unter „documentation/datamodel/…“. Laden Sie das Schema deshalb wie den Katalog aus demselben Commit und nicht über die $id. Zusätzlich lässt sich gegen das allgemeine OSCAL-Schema der Version prüfen, die im Feld oscal-version steht. Die NIST-Seite „OSCAL Models“ verlinkt für jedes Modell die XML- und JSON-Schemata; für den Katalog gilt das Schema des Katalogmodells, für das Mapping das des Control-Mapping-Modells.
Auf das Schema folgen inhaltliche Prüfungen. Das Beispiel zählt die Anforderungen rekursiv über alle Ebenen und prüft, dass jede genau eine eindeutige UUID hat:
import json
kat = json.load(open('katalog.json', encoding='utf-8'))['catalog']
def anforderungen(knoten):
for gruppe in knoten.get('groups', []):
yield from anforderungen(gruppe)
for c in knoten.get('controls', []):
yield c
yield from anforderungen(c)
alle = list(anforderungen(kat))
uuid_zu_id = {}
for c in alle:
uuids = [p['value'] for p in c.get('props', []) if p['name'] == 'alt-identifier']
assert len(uuids) == 1, c['id']
uuid_zu_id[uuids[0]] = c['id']
print(len(alle), len(uuid_zu_id)) # 1000 1000
Diese Prüfungen führen wir bei jedem Import aus. Die rechte Spalte zeigt das Ergebnis für Commit c3f37859.
| Prüfung | Warum | Ergebnis c3f37859 |
|---|---|---|
| Prüfsumme gegen Manifest | Datei unverändert seit dem Bezug | gleich |
| Schema oscal_satzschablone_schema.json | Struktur und zulässige Feldnamen; Werte prüft das Schema nicht | 0 Fehler |
| Zahl der Anforderungen, rekursiv | Werkzeuge, die nur zwei Ebenen lesen, verlieren Anforderungen | 1.000 (zwei Ebenen: 979) |
| genau eine UUID je Anforderung, alle verschieden | Grundlage für Änderungsbericht und Mapping | 1.000 von 1.000 |
| Modalverb im Anforderungstext und im Feld modal_verb gleich | Feld und Satz dürfen sich nicht widersprechen | erfüllt |
| Gefährdungskennungen im Feld threats kommen in basethreats.csv vor | keine unbekannten Kennungen | erfüllt |
| Sicherheitsniveau „erhöht“ nur mit KANN (300-1, Kap. 3.4.2) | bekannte Abweichungen zwischen Katalog und Standard sichtbar machen | drei Ausnahmen: BES.1.4, DET.4.12.1, REA.2.5 |
Schritt 3: ein Versionsmanifest anlegen
Das Manifest ist eine kleine Datei, die neben jedem Import liegt. Es beantwortet später die Fragen, die Prüfende und Sie selbst stellen werden: Welcher Stand? Woher? Geprüft womit? Mit welchem Ergebnis? Die Werte im Beispiel sind die echten Werte vom 01.11.2026; die Gliederung ist unser Vorschlag.
{
"quelle": "https://github.com/BSI-Bund/Stand-der-Technik-Bibliothek",
"commit": "c3f37859fdf302394de39e89252eb3e72a45953c",
"commit_datum": "2026-10-30T10:01:58Z",
"abgerufen": "2026-11-01",
"dateien": [
{
"pfad": "control_layer/Grundschutz++/Grundschutz++-resolved_catalog.json",
"sha256": "592410c513691c18631402db3982dda6a4530dd6f2960868a6999017d311fa28",
"titel": "Anwenderkatalog Grundschutz++",
"last_modified": "2026-10-29T08:03:17.266980922Z",
"version": "2026-10-29T08:03:12.736989+00:00",
"oscal_version": "1.1.3",
"document_id": "ebe77c16-3ddc-42ce-8d53-eff5b6e23334",
"anforderungen": 1000
},
{
"pfad": "control_layer/Mappings/IT-GS2023-zu-GSpp/ITGS-to-GS++-mapping_collection.json",
"sha256": "df7ea11261ace956a3ebb440f60928851a4815f5545775ac9b24e4d3d22f267f",
"last_modified": "2026-07-21T07:57:12Z",
"oscal_version": "1.2.1",
"status": "draft",
"zuordnungen": 1185
}
],
"schema": {
"pfad": "documentation/datamodel/oscal_satzschablone_schema.json",
"sha256": "11f01d7f1525a5a16ec7f3f065a4ccbe045514c75b76ffe975c9a32061f4b1af",
"ergebnis": "0 Fehler (jsonschema 4.10.3, Draft 7)"
},
"lizenz": "CC BY-SA 4.0"
}
Achten Sie auf drei Felder, die der Katalog selbst nicht liefert: den Status des Mappings (Entwurf), die Lizenz und das Werkzeug, mit dem validiert wurde. Gehören Komponentendefinitionen aus dem Implementation Layer zu Ihrem Import, nehmen Sie sie mit Pfad und Prüfsumme auf. Das Manifest ist zugleich ein guter Nachweis für die Validierung der Anforderungen, die 300-1 in Kapitel 5.5 vorsieht: Dort stehen Anpassungen an den Anforderungen der Stand-der-Technik-Bibliothek ausdrücklich unter den Aspekten, die die Validierung umfassen sollte.

Schritt 4: der Änderungsbericht zwischen zwei Builds
Ein neuer Build ist erst dann übernommen, wenn Sie wissen, was sich geändert hat. Den Bericht erzeugen Sie, indem Sie beide Builds über die UUID der Anforderungen nebeneinanderlegen und je UUID Kennung, Titel, Anforderungstext, Parameter, Erläuterung sowie die Metadaten der Anforderung (etwa Sicherheitsniveau und Gefährdungen) und des Anforderungssatzes (etwa Modalverb und Zielobjektkategorien) vergleichen. Über die Kennung zu vergleichen reicht nicht, weil das BSI Kennungen umhängt; über den Titel zu vergleichen geht gar nicht, weil Titel mehrfach vorkommen.
def stand(datei):
kat = json.load(open(datei, encoding='utf-8'))['catalog']
erg = {}
for c in anforderungen(kat):
u = next(p['value'] for p in c['props'] if p['name'] == 'alt-identifier')
satz = next(t for t in c['parts'] if t['name'] == 'statement')
erg[u] = {'id': c['id'], 'titel': c['title'], 'text': satz['prose'],
'params': json.dumps(c.get('params', []), sort_keys=True),
'erlaeuterung': next((t.get('prose') for t in c['parts'] if t['name'] == 'guidance'), None),
'props': json.dumps(c.get('props', []), sort_keys=True),
'satz_props': json.dumps(satz.get('props', []), sort_keys=True)}
return erg
alt, neu = stand('katalog-2026-10-22.json'), stand('katalog-2026-10-29.json')
print('neu:', [neu[u]['id'] for u in neu.keys() - alt.keys()])
print('entfallen:', [alt[u]['id'] for u in alt.keys() - neu.keys()])
for u in alt.keys() & neu.keys():
for feld in ('id', 'titel', 'text', 'params', 'erlaeuterung', 'props', 'satz_props'):
if alt[u][feld] != neu[u][feld]:
print(neu[u]['id'], feld, alt[u][feld], '|', neu[u][feld])
Ergebnis für den Build vom 22.10.2026 (Commit 9fb19de7 vom 23.10.2026) gegen den Build vom 29.10.2026 (Commit c3f37859): 1.000 Anforderungen in beiden, keine neu, keine entfallen, keine Kennung geändert. Geändert haben sich sechs Titel, ein Anforderungstext samt Parameter und Satz-Metadaten und zwei Erläuterungen. Der Bericht mit unserer fachlichen Einordnung:
| Anforderung | Änderung | vorher | nachher | Einordnung |
|---|---|---|---|---|
| KONF.2.3 | Titel | Änderung von Default-Zugangsdaten | Default-Zugangsdaten in IT-Systemen | vorher gleicher Titel wie KONF.10.3; Text unverändert, keine fachliche Folge |
| KONF.10.3 | Titel | Änderung von Default-Zugangsdaten | Default-Zugangsdaten in Anwendungen | wie KONF.2.3 |
| KONF.2.5 | Titel | Überprüfung der Konfiguration | Überprüfung der Systemkonfiguration | Präzisierung, keine fachliche Folge |
| KONF.2.6 | Titel | Automatische Konfigurationsverwaltung | Mobile Device Management | Der unveränderte Text verlangt, die Verwaltung durch ein MDM zu aktivieren; der neue Titel passt dazu. Prüfen, ob Maßnahme und Nachweis bisher nach dem alten Titel ausgewählt wurden |
| KONF.9.2 | Titel | Begrenzung der Rechenleistung | Begrenzung der Hostleistung | vorher gleicher Titel wie KONF.15.2 |
| KONF.15.3 | Titel | Denial of Service | Schutz gegen Denial of Service | Präzisierung |
| KONF.15.2 | Anforderungstext, Parameter und Satz-Metadaten | „… KANN die Rechenleistung einschränken.“ | „… KANN die Rechenleistung pro {{ insert: param, konf.15.2-prm1 }} einschränken.“, neuer Parameter mit der Bezeichnung „Zugangskonto oder Mandant“, neues Feld result_specification „pro {{Zugangskonto oder Mandant}}“ | Fachliche Änderung: Wer KONF.15.2 im Paket hat, muss den neuen Parameter konkretisieren (300-1, Kap. 3.5) |
| BES.7.4.7, BES.7.4.12 | Erläuterung | je ein kurzer Satz | ausführliche Erläuterung | Erläuterung lesen; Anforderungstext unverändert |
Was in den Bericht gehört, bestimmt die Folge für Ihr Paket: Neue oder entfallene UUIDs und geänderte Zielobjektkategorien oder Sicherheitsniveaus ändern das Anforderungspaket, weil Zielobjektkategorie und Sicherheitsniveau bestimmen, welche Anforderungen hineingehören (300-1, Kap. 3.4.1 und 3.4.2). Ein geändertes Modalverb ändert, wie eine nicht erfüllte Anforderung zu behandeln ist (Kap. 4.1.2): KANN ist optional, bei SOLLTE ist eine begründete temporäre oder eine dauerhafte Nichterfüllung mit Risikobetrachtung möglich, bei MUSS keine Ausnahme; prüfen Sie dann den Status neu. Geänderte Texte, Parameter und Erläuterungen verlangen eine fachliche Prüfung des Status, bei Titeländerungen mit unverändertem Text genügt eine Anpassung der Anzeige. Halten Sie im Bericht fest, wer die Einordnung vorgenommen hat und wann.
Das Mapping 2023 zu Grundschutz++ über die UUID verknüpfen
Am deutlichsten zeigt sich der Wert der UUIDs beim Mapping vom IT-Grundschutz-Kompendium 2023 auf Grundschutz++. Die Datei hat den Status „draft“, also Entwurf; ihr Feld last-modified nennt den 21.07.2026, das Feld generated-at den 09.06.2026 als Exportdatum. Ihre 1.185 Zielkennungen passen vollständig zu den Katalogständen vom 05.03. bis 20.04.2026. Danach hat das BSI in fünf Stufen, mit den Builds vom 28.05., 24.06., 03.07., 16.07. und 26.07.2026, Kennungen umgehängt; die UUIDs blieben gleich (eigene Auflösung gegen die Katalogstände im Repository).
Jede Zuordnung trägt neben der Zielkennung im Feld id-ref eine UUID in der Eigenschaft oscal_uuid. Im Katalog steht dieselbe UUID als alt-identifier. Gegen den Build vom 29.10.2026 haben wir nachgezählt:
| Ergebnis des Abgleichs | Zuordnungen | Was zu tun ist |
|---|---|---|
| Kennung und UUID passen zusammen | 1.039 | fachlich prüfen wie jede Entwurfszuordnung |
| Kennung gibt es, sie gehört aber zu einer anderen UUID | 90 | über die UUID die heutige Kennung ermitteln; die Kennung allein führt auf eine falsche Anforderung |
| Kennung gibt es nicht mehr, UUID ist vorhanden | 40 | über die UUID die heutige Kennung ermitteln |
| weder Kennung noch UUID im Build | 16 | alle mit Ziel VRB.1.2; Zuordnung offen, beim BSI-Stand nachprüfen |
Ein Beispiel für die zweite Zeile: Die Zuordnung von APP.3.1.A1-UA.4 zeigt auf die Kennung BER.3.10. Die mitgelieferte UUID gehört im Build vom 29.10.2026 aber zu BER.3.11; unter BER.3.10 steht heute eine andere Anforderung. Die Auflösung ist eine Zeile, wenn Sie das Verzeichnis uuid_zu_id aus Schritt 2 haben:
ziel_heute = uuid_zu_id.get(ziel_uuid) # None, wenn die UUID im Build fehlt
Die Zuordnungen selbst bleiben Entwurf. Wie Sie sie fachlich prüfen, zeigt die Seite Mapping IT-Grundschutz 2023.
Was ein sauberer Import nicht ersetzt
Ein valider, dokumentierter Import beweist, dass Sie die Datei richtig übernommen haben. Ob ihr Inhalt zum Standard passt, beweist er nicht. Im Build vom 29.10.2026 weichen Katalog und BSI-Standard 300-1 an drei Stellen voneinander ab, beim Umsetzungsstatus, bei den Anforderungen ohne Zielobjektkategorie und bei den drei SOLLTE-Anforderungen mit Niveau „erhöht“; die Einzelheiten stehen auf der Seite Anwenderkatalog Grundschutz++.
Die Bibliothek steht unter der Lizenz CC BY-SA 4.0. Sie verlangt unter anderem Namensnennung und die Weitergabe von Bearbeitungen unter gleichen Bedingungen; was das für Ihr Werkzeug oder Ihre Exporte bedeutet, gehört zur Prüfung durch Ihre Rechtsabteilung. Wer technische Prüfergebnisse aus dem eigenen Betrieb als Nachweis an Anforderungen hängen will, findet das Vorgehen auf der Seite Automatisierte Nachweise.
Weiterlesen: Anwenderkatalog Grundschutz++, Automatisierte Nachweise. Blackfort Technology unterstützt beim Abgleich eines Altbestands mit dem aktuellen Katalogstand im Rahmen der Readiness-Analyse und der Migration; die Leistungen stehen auf der Seite Beratung.
Rechtehinweis: Zitate aus BSI-Standard 300-1 stammen von der BSI-Seite zu Grundschutz++ und sind © Bundesamt für Sicherheit in der Informationstechnik; sie stehen nicht unter CC BY-SA 4.0. Die Codebeispiele sind eigene Beispiele von Blackfort Technology.
