Streams in NTFS Dateien
Geschrieben von: Christoph Wille Im heutigen Artikel möchte ich etwas in die Untiefen von NTFS (NT File System) abtauchen, und ein interessantes Feature besprechen: Streams. Zuerst werde ich mich mit den Grundlagen beschäftigen, und dann Beispiele bringen, wie man in Streams schreibt, und Daten aus Streams ausliest. Das Schöne ist, daß man keinerlei zusätzliche Komponenten braucht, um dieses Feature des Betriebssystems zu seinen Gunsten zu verwenden. Streams - die GrundlagenWas sind Streams? Vereinfacht gesagt kann eine Datei auf einer NTFS Partition in mehrere "Unterbereiche" (Streams) aufgeteilt werden, die separat ansprechbar sind - wobei allerdings nur einer davon standardmäßig sichtbar (=lesbar) ist - der unbenannte Standardstream. Das folgende Bild zeigt schematisch eine Datei und ihre Streams. Wie bereits erwähnt muß nur der Standardstream existieren, alle weiteren Streams sind optional. Der Zugriff via zB FileSystemObject auf den Standardstream erfolgt einfach über den Dateinamen: myfile.ext. Bei Streams stellt sich nur eine kleine Änderung ein: myfile.ext:streamname. An den eigentlichen Dateinamen wird mit Doppelpunkt der Streamname angehängt. Die Daten des jeweiligen Streams werden intern vom Betriebssystem wie folgt angesprochen: myfile.ext:mystream:$DATA Ich hoffe, mit dem $DATA habe ich jetzt bei einigen Herrschaften eine Glocke geläutet - es gab bei IIS mit ASP den sogenannten ::$DATA Bug, der es erlaubte, an der ASP Engine vorbei den Sourcecode einer ASP Datei downzuloaden - und zwar genau über das Standardstreamfeature von NTFS, das von IIS nicht korrekt abgeblockt wurde. Weil wir gerade beim Thema Sicherheit sind: wofür soll denn nun für einen ASP Programmierer das Streams Feature von Nutzen sein? Nun, wenn nur der Standardstream sichtbar ist, heißt das, daß ich sensitive Informationen in weiteren Streams ablegen kann. Und das Beste ist, daß weder über FTP, einen Web Browser und festhalten - noch über den Windows Explorer - diese Streams sichtbar werden! Wer also bestimmte Daten nicht nur vor Hackern sondern auch vor seinem Provider verstecken will, der liegt mit Streams genau richtig. Ein weiteres Anwendungsgebiet von Streams wäre zum Beispiel, daß man eine Datei für Lesen und Schreiben gleichzeitig aufmachen kann - das Locking funktioniert per Stream. Anwendung könnte das für Datei-basierte Foren und so weiter finden. Da wir nun die Anwendungsgebiete im Groben mal abgesteckt haben, kommen wir zu einem wichtigen Punkt der impliziert ist, aber auch explizit erwähnt werden sollte: das Streams Feature ist nur auf NTFS vorhanden ist (ergo Windows NT/2000). Will man eine Datei, die mehrere Streams enthält, auf eine andere Partition kopieren (FAT, FAT32), so werden die zusätzlichen Streams nicht mitgenommen - man wird allerdings davor gewarnt: Aus diesem Grund sollte man sich rückversichern, daß die aktuelle Partition Streams unterstützt - möglichst bevor man Streams herumspielt. Die folgende Funktion ist Teil der Datei StreamLibrary.asp, die als Include in allen anderen Beispielen verwendet wird (auch Teil des Downloads).
Function IsDriveNTFSDrive(strDriveLetter) Dim fsObj, drvObj, strTypeOfFS IsDriveNTFSDrive = False Set fsObj = CreateObject("Scripting.FileSystemObject") Set drvObj = fsObj.GetDrive(strDriveLetter) strTypeOfFS = drvObj.FileSystem If (0 = StrComp("NTFS", strTypeOfFS)) Then IsDriveNTFSDrive = True End If End Function Diese Funktion verwendet die FileSystem Eigenschaft des Drive Objekts um den Typ des Dateisystems zu ermitteln. Bei NTFS liefert sie True, ansonsten immer False. Schreiben von StreamsDie Voraussetzungen sind abgeklärt, jetzt geht es um's Schreiben in die Datei. Dazu habe ich auch eine universell einsetzbare Funktion gebaut: WriteStreamData.
Sub WriteStreamData(strTargetFile, strTargetStream, strStreamData) Dim fsObj, objTextStream, strFullStreamedName Set fsObj = CreateObject("Scripting.FileSystemObject") ' der default stream muß zwar nicht explizit generiert werden, es ' empfiehlt sich aber sehr! If (Not fsObj.FileExists(strTargetFile)) Then Set objTextStream = fsObj.CreateTextFile(strTargetFile) objTextStream.Write "Mehrfach-Stream Datei" objTextStream.Close Set objTextStream = Nothing End If strFullStreamedName = strTargetFile & ":" & strTargetStream Set objTextStream = fsObj.CreateTextFile(strFullStreamedName) objTextStream.Write strStreamData objTextStream.Close Set objTextStream = Nothing Set fsObj = Nothing End Sub Etwas, das ich nicht tun müßte, ist den Standardstream mit Daten anzufüllen - es dient nur dazu, daß die Datei nicht 0 Byte lang ist. Der Grund warum sie 0 Byte wäre ist der, daß nur der Standardstream zur Größenkalkulation herangezogen werden kann (also wer seinem Systemadministrator ein Ei legen will, der kann mehrere MB's in Dateien der Länge 0 verstecken...). Auch wenn die Größe vom Standardstream gerechnet wird, werden alle Streams bei einem Backup gesichert - also um die Daten in den zusätzlichen Streams muß man sich nicht fürchten. Das eigentliche Schreiben in einen Stream ist sehr simpel - nur 4 Zeilen inklusive des Erstellens eines Strings mit dem Streamnamen und dem Schließen der Datei. Schon hat man Daten erfolgreich versteckt. Verwendet wird die Funktion wie folgt (WriteStream.asp):
<!--#include file="StreamLibrary.asp"--> <% Dim strFile, strStream strFile = Server.MapPath("demo.txt") strStream = "mystream" If IsDriveNTFSDrive("d") Then WriteStreamData strFile, strStream, "some data you won't see on disk" End If %> Das Beispiel ist wirklich sehr straight-forward: die Datei wird definiert, das Dateisystem auf NTFS gecheckt, und dann die Daten geschrieben. Sollte alles gutgehen, bekommt man eine leere Seite präsentiert (das sollte man unter Umständen ändern), sonst eine Fehlermeldung. Wer möchte, kann die Datei nun in Notepad öffnen - er wird nur den Standardtext aus der Funktion WriteStreamData erhalten. Um die Daten des zusätzlichen Streams zu sehen, muß man mit Doppelpunkt hinter dem Dateinamen den Streamnamen angeben, und schon sieht man die Daten auch in Notepad - aber wie gesagt, man muß den Namen des Streams kennen. Lesen von StreamsDa unsere Daten nun sicher in einem Stream liegen, stellt sich noch die Frage, wie man sie wieder auslesen kann. Diese Frage beantwortet der Sourcecode zur Funktion ReadStreamData:
Function ReadStreamData(strFileName, strStreamName) Dim fsObj, objTextStream, strContent Set fsObj = CreateObject("Scripting.FileSystemObject") If Not fsObj.FileExists(strFileName) Then Err.Raise vbObjectError+1, "Datei existiert nicht!" End If Set objTextStream = fsObj.OpenTextFile(strFileName & ":" & strStreamName) strContent = objTextStream.ReadAll() objTextStream.Close Set objTextStream = Nothing Set fsObj = Nothing ReadStreamData = strContent End Function Wieder passiert hier eigentlich nichts aufregendes - ich habe nur eine kleine Sicherheitsmaßnahme eingebaut: das Checken, ob die Datei existiert. Allerdings kümmere ich mich nicht um die Fehler, die entstehen falls der Stream nicht existiert - das ist Aufgabe des Lesers! Anwendung findet die Funktion in der Datei ReadStreams.asp:
<!--#include file="StreamLibrary.asp"--> <% Dim strFile, strStream strFile = Server.MapPath("demo.txt") strStream = "mystream" If IsDriveNTFSDrive("d") Then Response.Write ReadStreamData(strFile, strStream) End If %> Das Lesen funktioniert im Grunde genauso einfach wie das Schreiben. Mit der Library die ich Ihnen in diesem Artikel vorgestellt habe, kann man bequem mit Streams arbeiten - und diese zum "Verstecken" von Daten oder zum Speichern von verwandten Daten in einer einzigen Datei verwenden. SchlußbemerkungWichtig zu bemerken ist unbedingt, daß man mit dem FileSystemObject keine Möglichkeit hat, alle Streams, die in einer Datei vorhanden sind, einfach aufzulisten. Man muß wissen, daß ein Stream existiert (auch nicht schlecht von der Perspektive der Sicherheit). Wer allerdings einen C++ Compiler hat, der kann mit WIN32 API Funktionen sehr wohl alle Streams auflisten und anzeigen lassen - also 100% sicher sind die Daten nicht, das würde nur mit Verschlüsselung stimmen (wenn sie richtig angewendet ist). Download des CodesKlicken Sie hier, um den Download zu starten. Verwandte Artikel
Dateiattribute unter ASP auslesen Links zu anderen Sites
File Access Issue with Windows NT Internet Information Server ($DATA Bug) Wenn Sie jetzt Fragen haben...Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten. Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.
Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.
©2000-2006 AspHeute.com |