Building DevSecOps solutions using AWS, Terraform and Kubernetes

Prevent traversal attacks in Magento 2

  • 4th September 2021

What are they?

When a user attempts to provide a malicious path to access a restricted directory, then we call this a "Directory traversal attack".

These are examples of good paths:

  • '/var/www/html/pub/media/img1.png'
  • '/var/www/html/pub/media/../media/img1.png'

This is an example of a bad path:

  • '/var/www/html/pub/media/../../../../../../../etc/passwd'

So validating against the start of the path is not enough, we need to validate against the realpath()

How to validate good paths?

As a rule of thumb, never roll out your own security. If you have a modern framework at your disposal then it is much easier to follow their best practice.

Here is a simplified example of using a user supplied directory path in Magento 2. This controller uses the validatePath() function in Magento to help avoid traversal attacks.

Magento does the hard lifting of using PHP's built in realpath() function.

<?php

namespace MyNamespace\MyExtension\Controller\Index;

class Index extends \Magento\Framework\App\Action\Action
{
    protected $_pageFactory;
    protected $_dir;
    protected $_request;
    protected $_directoryResolver;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $pageFactory,
        \Magento\Framework\App\Request\Http $request,
        \Magento\Framework\Filesystem\DirectoryList $dir,
        \Magento\Framework\App\Filesystem\DirectoryResolver $directoryResolver
    ) {
        $this->_pageFactory = $pageFactory;
        $this->_request = $request;
        $this->_dir = $dir;
        $this->_directoryResolver = $directoryResolver;
        return parent::__construct($context);
    }

    public function execute()
    {
        $insecurePathToLocalFile = $this->_request->getParam('local_file_path');
        $realMediaDirectory = DirectoryList::MEDIA;

        // $insecurePathToLocalFile can't be trusted, so validate that it a real path inside the public media directory

        $trustedPath = null;
        if ($this->_directoryResolver->validatePath($insecurePathToLocalFile, $realMediaDirectory)) {
            $trustedPath = $insecurePathToLocalFile;
        } else {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('Potential traversal attack detected. Directory %1 is not under media folder', $insecurePathToLocalFile)
            );
        }

        // ...

        // Now we can do something with $trustedPath

        // ...

        return $this->_pageFactory->create();
    }
}

Rhuaridh

Please get in touch through my socials if you would like to ask any questions - I am always happy to speak tech!