55import java .io .File ;
66import java .io .IOException ;
77import java .io .OutputStream ;
8- import java .io .PrintWriter ;
98import java .nio .file .Files ;
9+ import java .nio .file .Path ;
10+ import java .nio .file .Paths ;
1011import java .util .Map ;
1112
1213public class StaticFileHandler {
@@ -30,21 +31,21 @@ public void sendGetRequest(OutputStream outputStream, String uri) throws IOExcep
3031 // Sanera URI: ta bort frågetecken, hashtaggar, ledande snedstreck och null-bytes
3132 String sanitizedUri = sanitizeUri (uri );
3233
33- // Kontrollera för sökvägsgenomgång-attacker
34+ // Kontrollera för sökvägsgenomgång-attacker med Path normalisering
3435 if (isPathTraversal (sanitizedUri )) {
3536 sendErrorResponse (outputStream , 403 , "Forbidden" );
3637 return ;
3738 }
3839
39- byte [] fileBytes = cacheFilter .getOrFetch (sanitizedUri ,
40+ byte [] fileBytes = cacheFilter .getOrFetch (sanitizedUri ,
4041 path -> Files .readAllBytes (new File (webRoot , path ).toPath ())
4142 );
4243
4344 HttpResponseBuilder response = new HttpResponseBuilder ();
44- response .setHeaders (Map .of ("Content-Type" , "text/html; charset=utf -8" ));
45+ response .setHeaders (Map .of ("Content-Type" , "text/html; charset=UTF -8" ));
4546 response .setBody (fileBytes );
46- PrintWriter writer = new PrintWriter ( outputStream , true );
47- writer . println ( response . build () );
47+ outputStream . write ( response . build () );
48+ outputStream . flush ( );
4849
4950 } catch (IOException e ) {
5051 // Hantera saknad fil och andra IO-fel
@@ -76,16 +77,26 @@ private String sanitizeUri(String uri) {
7677
7778 private boolean isPathTraversal (String uri ) {
7879 // Kontrollera för kataloggenomgång-försök
79- return uri .contains (".." ) || uri .contains ("~" );
80+ try {
81+ // Normalisera sökvägen för att detektera traversal-försök
82+ Path webRootPath = Paths .get (webRoot ).toRealPath ();
83+ Path requestedPath = webRootPath .resolve (uri ).normalize ();
84+
85+ // Om den normaliserade sökvägen är utanför webRoot, är det path traversal
86+ return !requestedPath .startsWith (webRootPath );
87+ } catch (IOException e ) {
88+ // Om något går fel vid normalisering, behandla det som potentiell path traversal
89+ return true ;
90+ }
8091 }
8192
8293 private void sendErrorResponse (OutputStream outputStream , int statusCode , String statusMessage ) throws IOException {
8394 HttpResponseBuilder response = new HttpResponseBuilder ();
8495 response .setStatusCode (statusCode );
85- response .setHeaders (Map .of ("Content-Type" , "text/html; charset=utf -8" ));
96+ response .setHeaders (Map .of ("Content-Type" , "text/html; charset=UTF -8" ));
8697 String body = "<html><body><h1>" + statusCode + " " + statusMessage + "</h1></body></html>" ;
8798 response .setBody (body );
88- PrintWriter writer = new PrintWriter ( outputStream , true );
89- writer . println ( response . build () );
99+ outputStream . write ( response . build () );
100+ outputStream . flush ( );
90101 }
91102}
0 commit comments