Κυριακή 23 Φεβρουαρίου 2014

Secure Systems Design - Part II

IV. Simple Web Server

Για να γίνει κατανοητό τι μπορεί να πάει στραβά σε μία λάθος σχεδίαση, όσον αφορά την ασφάλεια, παραθέτω το παρακάτω παράδειγμα ενός web server, ο οποίος υλοποιήθηκε σε Java.

a. Hypertext Transfer Protocol
HTTP είναι το πρωτόκολλο επικοινωνίας το οποίο χρησιμοποιούν οι servers στο Web. Μία ιστοσελίδα ξεκινάει ως http://prefix
Ένα τυπικό HTTP request, από έναν browser σε ένα web server είναι:
GET / HTTP/1.0
Η απόκριση από το server θα είναι η αναζήτηση του root αρχείου (index.html) κι επιστροφή HTTP/1.0 200 OK μαζί με τα περιεχόμενα του αρχείου.

/*This method is called when the program is run from the command line. */
public static void main (String argv[]) throws Exception
{
/*Create a SimpleWebServer object, and run it */
SimpleWebServer sws = new SimpleWebServer();
sws.run();
}

public class SimpleWebServer {
/*Run the HTTP server on this TCP port. */
private static final int PORT = 8080;
/*The socket used to process incoming connections from web clients*/
private static ServerSocket dServerSocket;

public SimpleWebServer () throws Exception {
dServerSocket = new ServerSocket (PORT);
}

public void run () throws Exception {
while (true) {
/*wait for a connection from a client */
Socket s = dServerSocket.accept ();
/* then process the client’s request */
processRequest(s);
                }
}

/*Reads the HTTP request from the client, and responds with the file the user requested or a HTTP error code */
public void processRequest (Socket s) throws Exception {
/*used to read data from the client */
BufferedReader br = new BufferedReader (new InputStreamReader (s.getInputStream()));
/*used to write data to the client */
OutputStreamWriter osw = new OutputStreamWriter (s.getOutputStream());
/* read the HTTP request from the client */
String request = br.readLine();
String command = null;
String pathname = null;
/* parse the HTTP request */
StringTokenizer st = new StringTokenizer (request, “ “);
Command = st.nextToken();
Pathname = st.nextToken();
if (command.equals(“GET”)) {
/*if the request is a GET try to respond with the file the user is requesting */
serveFile (osw, pathname);
}
else {
/*if the request is a NOT a GET, return an error saying this server does not implement the requested command */
osw.write (“HTTP/1.0 501 Not Implemented\n\n”);
}
/* close the connection to the client */
osw.close();
}

public void serveFile (OutputStreamWriter osw, String pathname) throws Exception {
FileReader fr = null;
Int c = -1;
StringBuffer sb = new StringBuffer();
/*remove the initial slash at the beginning of the pathname in the request */
If (pathname.charAt(0) == ‘/’)
pathname = pathname.substring(1);
/* if there was no filename specified by the client, serve the “index.html” file */
If (pathname.equals(“”))
pathname = “index.html”;
/* try to open file specified by pathname */
try {
fr = new FileReader(pathname);
c = fr.read();
}
catch (Exception e) {
/* if the file is not found, return the appropriate HTTP response code */
osw.write (“HTTP/1.0 404 Not Found \n\n”);
return;
}
/* if the requested file can be successfully opened and read, then return an OK response code and send the contents of the file */
osw.write (“HTTP/1.0 200 OK\n\n”);
while (c != -1) {
sb.append ((char)c);
c = fr.read();
}
osw.write (sb.toString());
}

b. DoS Παράδειγμα
processRequest(){
/*read the HTTP request from the client*/
String request = br.readline(); //empty string
String command = null;
String pathname = null;
/*parse the HTTP request*/
StringTokenizer st = new StringTokenizer(request, " ");
command = st.nextToken(); // EXCEPTION: no tokens!
/*SERVER CRASHES HERE - DENIAL OF SERVICE! */
pathname = st.nextToken();
}

c. How do we fix this?
 - Ο web server πρέπει να αποσυνδεθεί από τον web client ο οποίος στέλνει την malformed HTTP request στο server.
 - Ο προγραμματιστής πρέπει να χειριστεί με προσοχή τα exceptions για τις malformed requests.
 - Λύση: περικύκλωση του String Tokenizing κώδικα με try/catch block.
/*read the HTTP request from the client */
String request = br.readline();
String command = null;
String pathname = null;

try {
/*parse the HTTP request */
StringTokenizer st = new StringTokenizer(request, " ");
command = st.nextTokenizer();
pathname = st.nextTokenizer();
}
catch (Exception e) {
osw.write("HTTP/1.0 400 Bad Request\n\n");
osw.close();
return;
}

Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου