Wie wird ein Mime-Type eigentlich erkannt?

Vor einiger Zeit habe ich ein Problem beim Import von Caldera-Formularen gehabt und habe über meine Lösung auch gebloggt. Aber ich habe nicht verstanden, warum dieser Fehler manchmal auftritt und manchmal nicht. In diesem Artikel will ich nun erklären, was da eigentlich genau schief geht, warum das passiert und was das mit einer Sicherheitslücke in WordPress zu tun hat.

Kurz noch einmal das Problem erklärt: Ich habe ein Caldera-Formular exportiert und es dann auf einer andere (oder auch der gleichen) Website importiert. Doch es kam die Fehlermeldung Form could not be imported. File type must be JSON. Das war merkwürdig, denn es handelte sich definitiv um eine JSON-Datei, die ja von Caldera-Forms selbst erst kurz vorher exportiert wurde. Was könnte dabei schief gegangen sein?

Es stellte sich heraus, dass die Datei den falschen Mime-Type meldete. Statt application/json meldete das PHP text/html als Mime-Type zurück. Ein Hinzufügen von text/html als zweiten gültigen Mime-Type für JSON-Dateien behebt das Problem. Innerhalb des Plugins wird bereits text/plain als zweite Möglichkeit geprüft.

$name = $_FILES[ 'import_file' ][ 'name' ];
					$type_check = wp_check_filetype_and_ext($temp_name,$name, [
					        'json' => 'application/json',
                    ]);
					if( ! $type_check['type'] ){
						$type_check = wp_check_filetype_and_ext($temp_name,$name, [
							'json' => 'text/plain',
						]);
                    }

Warum wird die Datei also manchmal als text/html erkannt. Dazu musste ich erst einmal verstehen, was der Mime-Type überhaupt ist. Und da war doch was in der einen WordPress-Version nach der das Problem überhaupt auftauchte. Also schaue ich mir noch mal den Make-Artikel an.

MIME validation for uploaded files

Prior to 5.0.1, WordPress did not require uploaded files to pass MIME type verification, so files could be uploaded even if the contents didn’t match the file extension. For example, a binary file could be uploaded with a .jpg extension.

This is no longer the case, and the content of uploaded files must now match their extension. Most valid files should be unaffected, but there may be cases when a file needs to be renamed to its correct extension (e.g., an OpenOffice doc going from .pptx to .ppxs).

Der Inhalt einer Datei muss der Dateiendung entsprechen. Das wird nun geprüft. Aber eine JSON-Datei ist nur eine Textdatei. Wie soll denn WordPress erkennen, was das für ein Inhalt ist?

PHP nutzt dazu Signaturen, also spezielle Muster, die einen Dateityp charakterisieren. (Hintergrund für diese Technik) Für manche Typen ist das sehr einfach. Eine PDF-Datei startet zum Beispiel mit %PDF-. Es wird also versucht die Datei auf Muster zu scannen und so den Typ zu erkennen. Ist nun in dem Formular viel HTML-Code zu finden, so kann es passieren, dass als Rückgabe eben text/html kommt. Denn neben viel normalem Text, der eher auf text/plain schließen würde, ist JSON ja nur an den paar geschwungen Klammern, Brackets und Doppelpunkten zu erkennen. Wahrscheinlich schwer zu erkennen …

Das Problem liegt also an der Fehlinterpretation von PHP (bzw. der hinterlegten Signaturen auf der Installation) und wäre mit einem anderen Formular und/oder auf einem anderen Server nicht unbedingt reproduzierbar. Und genau das passt auch zu meinen Tests. Mit der gleichen Datei habe ich auf unterschiedlichen Servern unterschiedliche Ergebnisse. Und auch mit unterschiedlichen Dateien auf dem jeweils gleichen Server unterscheiden sich die Ergebnisse. Das passt zu der Theorie, dass der Inhalt der Datei und die Erkennungssignaturen relevant sind. Hilft uns nur kaum beim Lösen des Problems.

Folglich wäre auch ein Unit-Test für die korrekte Mime-Type-Erkennung, an den ich zuerst gedacht hatte, wenig sinnvoll.

Es sieht so aus, also ob ich genau den richtigen Weg genommen, auch ohne genau zu wissen, warum. Denn das Hinzufügen von mehr erlaubten Mime-Types für die JSON-Dateiendung scheint mir hier der einzig sinnvolle Weg.

Kennst du noch mehr Details über die Signaturen bei der Mime-Type-Erkennung oder hattest ein ähnliches Problem? Dann freue ich mich einen Kommentar!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.