Inadequate file size control - Java

Inadequate file size control - Java

Need

Enforcement of file size restrictions

Context

  • Usage of Java 8 for developing applications with enhanced features and performance improvements
  • Usage of javax.servlet-api for developing Java web applications with servlets
  • Usage of commons-io for common input/output operations

Description

Non compliant code

        import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FileUploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String contentType = request.getContentType();
        if ((contentType != null) && (contentType.indexOf("multipart/form-data") >= 0)) {
            DataInputStream in = new DataInputStream(request.getInputStream());
            int formDataLength = request.getContentLength();

            byte dataBytes[] = new byte[formDataLength];
            int byteRead = 0;
            int totalBytesRead = 0;
            while (totalBytesRead < formDataLength) {
                byteRead = in.read(dataBytes, totalBytesRead, formDataLength);
                totalBytesRead += byteRead;
            }

            String file = new String(dataBytes);
            saveFile(file);
        }
    }

    private void saveFile(String fileContent) {
        File file = new File("/server/path/" + System.currentTimeMillis() + ".txt");
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(fileContent.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
        
        

The above code is a simple servlet that handles file uploads. The doPost method is invoked when a POST request is made to the servlet. It checks if the request content type is multipart/form-data, which is used for file uploads. If it is, it reads the incoming data and saves it to a file on the server.

The vulnerability in this code lies in the fact that there is no control over the size of the files that can be uploaded. The request.getContentLength() method is used to create a byte array of the exact size of the incoming file, and all incoming data is read into this array. If a user were to upload a very large file, this could potentially cause an OutOfMemoryError to be thrown, as the entire file is read into memory at once. This could lead to a Denial of Service (DoS) attack, as the server could be forced to exhaust its resources dealing with large file uploads.

Furthermore, there is no control over the amount of disk space that can be used by uploaded files. A user could potentially fill up the server's disk space by uploading very large files, which could also lead to a DoS attack.

The saveFile method simply writes the contents of the uploaded file to a new file on the server. There is no control over the type of files that can be uploaded, which could potentially lead to security issues if a user were to upload a malicious file.

Steps

  • Implement file size validation before saving the file.
  • Set a maximum file size limit for uploaded files.
  • Validate the file size against the maximum limit before saving the file.
  • Handle the case when the file size exceeds the maximum limit.
  • Consider using a library or framework that provides built-in file size control.
  • Ensure that the file size control is implemented on both the client-side and server-side.
  • Educate users about the maximum file size limit and provide appropriate error messages when the limit is exceeded.

Compliant code

        import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FileUploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final int MAX_FILE_SIZE = 1024 * 1024 * 5; // 5MB

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String contentType = request.getContentType();
        if ((contentType != null) && (contentType.indexOf("multipart/form-data") >= 0)) {
            int formDataLength = request.getContentLength();

            // Check if the file size exceeds the maximum limit
            if (formDataLength > MAX_FILE_SIZE) {
                response.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, "File size exceeds limit");
                return;
            }

            DataInputStream in = new DataInputStream(request.getInputStream());

            byte dataBytes[] = new byte[formDataLength];
            int byteRead = 0;
            int totalBytesRead = 0;
            while (totalBytesRead < formDataLength) {
                byteRead = in.read(dataBytes, totalBytesRead, formDataLength);
                totalBytesRead += byteRead;
            }

            String file = new String(dataBytes);
            saveFile(file);
        }
    }

    private void saveFile(String fileContent) {
        File file = new File("/server/path/" + System.currentTimeMillis() + ".txt");
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(fileContent.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
        
        

The updated code now includes a file size validation before saving the file. A constant MAX_FILE_SIZE is defined to set the maximum file size limit for uploaded files. This limit is set to 5MB in this example, but it can be adjusted according to the requirements.

In the doPost method, before reading the file data, the code checks if the size of the uploaded file exceeds the maximum limit. If the file size is larger than the maximum limit, the method sends an HTTP 413 error (Request Entity Too Large) and returns immediately, without processing the file.

This way, the system now performs an adequate control of the size of the files that can be uploaded to the server, preventing potential issues related to handling large files.

References