Анализатор обнаружил, что данные, полученные из внешнего источника, используются в качестве путей к файлам или папкам без предварительной проверки. Это может стать причиной уязвимости приложения к атакам path traversal.
Атаки этого типа выделены в отдельную категорию рисков в OWASP Top 10 Application Security Risks 2017: A5:2017-Broken Access Control.
Рассмотрим пример:
HttpResponse response; HttpRequest request; private void SendUserFileContent(string userDirectory) { .... string userFileRelativePath = request.QueryString["relativePath"]; string fullPath = Path.Combine(userDirectory, userFileRelativePath); var content = File.ReadAllText(fullPath); .... response.Write(content); }
Данный метод производит отправку содержимого некоторого файла из заданной папки пользователя. Предполагается, что пользователь должен иметь возможность получения содержимого только файлов, хранящихся внутри этой папки.
В качестве относительного пути здесь используется значение, полученное из внешнего источника – 'Request.QueryString'. Отсутствие каких-либо проверок позволяет злоумышленнику получить доступ к содержимому любых файлов в системе.
Например, в папке каждого пользователя может храниться файл userInfo.xml, в котором содержится различная (в том числе конфиденциальная) информация (при этом код выполняется на системе Windows). Тогда для получения доступа к данным пользователя 'admin' злоумышленник может передать в 'Request. QueryString["relativePath"]' следующую строку:
..\admin\userInfo.xml
Для защиты от такой атаки недостаточно простой проверки на наличие '..\' в начале строки. К примеру, для получения тех же данных может передаваться и строка
someFolder\..\..\admin\userInfo.xml
Ещё одна возможность для атаки – передача абсолютного пути вместо относительного. Если один из аргументов 'Path.Combine' представляет собой абсолютный путь, то все ранее записанные аргументы игнорируются. К примеру, метод может быть вызван следующим образом:
Path.Combine("folder", "childFolder", "C:\Users\Admin\secret.txt")
В результате будет возвращена строка 'C:\Users\Admin\secret.txt '. Таким образом, отсутствие проверки входных данных позволяет злоумышленнику получить доступ к любому файлу в системе. Более подробно атаки типа path traversal и способы их проведения описаны на официальном сайте OWASP по ссылке.
Для обеспечения защиты от path traversal необходимо применять различные средства проверки входных данных. В примере, описанном выше, можно использовать проверку на наличие подстрок ":" и "..\":
HttpResponse response; HttpRequest request; private void SendUserFileContent(string userDirectory) { .... string userFileRelativePath = request.QueryString["relativePath"]; if ( !userFileRelativePath.Contains(":") && !userFileRelativePath.Contains(@"..\")) { string fullPath = Path.Combine(userDirectory, userFileRelativePath); var content = File.ReadAllText(fullPath); .... response.Write(content); } else { .... } }
Анализатор также считает источниками небезопасных данных параметры методов, доступных из других сборок. Эта тема подробно раскрыта в заметке "Почему важно проверять значения параметров общедоступных методов".
Рассмотрим пример кода, выполняющегося на ОС Windows:
public class UserFilesManager { private const string UsersDirectoryAbsolutePath = ....; private HttpResponse response; private string userName; public void WriteUserFile(string relativePath) { string path = Path.Combine(UsersDirectoryAbsolutePath, userName, relativePath); WriteFile(path); } private void WriteFile(string absolutePath) { response.Write(File.ReadAllText(absolutePath)); } }
Анализатор сформирует предупреждение низкого уровня достоверности на вызов метода 'WriteFile' внутри 'WriteUserFile'. После вызова 'Path.Combine' небезопасные данные из 'relativePath' передаются в 'path', после чего выступают в качестве аргумента вызова 'WriteFile', где используются в качестве пути. Таким образом, пользовательский ввод может попасть в метод 'File.ReadAllText' без проверки, из-за чего данный код уязвим к path traversal.
Для защиты от атаки необходимо проводить валидацию параметров. В данном случае важно провести её до вызова 'Path.Combine', так как возвращаемое им значение в любом случае будет абсолютным путём:
public void WriteUserFile(string relativePath) { if (relativePath.Contains(":") || relativePath.Contains(@"..\")) { .... return; } string path = Path.Combine(UsersDirectoryAbsolutePath, userName, relativePath); WriteFile(path); }
Данная диагностика классифицируется как:
|
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V5609. |