10.6.2. Конкуренция доступа к каталогу /tmp
10.6.2. Конкуренция доступа к каталогу /tmp
Другая распространенная проблема безопасности связана с созданием файлов с предсказуемыми именами, в основном в каталоге /tmp. Предположим, что программа prog, выполняющаяся от имени пользователя root, всегда создает временный файл /tmp/prog и помещает в него важную информацию. Тогда злоумышленник может заранее создать символическую ссылку /tmp/prog на любой другой файл в системе. Когда программа попытается создать временный файл, функция open() завершится успешно, но в действительности вернет дескриптор символической ссылки. Любые данные, записываемые во временный файл, окажутся перенаправленными в файл злоумышленника.
В такой ситуации говорят о конкуренции. Она неявно существует между автором программы и хакером. Кто первым успеет создать временный файл, тот и победит.
Посредством этой атаки часто уничтожаются системные файлы. Создав нужную символическую ссылку, хакер может заставить программу, выполняющуюся с правами суперпользователя, затереть важный системный файл, например /etc/passwd.
Один из способов избежать такой атаки — создавать временные файлы со случайными именами. Например, можно прочитать из устройства /dev/random случайные данные и включить их в имя файла. Это усложнит задачу хакеру, но не остановит его полностью. Он может попытаться создать большое число символических ссылок с потенциально верными именами. Даже если их будет 10000, одна верная догадка приведет к непоправимому.
Другой подход заключается в вызове функции open() с флагом O_EXCL. Он заставляет функцию завершиться неудачей, если обнаруживается факт существования файла. К сожалению, это не срабатывает, если программа работает через NFS. Нельзя заранее предсказать, в какой файловой системе будет находиться программа, поэтому рассчитывать только на флаг O_EXCL нельзя.
В разделе 2.1.7, "Временные файлы", рассказывалось о применении функции mkstemp() для создания временных файлов. К сожалению, в Linux эта функция открывает файл с флагом O_EXCL после того, как было выбрано трудно угадываемое имя. Другими словами, применять функцию небезопасно, если каталог /tmp смонтирован через NFS.[35]
Прием, который всегда работает, заключается в вызове функции lstat() (рассматривается в приложении Б, "Низкоуровневый ввод-вывод") для созданного файла. Она отличается от функции stat() тем, что возвращает информацию о самой символической ссылке, а не о файле, на который она ссылается. Если функция сообщает, что новый файл является обычным файлом, а не символической ссылкой, и принадлежит владельцу программы, то все в порядке.
В листинге 10.5 представлена функция, которая пытается безопасно открыть файл в каталоге /tmp. Возможно, у этой функции есть свои слабости. Мы не рекомендуем читателям включать показанный код в свои программы без дополнительной экспертизы, просто мы хотим убедить читателей в том, что создание безопасных приложений — непростая задача,
Листинг 10.5. (temp-file.c) Безопасное создание временного файла
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
/* Функция возвращает дескриптор созданного временного файла.
Файл будет доступен для чтения и записи только тому
пользователю, чей идентификатор равен эффективному
идентификатору текущего процесса. Если файл не удалось создать,
возвращается -1. */
int secure_temp_file() {
/* Этот дескриптор ссылается на устройство /dev/random, из
которого будут получены случайные данные. */
static int random_fd = -1;
/* Случайное целое число. */
unsigned int random;
/* Буфер для преобразования числа в строку. */
char filename[128];
/* дескриптор создаваемого временного файла. */
int fd;
/* информация о созданном файле. */
struct stat stat_buf;
/* Если устройство /dev/random еще не было открыто,
открываем его. */
if (random_fd == -1) {
/* Открытие устройства /dev/random. Предполагается, что
это устройство является источником случайных данных,
а не файлом, созданным хакером. */
random_fd = open("/dev/random", O_RDONLY);
/* Если устройство /dev/random не удалось открыть,
завершаем работу. */
if (random_fd == -1)
return -1;
}
/* чтение целого числа из устройства /dev/random. */
if (read(random_fd, &random, sizeof(random)) != sizeof(random))
return -1;
/* Формирование имени файла из случайного числа. */
sprintf(filename, "/tmp/%u", random);
/* Попытка открытия файла. */
fd = open(filename,
/* Используем флаг O_EXCL. */
O_RDWR | O_CREAT | O_EXCL,
/* Разрешаем доступ только владельцу файла. "/
S_IRUSR | S_IWUSR);
if (fd == -1)
return -1;
/* Вызываем функцию lstat(), чтобы проверить, не является ли
файл символической ссылкой */
if (lstat(filename, &stat_buf) == -1)
return -1;
/* Если файл не является обычным файлом, кто-то пытается
обмануть нас. */
if (!S_ISREG(stat_buf.st_mode))
return -1;
/* Если файл нам не принадлежит, то, возможно, кто-то успел
подменить его. */
if (stat_buf.st_uid != geteuid() ||
stat_buf.st_gid != getegid())
return -1;
/* Если у файла установлены дополнительные биты доступа,
что-то не так. */
if ((stat_buf.st_mode & ~(S_IRUSR | S_IWUSR)) != 0)
return -1;
return fd;
}
Рассмотренная функция вызывает функцию open() для создания файла, а затем функцию lstat() для проверки того, что файл не является символической ссылкой. Внимательный читатель обнаружит здесь то, что называется состоянием гонки. Между вызовами функций open() и lstat() злоумышленник может успеть удалить файл и заменить его символической ссылкой. Это не вызовет разрушающих последствий, но приведет к тому, что функция завершится ошибкой и не сможет выполнить свою задачу. Такой тип атаки называется отказом от обслуживания.
В данной ситуации на помощь приходит sticky-бит. Поскольку для каталога /tmp он установлен, никто не сможет удалить файлы из этого каталога, не будучи их владельцем. Естественно, пользователю root разрешено делать все что угодно, но если хакер сумел получить привилегии суперпользователя, вас уже ничто не спасет.
Грамотный системный администратор не допустит, чтобы каталог /tmp был смонтирован через NFS, поэтому на практике можно пользоваться функцией mkstemp(). Если же речь идет о другом каталоге, то нельзя ни доверять флагу O_EXCL, ни рассчитывать на установку sticky-бита.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
14.4.1. Прохождение по каталогу
14.4.1. Прохождение по каталогу Если требуется перечитать содержимое каталога, уже открытого opendir(), с помощью rewinddir() структура DIR сбрасывается, чтобы следующий вызов readdir() мог вернуть первый файл в каталоге.#include <dirent.h>int rewinddir(DIR *
Права доступа
Права доступа Как уже обсуждалось в предыдущей главе, каждый процесс имеет четыре пользовательских идентификатора — UID, GID, EUID и EGID. В то время как UID и GID определяют реального владельца процесса, EUID и EGID определяют права доступа процесса к файлам в процессе выполнения. В
7.3. Права доступа
7.3. Права доступа В данном разделе нам предстоит познакомиться с основными параметрами файла конфигурации /etc/httpd/conf/httpd.conf. Они отвечают за права доступа, относящиеся к директориям, и имеют следующий вид:<Directory /var/www/html> Order allow,deny Allow from all</Directory>или, например:<Location
15.5.7. Параметры доступа
15.5.7. Параметры доступа http_access allow|deny aclnameРазрешать доступ к прокси по HTTP. icp_access allow | deny aclnameРазрешать доступ к прокси по ICP. miss_access allow | deny aclnameРазрешить получать ответ MISS от вас. cache_peer_access cache-host allow|deny aclnameОграничить запросы к данному соседу — расширение для cache_peer_domain. proxy_auth_realm
18.6.1. Параметры доступа
18.6.1. Параметры доступа Параметры доступа в файле squid.conf задаются следующими директивами:? http_access allow | deny aclname — разрешать доступ к прокси по HTTP;? icp_access allow | deny aclname — разрешать доступ к прокси по ICP;? miss_access allow | deny aclname — разрешать получать ответ MISS («не найден») от
Библиотеки доступа
Библиотеки доступа В мире приложений баз данных сложилось несколько устоявшихся подходов к работе с базами данных. Для InterBase можно выделить около пяти таких подходов: это работа с базой данных через BDE (Borland Database Engine, см. глоссарий), использование ODBC, применение OLE DB (ADO),
Безопасность доступа
Безопасность доступа Для новичков не всегда бывает очевидным, что существует разница между доступом к серверу и безопасностью базы данных. Когда вы соединяетесь с базой данных Firebird, используя isql или ваш любимый инструмент администратора, вы всегда указываете имя
Способ доступа
Способ доступа Способ доступа может быть READ WRITE (чтение/запись) или READ ONLY (только чтение). Транзакция READ WRITE может выбирать, добавлять, изменять и удалять данные. Транзакция READ ONLY может только выбирать данные.Способом доступа по умолчанию является READ WRITE.! ! !СОВЕТ. Одним из
Дмитрий Шабанов: Конкуренция или контроль? Дмитрий Шабанов
Дмитрий Шабанов: Конкуренция или контроль? Дмитрий Шабанов Опубликовано 14 июня 2012 года Как должна быть устроена система, чтобы её функционирование было оптимальным? Этот вопрос весьма непрост. Мы значительно лучше прослеживаем логические цепочки,
Упрощенный протокол доступа к каталогу LDAP
Упрощенный протокол доступа к каталогу LDAP Использование протокола DAP оказалось слишком обременительным для многих клиентских приложений. В результате в Университете штата Мичиган был разработан упрощенный протокол доступа к каталогу LDAP. Протокол LDAP был