Дэвид Лебланк - 19 смертных грехов, угрожающих безопасности программ
□ AUX
□ CON
□ LPT1
□ PRN.TXT
□....AUX
□ /dev/null
□ /dev/random
□ /dev/urandom
□ ../../dev/random
□ \servernamec$
□ \servernameipc$
Проверьте, не зависнет ли приложение, не завершится ли оно аварийно. Если это случится, значит, вы нашли место, где программа ожидает только «честного» имени файла! Посмотрите также, можете ли вы обратиться к файлам, к которым не должны иметь доступа, например к файлу /etc/passwd в Unix.
Как и для многих других грехов, описанных в этой книге, наиболее продуктивный способ выявления ошибок – это качественный анализ кода с точки зрения безопасности.Примеры из реальной жизни
Следующие примеры взяты из базы данных CVE (http://cve.mitre.org).
CAN–2005–0004
Сценарий mysqlaccess, входящий во многие версии MySQL, позволяет локальному пользователю затереть произвольный файл или прочитать содержимое временных файлов путем атаки с организацией символической ссылки на временный файл. Частично в ошибке повинна функция POSIX::tmpnam, которая возвращает предсказуемое имя временного файла! Если противник сможет создать символическую ссылку на конфиденциальный файл с таким же именем, то во время запуска сценария привилегированным пользователем этот файл будет затерт.
На странице http://lists.mysql.com/internals/20600; имеется заплата, которая устраняет ошибку за счет использования описателей вместо имен файлов и модуля File::Temp вместо POSIX::tmpnam.
CAN–2005–0799
Это еще одна ошибка в MySQL, на этот раз затрагивающая только пользователей Windows. Уязвимость связана с неправильной обработкой зарезервированных еще со времен MS–DOS имен устройств. Если указать специально подобранное имя базы данных, то можно вызвать крах сервера. Риск невелик, но привилегированный пользователь может «уронить» сервер, введя такую команду:
...use PRN
В результате открывается порт принтера по умолчанию, а не реальный файл.
CAN–2004–0452 и CAN–2004–0448
Обе ошибки связаны с гонкой, которая возникает при работе функции File::Path::rmtree в Perl. Для эксплуатации той и другой следует подменить существующий каталог в удаляемом дереве символической ссылкой на произвольный файл. Для устранения ошибки понадобилось значительно переработать – практически полностью переписать – функцию rmtree. Заплата имеется на странице http://ftp.debian.Org/debian/pool/main/p/perl/perl_5.8.4–8.diff.gz.
CVE–2004–0115 Microsoft Virtual PC для Macintosh
Процесс VirtualPC_Services, являющийся частью продукта Microsoft Virtual PC для версий от Мае 6.0 до Мае 6.1, позволяет локальному противнику усекать и перезаписывать произвольные файлы и потенциально открывает возможность выполнить произвольный код за счет атаки путем организации символической ссылки на временный файл /tmp/VPCServices_Log. Программа без каких бы то ни было проверок открывает файл с таким именем, даже если он является символической ссылкой. Если ссылка ведет на другой файл, он переписывается. Представьте, как будет смешно, если этот «другой файл» есть /mach_kernel!
Искупление греха
Для искупления греха в программе придерживайтесь следующих правил:
□ По возможности храните все файлы, нужные приложению, в таком месте, которое противник никак не может контролировать. Даже если программа ничего не проверяет, но безопасность ее рабочего каталога гарантируется, то большая часть проблем исчезнет сама собой. Обычно для этого создается «безопасный каталог», доступный только приложению. Часто самый простой способ обеспечить контроль доступа на уровне приложения заключается в том, чтобы создать специального пользователя, от имени которого приложение будет работать. Если этого не делать, то все приложения, работающие от имени того же пользователя, что и ваше, смогут манипулировать создаваемыми им файлами.
□ Никогда не используйте одно и то же имя файла для выполнения более одной операции над файлом; если первая операция выполнилась успешно, то всем последующим передавайте описатель или дескриптор файла.
□ Вычисляйте путь к файлу, к которому собираетесь обратиться. Для этого следуйте по символическим ссылкам и выполняйте проход по каталогам. Лишь после вычисления окончательного имени применяйте к нему проверки.
□ Если вы вынуждены открывать временный файл в общедоступном каталоге, то самый надежный способ сформировать его имя – это получить восемь байтов от генератора случайных чисел криптографического качества (см. грех 18) и представить их в кодировке base64. Если в результирующей строке окажется символ '/', замените его символом ',' или еще каким–нибудь безобидным – это и будет имя файла.
□ Там, где оправдано (читай: если сомневаетесь), блокируйте файл при первом доступе к нему или в момент создания.
□ Если вы точно знаете, что файл должен быть новым и иметь нулевую длину, усекайте его. Тем самым вы предотвратите попытку противника подсунуть программе предварительно заполненный временный файл.
□ Никогда не доверяйте именам файлов, контролируемым кем–то другим.
□ Проверьте, что имя относится именно к файлу, а не к каналу, устройству или символической ссылке.
Имея все это в виду, обратимся к примерам.
Искупление греха в Perl
Пользуйтесь описателем, а не именем файла, чтобы проверить его существование, а затем открыть.
...#!/usr/bin/perl
my $file = "$ENV{HOME}/.config";
if (open(FILE, "< $file")) {
read_config(*FILE) if is_accessible(*FILE);
}
Искупление греха в C/C++для Unix
В некоторых системах имеется библиотечная функция realpath(), существенно облегчающая вашу задачу. Но с ней связаны два «подводных камня». Во–первых, она небезопасна относительно потоков, поэтому вокруг нее придется поставить какой–то замок, если есть шанс, что функция будет вызываться из разных потоков. Во–вторых, на некоторых платформах она ведет себя неожиданно. Вот как выглядит сигнатура этой функции:
char* realpath (const char *original path, char resolved path[PATH MAX]);
В случае успеха она возвращает указатель на второй параметр, а в случае ошибки – NULL.
Идея заключалась в том, что вы передаете потенциально небезопасный путь, а функция следует по символическим ссылкам, удаляет повторяющиеся точки и т. д. Но в некоторых системах результат будет абсолютным путем, только если первый параметр – это абсолютный путь. Печально, но факт. Чтобы получить переносимый код, необходимо дописать в начало путь к текущему рабочему каталогу. Получить этот путь можно с помощью функции getcwd().
Искупление греха в C/C++для Windows
В следующем фрагменте имя файла получено от не заслуживающего доверия пользователя. Проверяется, соответствует ли оно настоящему файлу на диске; если нет, программа возвращает ошибку.
Примечание. Если хотите быть еще «круче», можете проверить также, что длина имени файла укладывается в допустимые пределы.
...HANDLE hFile = CreateFile(pFullPathName,
0, 0, NULL,
OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION,
NULL);
if (hFile != INVALID_HANDLE_VALUE &&
GetFileType(hFile) == FILE_TYPE_DISK) {
// похоже на обычный файл!
}
Получение места нахождения временного каталога пользователя
Хранить временные файлы в каталоге конкретного пользователя безопаснее, чем в общедоступном месте. Получить путь к частному каталогу пользователя для хранения временных файлов можно с помощью переменной окружения ТМР.
Искупление греха в .NET
В управляемом коде, написанном на таких языках, как С# или VB.NET (в частности, в среде ASP.NET), получить имя временного файла можно, как описано ниже. В случае ASP.NET временные файлы сохраняются в каталоге, определяемом по самому процессу, в контексте которого исполняется ASP.NET.
С#
...using System.IO;
string tempName = Path.GetTempFileName();
VB.NET
...Imports System.IO;
Dim tempName = Path.GetTempFileName
Managed С++
...using namespace System::IO;
String ^s = Path::GetTempFileName();
Дополнительные защитные меры
При работе с сервером Apache проверьте, чтобы в файле httpd.conf не было излишних директив FollowSymLink. Правда, когда эта директива удаляется, производительность слегка падает.
Другие ресурсы
□ «Secure programmer: Prevent race conditions» by David Wheeler: www–106. ibm.com/developerworks/linux/library/l–sprace.html?ca=dgr–lnxw07RACE
□ Building Secure Software by John Viega and Gary McGraw (Addison Wesley), Chapter 9, «Race Conditions»
□ Writing Secure Code, Second Edition by Michael Howard and David C. LeBlanc (Microsoft Press, 2002), Chapter 11 «Canonical Representation Issues»
□ Perl 5 Reference Guide в формате HTML от Рекса Суэйна: www.rexswain.com/ perl5.html#filetest
□ «Secure Programming for Linux and Unix HOWTO – Creating Secure Soft–ware» by David Wheeler: www.dwheeler.com/secure–programs/
Резюме
Рекомендуется
□ Тщательно проверяйте, что вы собираетесь принять в качестве имени файла.
Не рекомендуется
□ Не принимайте слепо имя файла, считая, что оно непременно соответствует хорошему файлу. Особенно это относится к серверам.
Стоит подумать
□ О хранении временных файлов в каталоге, принадлежащем конкретному пользователю, а не в общедоступном. Дополнительное преимущество такого решения – в том, что приложение может работать с минимальными привилегиями, поскольку всякий пользователь имеет полный доступ к собственному каталогу, тогда как для доступа к системным каталогам для временных файлов иногда необходимы привилегии администратора.