Building an Accounting API That Survives an Audit
A practical guide to the security and audit controls a financial API needs before Dutch businesses trust it with their books.
Eine Buchhaltungs-API, die bei einem Schreibvorgang für eine Zahlung den Status 200 OK zurückgibt, hat damit fast noch nichts Konkretes ausgesagt. Sie hat weder bestätigt, dass der Buchungssatz im Hauptbuch (ledger) erfasst wurde, noch dass der Ausführende die Berechtigung dazu hatte, dass der Betrag die Validierung bestanden hat oder dass überhaupt jemand mit entsprechender Befugnis diesen freigegeben hat. Für Unternehmen in den Niederlanden, wo die Steuerbehörden verlangen, dass Geschäftsunterlagen nachvollziehbar sind und sieben Jahre lang aufbewahrt werden, entsteht genau in dieser Lücke zwischen „Die Anfrage war erfolgreich“ und „Die Bücher stimmen“ das Risiko, dass eine Prüfung fehlschlägt.
Prüfungssicherheit (audit-ready) ist ein operatives Designziel und kein Zertifikat. Sie bedeutet, dass die API eine vollständige Kette bewahrt: vom authentifizierten Akteur über die autorisierte Aktion, die validierte Zustandsänderung, die Freigabe und das Ergebnis im Hauptbuch bis hin zu manipulationssessenden Nachweisen (tamper-evident evidence). Im Folgenden geht es darum, diese Kette gezielt aufzubauen, anstatt einfach vorauszusetzen, dass Authentifizierung und TLS ausreichen.
Was eine Buchhaltungs-API „prüfungssicher“ macht
Ein Prüfer, der eine Transaktion rekonstruiert, muss eine bestimmte Abfolge von Fragen beantworten können: Wer hat sie ausgelöst? Durfte diese Person das? Hat die Änderung die buchhalterische Validierung bestanden? Wer hat sie genehmigt? Was wurde im Hauptbuch aufgezeichnet? Kann dieser Datensatz nachträglich ohne Spuren verändert werden?
Wenn Ihre API nicht alle sechs Fragen aus ihren eigenen Protokollen und ihrem Datenmodell heraus beantworten kann, ist sie nicht prüfungssicher – ganz gleich, wie sauber der Code aussieht. Die meisten APIs lösen die erste Frage gut und den Rest eher schlecht.
Die Kontrollen, die diese Lücke schließen, lassen sich in mehrere Gruppen unterteilen: expliziter Buchungsstatus (accounting state), mehrschichtige Autorisierung, bereichsbezogene Authentifizierung (scoped authentication), idempotente Schreibvorgänge, serverseitige Validierung, Funktionstrennung (segregation of duties) und manipulationssichere Protokollierung (tamper-evident logging). Sie verstärken sich gegenseitig. Eine schwache Autorisierung untergräbt ein starkes Prüfprotokoll, da man sich nicht mehr darauf verlassen kann, dass der protokollierte Akteur überhaupt berechtigt war, die Handlung auszuführen.
Buchungszustände modellieren, bevor Sie Endpunkte modellieren
Der häufigste Designfehler besteht darin, jeden Finanzdatensatz als frei bearbeitbares Objekt mit den Methoden create, read, update und delete zu behandeln. Die Buchhaltung funktioniert jedoch nicht so, und ein Prüfer wird sofort bemerken, wenn ein verbuchter Buchungssatz unbemerkt überschrieben werden kann.
Jede finanzrelevante Ressource benötigt eine explizite Zustandsmaschine (state machine). Ein Buchungssatz oder eine Zahlung durchläuft typischerweise folgende Phasen:
draft → submitted → approved → posted → settled
Korrekturen machen diesen Weg nicht rückgängig. Ein fehlerhafter, bereits verbuchter Datensatz erhält eine verknüpfte Stornierung oder eine ausgleichende Berichtigung. Das Original bleibt unverändert.
Ein praktikabler Regelsatz:
- Entwürfe (Drafts) können von autorisierten Benutzern bearbeitet werden.
- Eingereichte Datensätze können nur von Personen mit entsprechenden Rollen bearbeitet oder in den Entwurfsstatus zurückversetzt werden.
- Genehmigte Datensätze erfordern eine kontrollierte Änderung und eine erneute Freigabe.
- Verbuchte Datensätze können weder überschrieben noch gelöscht, sondern nur storniert oder berichtigt werden.
- Änderungen in geschlossenen Perioden erfordern eine erhöhte Autorisierung, eine Begründung sowie ein Audit-Ereignis.
Der Versuch eines unzulässigen Übergangs – etwa das Bearbeiten eines verbuchten Eintrags – sollte einen stabilen Fehler zurückgeben und dennoch einen Audit-Eintrag schreiben. Der fehlgeschlagene Versuch ist schließlich ebenfalls ein Beweis.
Hier zeigt sich der Wert eines unveränderlichen doppelten Buchführungssystems (immutable double-entry ledger). Das Hauptbuch von Nordlet ist so konzipiert, dass jede Transaktion als ausgeglichener, permanenter Eintrag landet. Die Saldenwahrung wird zum Commit-Zeitpunkt durch einen Datenbank-Trigger erzwungen, und Korrekturen erfolgen über Stornierungen anstelle von Überschreibungen. Diese Einschränkung fühlt sich während der Entwicklung restriktiv an, verwandelt sich aber bei einer Prüfung genau in das Vertrauen, das Ihr Steuerberater benötigt.
Jede Anfrage autorisieren, nicht nur authentifizieren
Die Authentifizierung beweist, wer eine Anfrage stellt. Sie besagt jedoch rein gar nichts darüber, ob dieser Aufrufer eine bestimmte Rechnung, ein Journal oder eine juristische Person berühren darf. Das OWASP API Security Project führt eine fehlerhafte Autorisierung auf Objektebene (broken object-level authorization) ganz oben in seiner Risikoliste auf – genau deshalb, weil APIs Objektkennungen offenlegen, die bei fehlenden Prüfungen mandantenübergreifende Zugriffe erleichtern.
Jede Anfrage an eine Finanz-API sollte anhand einer Kombination von Faktoren autorisiert werden, nicht nur anhand eines Tokens:
- authentifizierter Akteur
- Client-Anwendung oder Dienstkonto (service account)
- Mandant (tenant)
- juristische Person
- Ressourcen-ID
- angeforderter Vorgang
- aktueller Ressourcenstatus
- Betrag oder Transaktionsschwellenwert
Zwei praktische Regeln sind wichtiger als alle anderen. Erstens: Leiten Sie den Mandanten- und Benutzerkontext aus der authentifizierten Identität ab und weisen Sie vom Client übermittelte Mandanten- oder Rollenansprüche (claims) zurück, die im Widerspruch dazu stehen. Ein Aufrufer sollte niemals selbst behaupten können, für welches Unternehmen er gerade handelt. Zweitens: Nutzen Sie das Prinzip der Verweigerung im Standard (deny-by-default). Wenn keine Richtlinie eine Aktion ausdrücklich erlaubt, schlägt sie fehl.
Testen Sie beide Richtungen: Den horizontalen Zugriff, bei dem ein Mandant auf die Daten eines anderen Mandanten zugreift, sowie den vertikalen Zugriff, bei dem ein normaler Benutzer Funktionen zur Freigabe, Verbuchung oder zum Export erreicht. Beide Szenarien kommen häufig vor und sind bei Buchhaltungsdaten katastrophal.
Das Rollenmodell von Nordlet – mit Eigentümer-, Admin-, Buchhalter-, Manager-, Entwickler- und Betrachterrollen über mehrere Unternehmen hinweg unter einem Konto – dient genau dem Zweck, diese Trennung erzwingbar statt nur wünschenswert zu machen. Eine Entwicklerrolle, die Rechnungsentwürfe erstellen kann, darf keine Zahlungen freigeben.
Tokens auf geschäftliche Funktionen statt auf CRUD-Verben beschränken
Verwenden Sie für delegierte Zugriffe die aktuellen Sicherheitsrichtlinien für OAuth 2.0 anstelle von wiederverwendbaren Passwörtern oder breit gefassten, statischen API-Schlüsseln. RFC 9700 stellt die aktuelle Best Practice dar und definiert klare Anforderungen für Clients und Autorisierungsserver: validierte Umleitungs-URIs (redirect URIs), PKCE wo anwendbar, Aussteller- und Zielgruppenprüfungen (issuer and audience checks), kurze Lebensdauern von Access-Tokens sowie Refresh-Token-Rotation mit Widerruf.
Die Festlegung von Scopes (Berechtigungen) zeigt, wie stark die Architektur auf die Buchhaltung ausgerichtet ist. Generische Scopes wie read und write sind für die Funktionstrennung nahezu wertlos. Scopes sollten sich an geschäftlichen Funktionen orientieren:
journal:createundjournal:approvesind separate Scopes.- Das Erstellen einer Zahlungsanweisung gewährt noch lange keine Berechtigung zu deren Freigabe.
- Die Exportberechtigung unterscheidet sich von der Leseberechtigung, da Massenexporte einen Pfad für Datenabfluss darstellen.
Seien Sie präzise, wo sich ein bestimmtes Produkt auf dieser Skala bewegt. Die API-Schlüssel von Nordlet verfügen über modulspezifische Scopes wie sales:read und sales:write, die bei jeder Aktion überprüft werden. Dies trennt Module und Lese- von Schreibzugriffen, jedoch noch nicht das Erstellen vom Freigeben. Wenn Sie diese feinere Unterteilung benötigen, setzen Sie diese vor dem API-Aufruf in Ihrem eigenen Dienst durch.
Bei Vorgängen mit hohem Wert lohnt es sich zu prüfen, ob das FAPI 2.0 Security Profile anwendbar ist. Es wurde für APIs entwickelt, die sensible Finanzdaten schützen, und bietet stärkere Garantien als das OAuth-Basisprofil. Die meisten KMU-Buchhaltungsintegrationen benötigen das vollständige Profil zwar nicht, aber Zahlungsfreigaben und Bankverbindungsabläufe sind die Bereiche, in denen man es in Betracht ziehen sollte.
Die passwortlose Anmeldung von Nordlet über einmalige E-Mail-Links beseitigt das Problem wiederverwendbarer Passwörter für menschliche Benutzer. Damit gibt es eine Anmeldeinformation weniger, die rotieren, durchsickern oder für Phishing missbraucht werden kann.
Finanzbezogene Schreibvorgänge idempotent machen
Netzwerke fallen mitten in einer Anfrage aus. Ein Client sendet eine Zahlungsanweisung, die Verbindung bricht ab, bevor die Antwort eintrifft, und der Client versucht es erneut. Ohne Schutz haben Sie nun zwei Zahlungen vorliegen.
Idempotenzschlüssel lösen dieses Problem. Der Client sendet bei jedem Schreibvorgang einen eindeutigen Schlüssel; der Server speichert den Schlüssel zusammen mit seinem Ergebnis. Ein neuerlicher Versuch mit demselben Schlüssel gibt das ursprüngliche Ergebnis zurück, anstatt einen zweiten Eintrag zu erstellen. Nordlet akzeptiert bei jedem ändernden Aufruf einen Idempotency-Key-Header, spielt bei einem Wiederholungsversuch mit derselben Nutzlast (payload) die gespeicherte Antwort aus und lehnt denselben Schlüssel bei veränderter Nutzlast ab. Jede Buchhaltungs-API, die dieses Feature auslässt, erzeugt früher oder später doppelte Hauptbucheinträge, die mühsam von Hand entwirrt werden müssen.
Kombinieren Sie dies mit serverseitiger Validierung. Vertrauen Sie niemals dem Client, wenn es darum geht zu prüfen, ob Soll und Haben übereinstimmen, ob ein Steuersatz für das Land und den Zeitraum gültig ist oder ob ein Konto überhaupt existiert. Die Validierung läuft auf dem Server, und zwar vor dem Zustandsübergang. Ein abgelehnter Schreibvorgang erzeugt einen stabilen Fehler und einen Audit-Eintrag.
Manipulationssichere Prüfprotokolle und niederländische Aufbewahrungsfristen
Das Prüfprotokoll (audit log) bildet die Beweisschicht und unterliegt anderen Anforderungen als normale Geschäftsdaten. Es sollte die Autorisierungsentscheidung, die Richtlinienversion, den Akteur, das Objekt, den Vorgang, den vorherigen sowie den neuen Status und einen Begründungscode (reason code) aufzeichnen – ohne jemals Geheimnisse oder vollständige Zahlungsdaten zu protokollieren.
Die entscheidende Eigenschaft ist die Manipulationssicherheit (tamper-evidence). Wenn ein Administrator Audit-Einträge heimlich bearbeiten oder löschen kann, beweist das Protokoll gar nichts. Speicher, die nur das Anhängen erlauben (append-only), kryptografische Verkettungen oder einmalig beschreibbare Speicher (write-once) adressieren genau diesen Umstand. Der Kernpunkt ist, dass eine Modifikation erkennbar sein muss.
Die Aufbewahrung erfordert eine eigene Richtlinie, die von der Löschung von Geschäftsdaten getrennt ist. In den Niederlanden beträgt die allgemeine Aufbewahrungsfrist für administrative Aufzeichnungen sieben Jahre und für Aufzeichnungen im Zusammenhang mit unbeweglichem Vermögen zehn Jahre. Ihre normalen Datenlösch- und DSGVO-Lösch-Workflows dürfen niemals in der Lage sein, Datensätze oder Audit-Beweise zu vernichten, die noch unter eine gesetzliche Aufbewahrungsfrist fallen. Definieren Sie Regeln für gesetzliche Sperren (legal hold), die Archivierung und die Löschung von Audit-Nachweisen unabhängig voneinander und ordnen Sie diese den Jurisdiktionen zu, in denen Sie tätig sind.
Die Periodensperre (period locking) unterstützt dies auf der buchhalterischen Ebene. Sobald ein Monat abgeschlossen ist, können darin enthaltene Einträge nicht mehr ohne erhöhte Autorisierung und eine protokollierte Begründung geändert werden. Nordlet erzwingt die Periodensperre, sodass geschlossene Monate auch geschlossen bleiben. Jede Buchung, deren Datum in eine gesperrte Periode fällt, wird selbst über die API abgewiesen. Genau dies ist einer der ersten Punkte, die ein niederländischer Prüfer kontrolliert.
Die Ränder absichern: Webhooks, Exporte und Integrationen
Die Kern-API ist im System meist der am besten verteidigte Bereich. Die Ränder weisen jedoch Lecks auf.
Webhooks bergen das Risiko gefälschter Anfragen. Ein Ereignis wie sale_invoice.paid sollte signiert sein, damit der Empfänger überprüfen kann, ob es tatsächlich von Ihnen stammt. Empfänger sollten die Zustellung als mindestens einmal (at-least-once) behandeln und die Ereignis-ID zur Deduplizierung nutzen. Nordlet signiert jede Webhook-Zustellung mit einer HMAC-Signatur über den rohen Rumpf (raw body) und versucht fehlgeschlagene Zustellungen mit exponentiellem Backoff erneut zuzustellen. Ein Empfänger muss folglich die Signatur verifizieren und nach Ereignis-ID deduplizieren, anstatt von einer exakt einmaligen Zustellung (exactly-once) auszugehen.
Exporte stellen einen Pfad für massenhaften Datenabfluss dar. Berichtsexporte als XLSX, PDF oder JSON rufen in einem einzigen Vorgang große Mengen an Finanzdaten ab. Daher benötigen sie eine eigene Berechtigung, Ratenbegrenzungen (rate limits) und eine Audit-Protokollierung. Von Dritten bezogene Integrationen sollten als nicht vertrauenswürdige Eingaben behandelt und genauso validiert werden wie direkte Client-Anfragen.
Checkliste zur Prüfungssicherheit für eine niederländische Buchhaltungs-API
Nutzen Sie diese Checkliste, bevor Sie behaupten, dass eine Integration prüfungssicher ist:
- Explizite Zustandsmaschine für jede Finanzressource; verbuchte Einträge können nicht überschrieben werden
- Autorisierung auf Objekt- und Unternehmensebene bei jeder Anfrage, standardmäßig verweigert (deny-by-default)
- Mandanten- und Rollenkontext wird aus dem Token abgeleitet, nicht aus Client-Ansprüchen
- OAuth 2.0 gemäß RFC 9700; funktionsbasierte Scopes; getrennte Erstellungs- und Freigabeberechtigungen
- Funktionstrennung ist über Rollen erzwungen, nicht nur dokumentiert
- Idempotenzschlüssel bei allen finanzrelevanten Schreibvorgängen
- Serverseitige Buchhaltungs- und MwSt.-Validierung vor den Zustandsübergängen
- Ausschließlich erweiterbares (append-only), manipulationssicheres Prüfprotokoll mit Begründungscodes
- Aufbewahrungs- und Sperrregeln (legal hold) an niederländische Fristen angepasst (sieben Jahre, zehn Jahre bei Immobilien)
- Periodensperre für abgeschlossene Monate
- Signierte Webhooks mit Deduplizierung; bereichsbezogene, ratenbegrenzte und protokollierte Exporte
Was wir zuerst bauen würden
Wenn wir morgen die Buchhaltung in eine niederländische Plattform integrieren müssten, würden wir vor dem Schreiben eines einzigen geschäftlichen Endpunkts mit dem Zustandsmodell und der Autorisierung auf Objektebene beginnen. Diese beiden Entscheidungen schränken alle nachgelagerten Abläufe ein, und sie nachträglich in ein System einzubauen, das Hauptbucheinträge als bearbeitbare Tabellenzeilen behandelt hat, ist ausgesprochen schmerzhaft. Idempotenz und das Audit-Log folgen als Nächstes, da sie sich früh kostengünstig und nach fließenden Daten nur teuer hinzufügen lassen.
Der Rest – bereichsbezogene Tokens, signierte Webhooks, Periodensperre – lässt sich leichter umsetzen, sobald das Fundament steht. All dies lässt sich an einem Sandkasten-Unternehmen testen, bevor auch nur eine Zeile produktive Daten berührt wird.
FAQ
Bedeutet eine prüfungssichere API, dass das Unternehmen regelkonform (compliant) ist?
Nein, und hier lohnt es sich, präzise zu sein. Prüfungssicherheit ist eine Designeigenschaft des Systems: Das Hauptbuch, die Kontrollen und die Beweiskette sind so aufgebaut, dass eine Prüfung erfolgreich verlaufen kann. Die Einhaltung eines bestimmten Steuer-, Buchhaltungs- oder Sicherheitsrahmens ist eine separate Bewertung, die diese Kontrollen auf einen benannten Standard abbildet. Eine gut gebaute API erleichtert die Compliance-Arbeit, ersetzt sie jedoch nicht.
Wie lange müssen Buchhaltungsunterlagen in den Niederlanden aufbewahrt werden?
Die allgemeine Verpflichtung beträgt sieben Jahre für administrative Unterlagen und erstreckt sich auf zehn Jahre für Unterlagen im Zusammenhang mit unbeweglichem Vermögen. Erstellen Sie Aufbewahrungs- und Sperrregeln (legal hold), die Ihre normalen Lösch-Workflows nicht außer Kraft setzen können.
Ist ein statischer API-Schlüssel für eine Finanzintegration ausreichend?
Für Server-zu-Server-Automatisierungen mit engem Rahmen kann das funktionieren. Wiederverwendbare statische Schlüssel lassen sich jedoch nur schwer rotieren und sind gefährlich, wenn sie durchsickern. Für delegierte Zugriffe und jegliche Abläufe mit menschlicher Interaktion ist OAuth 2.0 mit kurzlebigen, funktionsbezogenen Tokens die bessere Wahl.
Warum ist Idempotenz gerade für die Buchhaltung so wichtig?
Weil ein doppelter Schreibvorgang in den meisten Systemen ein Ärgernis ist, in der Buchhaltung jedoch eine falsche Zahl in den Büchern darstellt, die jemand mühsam finden und stornieren muss. Idempotenzschlüssel machen Wiederholungsversuche sicher anstatt riskant.
Weiterführende Literatur
- OWASP API Security Project für die aktuellen API-Risikokategorien
- RFC 9700: OAuth 2.0 Security Best Current Practice für Anforderungen an delegierte Zugriffe
- Echtzeit-EU-MwSt. für Entwickler in den Niederlanden zu den praktischen steuerlichen Gegebenheiten in den Niederlanden
- API-Konventionen zu Scopes, Idempotenz, Fehlern und Webhook-Signierung