DEV Community

Golam_Mostafa
Golam_Mostafa

Posted on

Securing File Paths: Preventing Directory Traversal Attacks

Improper handling of file paths can lead to security vulnerabilities known as directory traversal attacks. These vulnerabilities allow an attacker to access arbitrary files on the server.

What is a Directory Traversal Attack?

A directory traversal attack occurs when an attacker manipulates file paths to access files outside the intended directory. For instance, if an application uses a user-provided file path without validation, an attacker could use a path like ../../etc/passwd to access sensitive files on the server.

Example of a Directory Traversal Attack:

  1. Vulnerable Code:
const filePath = `public/uploads/${req.params.fileName}`;
Enter fullscreen mode Exit fullscreen mode

Imagine you have a file download function that allows users to download files by providing an id. The application might construct the file path directly from the user input.

  1. Malicious Input:
/public/uploads/../../secret.txt
Enter fullscreen mode Exit fullscreen mode

Here an attacker could provide a malicious input like ../../secret.txt, leading to an unintended file access.

  1. Consequences:

If the application does not validate this input, it could expose sensitive files, such as configuration files or user data, to the attacker.

Example of preventing such kind of attacks

import path from 'path';
import fs from 'fs/promises';
import { RequestHandler, NextFunction } from 'express';

// Point: 1
const BASE_DIRECTORY = path.resolve(__dirname, 'public/uploads');

export const downloadAttachment: RequestHandler = async (req, res, next: NextFunction) => {
    // Point: 2
    const { fileName } = req.params; 

    // Point: 3
    const filePath = path.join(BASE_DIRECTORY, fileName);
    const resolvedPath = path.resolve(filePath);

    // Point: 4
    if (!resolvedPath.startsWith(BASE_DIRECTORY)) {
        return res.status(400).json({ message: "Invalid file path" });
    }

    try {
        // Point: 5
        await fs.access(resolvedPath);

        // Point: 6
        res.download(resolvedPath, path.basename(fileName), (err) => {
            if (err) {
                return next(err);
            }
        });
    } catch {
        // Point: 7
        return res.status(404).json({ message: "File not found" });
    }
};
Enter fullscreen mode Exit fullscreen mode

Key Points Explained:

  1. Base Directory Definition: Establishes a fixed directory for file uploads to restrict access.

  2. Extracting File Name: Retrieves the requested file name from the URL parameters.

  3. File Path Construction: Combines the base directory with the requested file name to create a full path.

  4. Path Validation: Ensures that the resolved file path is within the designated base directory to prevent unauthorized access.

  5. File Existence Check: Asynchronously checks if the file exists at the constructed path.

  6. File Download Handling: Initiates the file download and handles any errors that may occur during the process.

  7. Error Handling for Missing Files: Sends a 404 response if the requested file does not exist.


Acknowledgment: This document references information from PortSwigger Web Security and ChatGPT.


Top comments (0)