Blog

Was heißt eigentlich API-Security?

27 Feb 2023

Foto Blogbeitrag - diskutierende Menschen

Jedem Enterprise-Entwickler, der schon einmal eine Webanwendung umgesetzt hat, sollten die OWASP Top Ten geläufig sein. Das Open Web Application Security Project (OWASP) ist eine Non-Profit-Organisation, die sich dem Thema Websecurity angenommen hat und in regelmäßigen Abständen besagte Top Ten der häufigsten Sicherheitslücken herausbringt.

Zu viele Daten zum Client

Wie kommt so etwas zustande? Ich weiß zwar nicht, ob die besagte Software in Java (oder einer anderen JVM-Sprache) geschrieben ist, wir werden aber sehen, dass ein solches Problem auf jeden Fall sehr leicht in Java-Applikationen auftreten könnte.

Aktuelle JSON-Mapping-Frameworks machen es einem leicht, Java-Objekte als JSON-Antwort auf einen REST Request zurückzugeben. Im einfachsten Fall returniert man das Java-Objekt einfach. Um die Übersetzung nach JSON kümmert sich das Framework.

Dieses Vorgehen birgt aber einen gravierenden Sicherheitsnachteil. Falls man es nicht explizit verbietet, werden alle Attribute des Objektes als JSON übertragen – und das sogar rekursiv für anhängende Objekte. Der Entwickler merkt davon erstmal nichts. An der Oberfläche sind ja auch nur die Daten sichtbar, die man explizit dort eingebaut hat. Dabei können unter der Haube ungewollt auch sensible Daten zum Client geschickt werden.

Auch dieses Sicherheitsproblem trat im oben geschilderten Fall auf. Fragte man die Stammdaten einer Arztpraxis ab, erhielt man auch die Zugangsdaten zu deren Mailserver. Damit ließen sich nicht nur Mails im Namen der Praxis verschicken, nein, es war auch möglich, sich den E-Mail-Verkehr der Praxis anzuschauen.

In der OWASP Top Ten der API-Security von 2019 rangiert dieses Problem unter dem Begriff „Excessive Data Exposure“ auf Platz drei.

Erlaubt oder nicht erlaubt

Doch das Problem der geleakten SMTP-Daten war erst der Anfang. In der Entwicklerkonsole des Browsers ließ sich ziemlich schnell feststellen, dass der URL zum Abrufen von Dokumenten die Form /:praxisNummer/document/:patientenDokument hatte. Ein naheliegender Versuch war also, zu versuchen, ob man alle Dokumente über /:praxisNummer/document abrufen konnte – und es ging tatsächlich. Als einfacher Patient darf ich also alle Dokumente der Praxis sehen, also auch die der anderen Patienten. Und damit nicht genug. Es lassen sich natürlich weitere Endpoints erraten, z. B. /:praxisNummer/patient, um alle Patienten abzurufen – auch das war möglich.

Das Problem ist offensichtlich: Nur weil jemand auf ein paar Dokumente zugreifen darf, darf er nicht automatisch auch auf alle Patienten zugreifen. Die OWASP bezeichnet das als „Broken Function Level Authorization“ und ordnet es auf Platz fünf der Top Ten ein.

Der Abruf aller Dokumente oder aller Patienten ist aus Sicht der Arztpraxis sicherlich sinnvoll, aus Sicht eines Patenten sollte er aber eben nicht erlaubt sein. Dieses Problem ließe sich mit einem einfachen Rollenmodell mit den Rollen „Praxis“ und „Patient“ lösen.

In Java könnte man den Zugriff dann leicht über die Annotation @RolesAllowed beschränken. In der Praxis werden diese einfachen Sicherheitsmechanismen aber vom Entwickler gerne vergessen. Um sicherzustellen, dass sich jeder Entwickler immer Gedanken dazu macht, wer auf seine REST-Schnittstelle zugreifen darf, hat sich in unseren Projekten eine ArchUnit-Regel [3] bewährt, die sicherstellt, dass an jeder REST-Ressource mindestens eine Securityannotation steht. Auch an öffentliche Ressourcen muss explizit ein @PermitAll geschrieben werden, um zu dokumentieren, dass die Ressource bewusst öffentlich zugänglich ist.

Objektbasierte Zugriffsrechte

Häufig reicht allerdings ein rollenbasierter Ansatz nicht aus. Auch wenn in diesem Beispiel der Zugriff auf /document oder /patient durch das Vergeben von Rollen verboten worden wäre, dann hätte man immer noch die IDs anderer Dokumente erraten und über /:praxisNummer/document/:patientenDokument auf die Dokumente anderer Patienten zugreifen können. Was hier benötigt wird, ist ein objektbasierter Zugriffsansatz. Und dieser ist gar nicht so leicht zu realisieren. Man muss nämlich für jedes Objekt Regeln definieren, um auswerten zu können, wer darauf zugreifen darf. Diese Regeln müssen dann irgendwo im Code überprüft werden. Ein Ansatz dazu sind Access Control Lists. Das Spring-Framework bietet in seiner Security-Library Unterstützung, um diese zu verwenden [4]. Aber auch mit dieser Lösung muss man die Regeln zum Anlegen der Access Control Lists natürlich irgendwo im Code hinterlegen. Andere Varianten packen die Regeln in Annotations. Das ist in Spring Security auf Methodenebene möglich (siehe [5], Example 11). Ich selbst habe vor einigen Jahren ein Framework geschrieben, mit dem das auf JPA-Entity-Ebene geschehen kann [6].

Alle diese Lösungen haben allerdings in bestimmten Kontexten Nachteile, sodass einem häufig nichts anderes übrigbleibt, als die Regeln explizit im Code zu implementieren. Das birgt natürlich das Risiko, dass sie an der einen oder anderen Stelle vergessen werden. Unter anderem deshalb ist vermutlich „Broken Object Level Authorization“ auf Platz eins der OWASP Top Ten.

Keine Zugriffslimitierung

Um in dem oben genannten Beispiel Zugriff auf die Dokumente anderer Patienten zu bekommen, ist es notwendig, IDs dieser Dokumente zu erraten. Auf dieselbe Art und Weise war es in der Software auch möglich, auf die Daten weiterer Arztpraxen zuzugreifen. Dazu musste man sich lediglich als Patient in der Praxis registrieren. Um das zu können, war nur die ID der Praxis nötig. Auch diese konnte erraten werden.

Die einfachste Möglichkeit, IDs zu erraten, ist es, einfach alle Nummern durchzuprobieren. Da die Arztpraxen in der Anwendung eine vierstellige ID haben, mussten einfach nur alle Zahlen von 0 bis 9 999 durchprobiert werden, um gültige Arztpraxen zu finden. Wenn das API ein solches Durchprobieren nicht erlaubt hätte (z. B., indem es nach drei falsch eingegebenen IDs von derselben IP jegliche Requests geblockt hätte), wäre das Erraten nicht so leicht möglich gewesen. Dieses Problem wird in den OWASP API Security Top Ten als „Lack of Resource & Rate Limiting“ bezeichnet und rangiert auf Platz 4. Realisieren lässt sich so ein Limiting in der Regel recht leicht über ein API Gateway.

Authentifizierung

Die oben beschriebene medizinische Software warb unter anderem mit einer dezentralen Datenhaltung, bei der die einzelnen Dokumente auf separaten Praxisservern liegen. Das zentrale Portal, bei dem sich die Patienten anmelden konnten, leitete die Anfragen dann unverändert an die dezentralen Praxisserver weiter. Wegen dieser „blinden“ Weiterleitung wird dieser Weiterleitungsserver „Blind-Proxy“ genannt.

In der Praxis waren die Anfragen allerdings nicht ganz unverändert. Zwar wurde der Payload nicht angerührt, allerdings gingen auf dem Weg die Authentifizierungsinformationen verloren und die Weiterleitung erfolgte als Super User. Vermutlich hätte man mit dieser Information verschiedenste zerstörerische Aktionen auf den Praxisservern durchführen können. Das haben die Forscher allerdings nicht ausprobiert.

Das Problem des Weiterleitens von Authentifizierungsinformationen ist ein gängiges Problem in verteilten Systemen, dass aber spätestens seit dem Aufkommen von Microservices gelöst ist.

Man hätte die Authentifizierung hier einfach durch den Einsatz von JSON Web Tokens [7], die dem Blind-Proxy übergeben werden, an die Praxisserver weiterleiten können. Dieses Problem bezeichnet das OWASP als „Broken User Authentication“ und ordnet es auf Platz zwei der Top Ten ein.

Security abschalten

Als ein weiteres Feature der Software wurde die „Ende-zu-Ende-Verschlüsselung“ beworben. Tatsächlich wurden allerdings nicht die Dokumente selbst verschlüsselt, sondern nur die Links auf die Dokumente. Das war allerdings nicht das einzige Problem mit der Verschlüsselung. Ende-zu-Ende-Verschlüsselung basiert darauf, dass der Sender den Datensatz explizit nur für den Empfänger verschlüsselt, sodass nur der Empfänger ihn lesen kann. Dazu muss der Sender natürlich wissen, wer der Empfänger ist. In der beschriebenen Software wurde das über einen Parameter beim Request mitgeteilt. Weiß der Sender nicht, wer der Empfänger ist, kann er die Daten demzufolge auch nicht Ende-zu-Ende verschlüsseln. Man würde also erwarten, dass das Weglassen des Empfängers im Request zu einem Fehler führen würde. In der hier beschriebenen Software war das allerdings nicht so. Stattdessen wurden in diesem Fall die Daten unverschlüsselt übertragen. In so einer Situation spricht das OWASP von „Security Misconfiguration“, die sich auf Platz sieben der Top Ten findet.

Weitere Probleme

Die weiteren Punkte auf der Liste der OWASP sind übrigens „Injection“, „Improper Asset Management“ und „Insufficient Logging & Monitoring“. Auch Letzteres war in der beschriebenen Software ein Problem: Nach Aufdecken der Sicherheitsprobleme war man nicht in der Lage, festzustellen, ob bereits illegal auf Patientendaten zugegriffen wurde oder nicht. Insofern konnten nicht einmal die Auswirkungen der Securitylücken abgeschätzt werden.

Fazit

Durch die wachsende Bedeutung von APIs steigt auch der Bedarf an ihrer Absicherung. Nicht immer geschieht das in ausreichendem Maße durch die Entwickler. Um auf die häufigsten Sicherheitsprobleme von APIs aufmerksam zu machen, veröffentlicht die OWASP seit 2019 die Top Ten der API-Security-Probleme.

Ich habe das Beispiel der durch das Team von Zerforschung [2] analysierten Software hier gewählt, weil es gleich die ersten sieben der Top Ten API-Security-Probleme enthält (und darüber hinaus noch Punkt zehn). Natürlich ist nicht jedes API so schlecht geschützt wie dieses Beispiel. Es reicht aber auch, wenn einer der Punkte aus der Top Ten auf das eigene API zutrifft, um eine potenzielle Sicherheitslücke zu haben.

Auch wenn viele der hier vorgestellten Probleme trivial erscheinen, offenbart die Diskussion über Lösungsansätze, dass viele Entwicklungsteams nicht davor gefeit sind, Sicherheitslücken zuzulassen. Das Beispiel zeigt exemplarisch, auf was man bei der API-Entwicklung achten sollte und wie man Securityproblemen begegnen kann.

Noch im letzten Jahr ist eine aktualisierte Version der Top Ten herauskommen. API-Entwickler sollten das im Blick haben.

In diesem Sinne – stay tuned!

Links & Literature

[1] https://owasp.org/www-project-api-security/

[2] https://zerforschung.org/posts/doczirkus/

[3] https://www.archunit.org

[4] https://docs.spring.io/spring-security/site/docs/3.0.x/reference/domain-acls.html

[5] https://docs.spring.io/spring-security/reference/servlet/authorization/method-security.html

[6] https://jpasecurity.org

[7] https://jwt.io

 

Keine Infos mehr verpassen!