Die Gefahren von setattr: Mass-Assignment-Schwachstellen in Python vermeiden
Jack Hair
15. Februar 2023
0 Min. LesezeitMass Assignment, auch als Autobinding oder Object Injection bezeichnet, ist eine Kategorie von Schwachstellen, die auftreten, wenn Benutzereingaben Variablen oder Objekten innerhalb eines Programms zugewiesen werden.
Mass-Assignment-Schwachstellen entstehen häufig, wenn Angreifer einem Objekt unerwartete Felder hinzufügen, um die Programmlogik zu manipulieren. Dies war die Ursache für eine bekannte GitHub-Authentifizierungsschwachstelle: Die Mass-Assignment-Funktionalität in Ruby on Rails ermöglichte es einem Angreifer, seinen öffentlichen Schlüssel zur GitHub-Organisation rails hinzuzufügen und einen Commit in den Master-Branch zu pushen.
Dieser Blogbeitrag wurde unter anderem durch die Spring4Shell-Schwachstelle angeregt, eine Remote-Code-Execution-Schwachstelle (RCE), die durch die im Spring-Framework enthaltene Autobinding-Funktionalität verursacht wurde. Das gab Anlass zu der Frage, ob sich eine ähnliche Schwachstelle auch im Python-Ökosystem finden ließe.
In diesem Beitrag untersuchen wir die potenziellen Risiken der Python-Funktion setattr() und zeigen, wie Sie Mass-Assignment-Schwachstellen in Ihrer Anwendung verhindern können.
Einführung in setattr
Eine gängige Methode, Mass Assignment in Python zu implementieren, ist die integrierte Funktion setattr(). Diese Funktion übernimmt ein Objekt, einen Attributnamen und einen Attributwert und weist dem Attribut des Objekts den angegebenen Wert zu. Sie kann sowohl neue Attribute hinzufügen als auch bestehende ändern.
Es ist zwar praktisch, einem Benutzer das Setzen des Werts beliebiger Attribute eines Objekts zu erlauben, kann aber unbeabsichtigte Folgen haben.
Erstens können dadurch herkömmliche Schwachstellen in der Programmlogik durch Mass Assignment entstehen. Objektfelder, die Benutzer eigentlich nicht ändern können sollten, lassen sich nun ändern.
Zweitens sind die Attribute, die sich mit setattr ändern lassen, nicht auf vom Programmierer definierte Felder beschränkt — auch Funktionen und integrierte Attribute wie __class__ und __dict__ lassen sich setzen. Anders als bei der Spring4Shell-Schwachstelle kann setattr keine verschachtelten untergeordneten Attribute eines Objekts setzen, was den Umfang eines Angriffs begrenzt. Es ist jedoch leicht, eine Ausnahme auszulösen, wenn setattr aufgerufen wird, indem __class__ auf einen Zeichenfolgenwert gesetzt wird, oder später während der Programmausführung, indem eine zum Objekt gehörende Funktion überschrieben wird. Eine auf diese Weise ausgelöste Ausnahme kann zu einem abnormalen Programmverhalten oder zu einem Denial-of-Service führen.
Der folgende Code ist ein kurzes Beispiel, das mit setattr einen Benutzer erstellt. Wird er mit der Eingabe first_name=Sam,last_name=S ausgeführt, lautet die Ausgabe Sam S: Permission denied.
Um das Programm durch eine nicht abgefangene Ausnahme zum Absturz zu bringen, kann die Eingabe first_name=Sam,last_name=S,is_admin=foo verwendet werden — dadurch wird die Funktion is_admin überschrieben und durch eine Zeichenfolge ersetzt. Beim Aufruf der Funktion wird dann eine Ausnahme ausgelöst.
Die Eingabe first_name=Sam,last_name=S,admin=foo überschreibt das admin-Attribut des User-Objekts mit der Zeichenfolge foo, da es sich dabei um einen Truthy-Wert handelt. Wenn die Funktion is_admin das admin-Attribut prüft, wird der Benutzer als Administrator behandelt und Sam S: You are admin! ausgegeben.
Mass Assignment verhindern
Eine allgemeine Strategie zur Eindämmung von Mass-Assignment-Schwachstellen besteht darin, Objekte mit Benutzereingaben von den Objekten zu trennen, die für die interne Programmlogik zuständig sind. Dazu werden Data Transfer Objects (DTOs) erstellt, die nur die Felder enthalten, die ein Benutzer setzen darf. In Python lässt sich dies leicht mit dataclasses umsetzen. Der folgende Code zeigt, wie sich mit einem DTO die zulässigen Felder explizit festlegen lassen. Werden ungültige Felder angegeben, wird ein TypeError ausgelöst — dieser wird anschließend abgefangen und behandelt, wodurch die oben beschriebenen Angriffe verhindert werden.
Auch die Validierung von Benutzereingaben kann Mass-Assignment-Schwachstellen verhindern. Wie immer ist es besser, die Eingaben anhand einer Liste zulässiger Daten zu validieren, statt nach verbotenen Daten zu suchen. Der folgende Code verwendet weiterhin setattr, prüft den Attributnamen aber anhand einer Liste zulässiger Attribute.
Am besten geben Sie immer explizit an, welche Benutzereingaben ein Programm erwartet. Wenn Sie bei der Verarbeitung von Benutzereingaben jedoch mehr Flexibilität benötigen, gibt es Alternativen zur Funktion setattr. Das collections-Modul der Python-Standardbibliothek stellt zwei nützliche Klassen bereit: collections.UserDict und collections.abc.MutableMapping. Von diesen Klassen können Sie erben, um Schlüssel-Wert-Zuordnungen zusätzliche Funktionalität hinzuzufügen. Wenn Sie auf Werte lieber über Attribute statt über Schlüssel zugreifen möchten, können Sie dies erreichen, indem Sie in Ihrer Klasse eine __getattr__-Methode implementieren. Im folgenden Beispiel verhält sich die User-Klasse wie ein Dictionary und kann alle vom Benutzer bereitgestellten Felder speichern. Durch das Überschreiben von __getattr__ wird ein Attribut, das sich nicht über den üblichen Mechanismus für den Attributzugriff finden lässt, stattdessen aus dem Dictionary mit den vom Benutzer bereitgestellten Feldern zurückgegeben. So kann der Benutzer auf diese Felder wie auf Attribute zugreifen, während Attribute der Klasse nicht durch Benutzereingaben überschrieben werden können.
Schutz Ihrer Python-Bibliotheken
Während der Softwareentwicklung kann es schwierig sein, Sicherheit gegen Komfort und Flexibilität abzuwägen. Was auf den ersten Blick harmlos erscheint, kann Sie und Ihre Anwendung einer Vielzahl von Sicherheitsrisiken aussetzen — deshalb sind Aufklärung und alternative Methoden so wichtig. Wir haben erläutert, wie setattr funktioniert, welche Gefahren mit seiner Verwendung in Ihren Python-Bibliotheken verbunden sind und wie Sie Mass-Assignment-Schwachstellen verhindern können. Mit diesem Wissen sind Sie gut gerüstet, um Ihre Python-Anwendungen vor Angriffen und Datenschutzverletzungen zu schützen. Weitere Informationen finden Sie auf unserer Homepage. Erstellen Sie dort ein kostenloses Konto oder buchen Sie eine Demo, um zu erfahren, wie Snyk Sie beim Schutz Ihres Codes, Ihrer Container, Abhängigkeiten und Cloud-Infrastruktur unterstützen kann.
Starten Sie mit Capture-the-Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Challenges lösen.



