Geschrieben von: Christoph Wille
Kategorie: ASP Tricks
This printed page brought to you by AlphaSierraPapa
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.
Was 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.
Die 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.
Da 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.
Wichtig 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).
This printed page brought to you by AlphaSierraPapa
Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20000821.zip
Dateiattribute unter ASP auslesen
http:/www.aspheute.com/artikel/20000523.htm
Lesen von Textdateien
http:/www.aspheute.com/artikel/20000530.htm
Minigolf - 99 Bottles of Beer
http:/www.aspheute.com/artikel/20030324.htm
File Access Issue with Windows NT Internet Information Server ($DATA Bug)
http://www.microsoft.com/technet/security/bulletin/ms98-003.asp
©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.