3 Stimmen

Wie werden Zeichenketten sicher geparst?

Wir wissen, dass die Verwendung von String-Konkatenation zur Erstellung von SQL-Abfragen ein Programm anfällig für SQL-Injection macht. Normalerweise umgehe ich das, indem ich Parameterfunktionen verwende, die von der API der verwendeten Datenbanksoftware bereitgestellt werden.

Aber ich habe nicht gehört, dass dies ein Problem bei der regulären Systemprogrammierung ist. Betrachten Sie den folgenden Code als Teil eines Programms, das es einem Benutzer erlaubt, nur in Dateien in seinem privaten Verzeichnis zu schreiben.

Scanner scanner = new Scanner(System.in);
String directoryName = "Bob";
String filePath = null;
String text = "some text";

System.out.print("Enter a file to write to: ");
filePath = scanner.nextLine();

// Write to the file in Bob's personal directory for this program (i.e. Bob/textfile.txt)
FileOutputStream file = new FileOutputStream(directoryName + "/" + filePath);
file.write(text.getBytes());

Ist die vorletzte Zeile eine Schwachstelle? Wenn ja, wie kann das Programm sicherer gemacht werden (insbesondere in Java, C++ und C#)? Eine Möglichkeit besteht darin, die Eingabe auf Escape-Zeichen zu überprüfen. Gibt es sonst noch etwas?

3voto

Cratylus Punkte 51546

Jede Eingabe des Benutzers sollte als " Verdächtig "

In Ihrem Fall gehen Sie davon aus, dass der Dateipfad an einer Stelle liegt, an die der Benutzer schreiben soll.

Der Benutzer kann einen beliebigen Dateipfad übergeben und (sofern das Programm über die entsprechenden Rechte verfügt) eine Datei ändern, die Sie nicht erwartet haben.

Also ja die Linie:

FileOutputStream file = new FileOutputStream(directoryName + "/" + filePath);

ist in der Tat eine Schwachstelle

Dieses Konzept gilt auch für C++

3voto

avgvstvs Punkte 5886

Die einfachste Lösung besteht darin, eine Whitelist der zulässigen Zeichen zu erstellen. Ändern Sie Ihren ursprünglichen Code (um Java-Konventionen zu berücksichtigen, da Sie sagten, Sie seien neu...)

package javawhitelist;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JavaWhiteListExample {

    public static void main(String[] args) throws IOException {

        Scanner scanner = new Scanner(System.in); 
        String directoryName = "Bob"; 
        String filePath = null; 
        FileWriter stream = null;
        String text = "some text";  
        System.out.print("Enter a file to write to: "); 
        filePath = scanner.nextLine();  
        String WHITELIST = "[^0-9A-Za-z]+";
        Pattern p = Pattern.compile(WHITELIST);
        Matcher m = p.matcher(filePath);

        //You need to do m.find() because m.matches() looks for COMPLETE match
        if(m.find()){ 
            //reject input.
            System.out.println("Invalid input.");
        }else{
            // Write to the file in Bob's home directory (i.e. Bob/textfile.txt) 
            try{
                File toWrite = new File(directoryName + File.separator + filePath);

                if(toWrite.canWrite()){
                    stream = new FileWriter(toWrite);
                    stream.write(text);
                }   
            }catch(FileNotFoundException e){
                e.printStackTrace();
            }catch(IOException e){
                e.printStackTrace();
            }finally{
                if(stream != null){
                    stream.close();
                }
            }

        }
    }
}

Die Standardimplementierung jeder JVM läuft mit allen Zugriffsberechtigungen des Benutzers. Die Verwendung der File.canWrite() Methode wird sicherstellen, dass der Benutzer nicht über eine Datei schreibt, für die er keine Berechtigung hat. Die sicherste Lösung (die GENAU angibt, wo die Datei gespeichert werden soll) wäre die Verwendung von com.sun.security.auth.module.UnixSystem.getName() und verwenden diese, um die /home/$USER Teil des Verzeichnisnamens. Einige Lösungen sagen Ihnen, dass Sie System.getProperty("user.home"): oder ähnliches, aber diese beruhen auf leicht veränderbaren Umgebungsvariablen.

Ich habe versucht, gründlich zu sein, ich hoffe, das hilft.

2voto

Marcus Punkte 11888

Da es mehrere reservierte Zeichen in einem Dateinamen kann es sinnvoll sein, den vom Benutzer angegebenen Pfad zu durchsuchen. Sie können auch überprüfen, ob die Zeichenkette nicht ../ , :/ usw., wodurch der Benutzer den Pfad zum "Heimatverzeichnis" manipulieren könnte. Ich würde empfehlen, einen regulären Ausdruck zu verwenden, um die angegebene Zeichenfolge zu überprüfen, bevor sie verwendet wird. Wenn die Überprüfung fehlschlägt, brechen Sie den Vorgang einfach ab und teilen dem Benutzer mit, dass etwas mit der Eingabe nicht in Ordnung war, anstatt zu versuchen, es zu beheben.

Die Dateistruktur kann ziemlich komplex sein, wenn man nicht weiß, was man tut, und Zeichen sind nicht das einzige Problem, wie in anderen Antworten erwähnt. Welche Dateinamen gültig sind, ist bei den verschiedenen Dateisystemen unterschiedlich. Alte FAT-Systeme haben eine Beschränkung von maximal 8 Zeichen, während das neuere NTFS, das von Windows verwendet wird, bis zu 255 Zeichen erlaubt.

Die Antwort wurde aktualisiert, um mehr Klarheit zu schaffen.

2voto

mmigdol Punkte 1789

Diese Frage unterscheidet sich deutlich von einem SQL-Injection-Problem. Bei einem SQL-Injection-Problem können böswillig eingegebene Parameter verwendet werden, um Befehle in einem privilegierten Sicherheitskontext auszuführen, da die Datenbank Der Benutzer, unter dem die Befehle ausgeführt werden, hat in der Regel freie Hand, um in die Zeilen der Datenbank zu schreiben.

In dem von Ihnen angeführten Beispiel lautet die Schlüsselfrage: "Als welcher Benutzer wird der Java-Code ausgeführt?". Wenn Sie diesen Code beispielsweise als CGI-Skript ausführen, ist jede Datei oder jedes Verzeichnis, in das der Benutzer des Webserver-Prozesses schreiben kann, anfällig. Wenn Sie den Code einfach von der Befehlszeile aus ausführen, ist es Sache des Betriebssystems (und nicht des Java-Codes), die Dateien/Verzeichnisse zu schützen, in die der Benutzer nicht schreiben können soll.

Wenn Sie dem Code nur erlauben wollen, in das Verzeichnis des Benutzers zu schreiben, dann sind die anderen Antworten richtig. Ich kann mir jedoch viele Szenarien vorstellen, in denen dies nicht der Fall sein könnte. z.B. Vielleicht schreiben Sie einen Code, um eine Datei im /etc-Verzeichnis automatisch zu bearbeiten.

Kurz gesagt, Sie sollten sich überlegen, in welchem Kontext Ihr Code ausgeführt wird, welche Sicherheit dieser Kontext bietet und welche Sicherheit Sie innerhalb Ihres eigenen Codes in diesem Kontext bieten müssen.

PS - Normalerweise sollten Sie nicht davon ausgehen, dass "/" Ihr Verzeichnis-Trennzeichen ist. Java bietet das Datei.trennzeichen zu diesem Zweck konstant.

2voto

Tom Hawtin - tackline Punkte 142461

Wenn Sie einen solchen Code sehen, führen Sie ihn aus.

Einige Probleme:

Angriffe durch Verzeichnisüberquerung: Traditionell werden bei Dateisystemen UI und API verwechselt. Wir haben diese Sprache mit Dateipfaden, aber keine Möglichkeit, besonders saubere Namen anzugeben. Auf typischen Betriebssystemen .. erlaubt es, in der Verzeichnisstruktur nach oben zu gehen (nicht unbedingt am Anfang des Pfades). Beachten Sie auch, dass mehr als ein Zeichen als Verzeichnistrennzeichen fungieren kann.

Links: Dateisystemverknüpfungen innerhalb des Verzeichnisses können auf andere Verzeichnisse verweisen.

NUL-Zeichen: Wenn Sie versuchen, ein Suffix anzugeben, z. B. eine Dateierweiterung, wird der Pfad durch ein Null-Byte abgeschnitten.

Shell-Escapes: Sie könnten Probleme mit Shell-Code haben, der versucht, den Dateipfad zu interpretieren, entweder vor der Erstellung oder später.

Vorhandene Dateien: Was passiert, wenn die Datei existiert?

Verwendung der Disc: Wenn die Daten vom Benutzer bereitgestellt werden, überprüfen Sie, ob sie nicht zu groß sind?

Versuchen Sie also, die Verwendung von Dateinamen zu vermeiden, die von Dritten erstellt wurden. Wenn Sie wirklich müssen, schlage ich vor, eine strenge Whitelist von Zeichen anzuwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X