diff options
Diffstat (limited to 'ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml')
-rw-r--r-- | ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml | 439 |
1 files changed, 0 insertions, 439 deletions
diff --git a/ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml b/ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml deleted file mode 100644 index 7006818a5f..0000000000 --- a/ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml +++ /dev/null @@ -1,439 +0,0 @@ -<!-- - The FreeBSD Russian Documentation Project - - $FreeBSD$ - $FreeBSDru: frdp/doc/ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml,v 1.1 2001/02/19 06:57:41 andy Exp $ - - Original revision: 1.1 ---> - -<chapter id="secure"> - <title>Безопасное программирование</title> - - <para>Эту главу написал Мюррей Стокели (Murray Stokely).</para> - - <sect1> - <title>Обзор</title> - - <para>Эта глава описывает некоторые из проблем обеспечения безопасности, - которые десятилетиями преследовали программистов Unix, а также - несколько новых доступных инструментов, помогающих программистам - избежать написания небезопасного кода.</para> - </sect1> - - <sect1 id="secure-philosophy"> - <title>Методология обеспечения безопасности</title> - - <para>Написание безопасных приложений требует весьма критического и - пессимистического взгляда на жизнь. Приложения должны работать по - принципу <quote>наименьших привилегий</quote>, при котором никакой - процесс не должен работать с привилегиями, превышающими минимально - необходимый для выполнения своих функций минимум. Ранее проверенный - код должен использоваться там, где только это возможно для избежания - общих ошибок, которые могли быть уже исправлены другими.</para> - - <para>Одной из неприятностей в среде Unix является легкость в - предположении безопасности этого окружения. Приложения никогда не - должны верить пользовательскому вводу (во всех его формах), ресурсам - системы, межпроцессному взаимодействию или времени выполнения событий. - Процессы Unix выполняются не синхронно, так что логические операции - редко бывают атомарными.</para> - </sect1> - - <sect1> - <title>Переполнения буфера</title> - - <para>Переполнения буфера появились вместе с появление архитектуры - Фон-Неймана <xref linkend="COD">. Впервые широкую известность они - получили в 1988 году вместе с Интернет-червем Мурса (Moorse). К - сожалению, точно такая же атака повторилась и в наши дни. Из 17 - бюллетеней безопасности CERT за 1999 год, 10 были непосредственно - вызваны ошибкам в программном обеспечении, связанным с переполнениями - буфера. Самые распространенные типы атак с использованием переполнения - буфера основаны на разрушении стека.</para> - - <para>Самые современные вычислительные системы используют стек для - передачи аргументов процедурам и сохранения локальных переменных. Стек - является буфером типа LIFO (последним вошел первым вышел) в верхней - части области памяти процесса. Когда программа вызывает функцию, - создается новая "граница стека". Эта граница состоит из аргументов, - переданных в функцию, а также динамического количества пространства - локальных переменных. "Указатель стека" является регистром, хранящим - текущее положение вершины стека. Так как это значение постоянно - меняется вместе с помещением новых значений на вершину стека, многие - реализации также предусматривают "указатель границы", который - расположен около начала стека, так что локальные переменные можно легко - адресовать относительно этого значения. <xref linkend="COD"> Адрес - возврата из функции также сохраняется в стеке, и это является причиной - нарушений безопасности, связанных с переполнением стека, так как - перезаписывание локальной переменной в функции может изменить адрес - возврата из этой функции, потенциально позволяя злоумышленнику - выполнить любой код.</para> - - <para>Хотя атаки с переполнением стека являются замыми распространенными, - стек можно также перезаписать при помощи атаки, основанной на выделении - памяти (malloc/free) из "кучи".</para> - - <para>Как и во многих других языках программирования, в C не выполняется - автоматической проверки границ в массивах или указателях. Кроме того, - стандартная библиотека C полна очень опасных функций.</para> - - <informaltable> - <tgroup cols=2> - <tbody> - <row> - <entry><function>strcpy</function>(char *dest, const char - *src)</entry> - <entry><simpara>Может переполнить целевой буфер</simpara></entry> - </row> - - <row> - <entry><function>strcat</function>(char *dest, const char - *src)</entry> - <entry><simpara>Может переполнить целевой буфер</simpara></entry> - </row> - - <row> - <entry><function>getwd</function>(char *buf)</entry> - <entry><simpara>Может переполнить буфер buf</simpara></entry> - </row> - - <row> - <entry><function>gets</function>(char *s)</entry> - <entry><simpara>Может переполнить буфер s</simpara></entry> - </row> - - <row> - <entry><function>[vf]scanf</function>(const char *format, - ...)</entry> - <entry><simpara>Может переполнить свои аргументы.</simpara></entry> - </row> - - <row> - <entry><function>realpath</function>(char *path, char - resolved_path[])</entry> - <entry><simpara>Может переполнить буфер path</simpara></entry> - </row> - - <row> - <entry><function>[v]sprintf</function>(char *str, const char - *format, ...)</entry> - <entry><simpara>Может переполнить буфер str.</simpara></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <sect2> - <title>Пример переполнения буфера</title> - - <para>В следующем примере кода имеется ошибка переполнения буфера, - предназначенная для перезаписи адреса возврата и обхода инструкции, - следующей непосредственно за вызовом функции. (По мотивам <xref - linkend="Phrack">)</para> - - <programlisting> -#include <sgmltag>stdio.h</sgmltag> - -void manipulate(char *buffer) { - char newbuffer[80]; - strcpy(newbuffer,buffer); -} - -int main() { - char ch,buffer[4096]; - int i=0; - - while ((buffer[i++] = getchar()) != '\n') {}; - - i=1; - manipulate(buffer); - i=2; - printf("The value of i is : %d\n",i); - return 0; -} - </programlisting> - - <para>Давайте посмотрим, как будет выглядеть образ процесса, если в - нашу маленькую программу мы введем 160 пробелов.</para> - - <para>[XXX figure here!]</para> - - <para>Очевидно, что для выполнения реальных инструкций (таких, как - exec(/bin/sh)), может быть придуман более вредоносный ввод.</para> - </sect2> - - <sect2> - <title>Как избежать переполнений буфера</title> - - <para>Самым прямолинейным решением проблемы переполнения стека является - использование только памяти фиксированного размера и функций - копирования строк. Функции <function>strncpy</function> и - <function>strncat</function> являются частью стандартной библиотеки - C. Эти функции будут копировать не более указанного количества байт - из исходной строки в целевую. Однако у этих функций есть несколько - проблем. Ни одна из них не гарантирует наличие символа NUL, если - размер входного буфера больше, чем целевого. Параметр длины также - по-разному используется в strncpy и strncat, так что для - программистов легко запутаться в правильном использовании. Есть - также и значительная потеря производительности по сравнению с - <function>strcpy</function> при копировании короткой строки в большой - буфер, потому что <function>strncpy</function> заполняет символами - NUL пространство до указанной длины.</para> - - <para>Для избежания этих проблем в OpenBSD была сделана другая - реализация копирования памяти. Функции <function>strlcpy</function> - и <function>strlcat</function> гарантируют, что они они всегда - терминируют целевую строку нулевым символом, если им будет передан - аргумент ненулевой длины. Более подробная информация об этом - находится здесь <xref linkend="OpenBSD">. Инструкции OpenBSD - <function>strlcpy</function> и <function>strlcat</function> были - во FreeBSD начиная с 3.5.</para> - - <sect3> - <title>Вкомпилированная проверка границ во время выполнения</title> - - <para>К несчастью, все еще широко используется очень большой объем - кода, который слепо копирует память без использования только что - рассмотренных функций с проверкой границ. Однако есть другое - решение. Существует несколько расширений к компилятору и - библиотекам C/C++ для выполнения контроля границ во время - выполнения.</para> - - <para>Одним из таких добавлений является StackGuard, который - реализован как маленький патч к генератору кода gcc. Согласно - сайту StackGuard, http://immunix.org/stackguard.html: - <blockquote> - <para>"StackGuard распознает и защищает стек от атак, - не позволяя изменять адрес возврата в стеке. При вызове - функции StackGuard помещает вслед за адресом возврата - сигнальное слово. Если после возврата из функции оно - оказывается измененным, то была попытка выполнить атаку на - стек, и программа отвечает на это генерацией сообщения о - злоумышленнике в системном журнале, а затем прекращает - работу."</para> - </blockquote> - - <blockquote> - <para>"StackGuard реализован в виде маленького патча к генератору - кода gcc, а именно процедур function_prolog() и - function_epilog(). function_prolog() усовершенствована для - создания пометок в стеке при начале работы функции, а - function_epilog() проверяет челостность пометки при возврате из - функции. Таким образом, любые попытки изменения адреса - возврата определяются до возврата из функции."</para> - </blockquote> - </para> - - <para>Перекомпиляция вашего приложения со StackGuard является - эффективным способом остановить большинство атак переполнений - буфера, но все же полностью это проблемы не решает.</para> - </sect3> - - <sect3> - <title>Проверка границ во время выполнения с использованием - библиотек.</title> - - <para>Механизмы на основе компилятора полностью бесполезны для - программного обеспечения, поставляемого в двоичном виде, которое вы - не можете перекомпилировать. В этих ситуациях имеется некоторое - количество библиотек, в которых реализованы небезопасные функции - библиотеки C (<function>strcpy</function>, - <function>fscanf</function>, <function>getwd</function>, и так - далее..), обеспечивающие невозможность записи после указателя - стека.</para> - - <itemizedlist> - <listitem><simpara>libsafe</simpara></listitem> - <listitem><simpara>libverify</simpara></listitem> - <listitem><simpara>libparnoia</simpara></listitem> - </itemizedlist> - - <para>К сожалению, эти защиты имеют некоторое количество недостатков. - Эти библиотеки могут защитить только против малого количества - проблем, и не могут исправить реальные проблемы. Эти защиты могут - не сработать, если приложение скомпилировано с параметром - -fomit-frame-pointer. К тому же переменные окружения LD_PRELOAD и - LD_LIBRARY_PATH могут быть переопределены/сняты - пользователем.</para> - </sect3> - </sect2> - </sect1> - - <sect1> - <title>Проблемы с установленным битом UID</title> - - <para>Имеется по крайней мере 6 различных идентификаторов (ID), связанных - с любым взятым процессом. Поэтому вы должны быть очень осторожны с - тем, какие права имеет ваш процесс в каждый момент времени. В - частности, все seteuid-приложения должны понижать свои привилегии, как - только в них отпадает необходимость.</para> - - <para>ID реального пользователя может быть изменен только процессом - администратора. Программа <application>login</application> - устанавливает его, когда пользователь входит в систему, и он редко - меняется.</para> - - <para>Эффективный ID пользователя устанавливается функциями - <function>exec()</function>, если у программы установлен бит seteuidt. - Приложение может выполнить вызов <function>seteuid()</function> в любой - момент для установки эффективного ID пользователя в значение реального - ID пользователя или сохраняемого set-user-ID. Когда эффективный ID - пользователя устанавливается функциями <function>exec()</function>, его - предыдущее значение сохраняется в сохраняемом set-user-ID.</para> - </sect1> - - <sect1 id="chroot"> - <title>Ограничение среды работы вашей программы</title> - - <para>Традиционно используемым методом ограничения доступа к процессу - является использование системного вызова <function>chroot()</function>. - Этот системный вызов меняет корневой каталог, относительно которого - определяются все остальные пути в самом процессе и всех порожденных ими - процессах. Для того, чтобы этот вызов был выполнен успешно, процесс - должен иметь право на выполнение (поиск) каталога, о котором идет речь. - Новая среда реально не вступит в силу, пока вы не выполните вызов - <function>chdir()</function> в вашей новой среде. Следует также - отметить, что процесс может с легкостью выйти из chroot-среды, если он - имеет привилегии администратора. Это может быть достигнуто созданием - файлов устройств для чтения памяти ядра, подключением отладчика к - процессу вне узницы и многими другими способами.</para> - - <para>Поведение системного вызова <function>chroot()</function> можно - некоторым образом контролировать <command>sysctl</command>-переменной - kern.chroot_allow_open_directories. Когда эта переменная установлена в - 0, <function>chroot()</function> не сработает с ошибкой EPERM, если - есть какие-либо открытые каталоги. Если она установлена в значение по - умолчанию, равное 1, то <function>chroot()</function> не сработает с - ошибкой EPERM, если есть какие-либо открытые каталоги и процесс уже - подвергнут вызову <function>chroot()</function>. Для всех других - значений проверка открытости каталогов будет полностью опущена.</para> - - <sect2> - <title>Функциональность джейлов (jail) во FreeBSD</title> - - <para>Концепция джейлов (Jail) расширяет возможности - <function>chroot()</function>, ограничивая власть администратора - созданием настоящих `виртуальных серверов'. Как только тюремная - камера создана, все сетевые коммуникации должны осуществляться через - выделенный адрес IP, а сила "привилегий пользователя root" в этой - тюрьме довольно ограничена.</para> - - <para>При работе внутри тюрьмы, любые проверки силы администратора в - ядре при помощи вызова <function>suser()</function> будут - оканчиваться неудачно. Однако некоторые вызовы к - <function>suser()</function> были изменены на новый интерфейс - <function>suser_xxx()</function>. Эта функция отвечает за - распознание и разрешение доступа к власти администратора для - процессов, не находящихся в неволе.</para> - - <para>Процесс администратора внутри среды джейла имеет право:</para> - - <itemizedlist> - <listitem><simpara>Манипулировать привилегиями с помощью - <function>setuid</function>, <function>seteuid</function>, - <function>setgid</function>, <function>setegid</function>, - <function>setgroups</function>, <function>setreuid</function>, - <function>setregid</function> и - <function>setlogin</function></simpara> - </listitem> - - <listitem><simpara>Устанавливать ограничения на использование - ресурсов при помощи - <function>setrlimit</function></simpara> - </listitem> - - <listitem><simpara>Модифицировать некоторые sysctl-переменные - (kern.hostname)</simpara> - </listitem> - - <listitem><simpara><function>chroot()</function></simpara></listitem> - - <listitem><simpara>Устанавливать следующие флаги на vnode: - <function>chflags</function>, - <function>fchflags</function></simpara> - </listitem> - - <listitem><simpara>Устанавливать такие атрибуты vnode, как права - доступа к файлу, изменять его владельца, группу, размер, время - доступа и модификации.</simpara> - </listitem> - - <listitem><simpara>Осуществлять привязку к привилегированному порту - в области портов Интернет (порты с номерами < 1024)</simpara> - </listitem> - </itemizedlist> - - <para><function>Jail</function> является очень полезным инструментом - для запуска приложений в защищенном окружении, но есть и некоторые - недостатки. На текущий момент к формату - <function>suser_xxx</function> не преобразованы механизмы IPC, так - что такие приложения, как MySQL, не могут работать в джейле. Права - администратора могут имеет малую силу внутри джейла, но нет - способа определить, что значит "малую".</para> - </sect2> - - <sect2> - <title>Возможности процессов POSIX.1e</title> - - <para>Posix выпустил рабочий документ, который добавляет аудит событий, - списки управления доступом, тонко настраиваемые привилегии, метки - информации и жесткое управление доступом.</para> - - <para>Этот документ находится в работе и находится в центре внимания - проекта <ulink url="http://www.trustedbsd.org">TrustedBSD</ulink>. - Некоторая начальная функциональность уже была добавлена во - FreeBSD-current (cap_set_proc(3)).</para> - </sect2> - </sect1> - - <sect1> - <title>Доверие</title> - - <para>Приложение никогда не должно полагать, что среда пользователя - безопасна. Сюда включается (но этим не ограничено): ввод пользователя, - сигналы, переменные среды, ресурсы, IPC, отображаемая в файл память, - рабочий каталог файловой системы, дескрипторы файлов, число открытых - файлов и прочее.</para> - - <para>Никогда не думайте, что сможете предусмотреть все формы - неправильного ввода, который может дать пользователь. Вместо этого - ваше приложение должно осуществлять позитивную фильтрацию, пропуская - только конечное множество возможных вариантов ввода, которые вы - считаете безопасными. Неполная праверка данных была причиной многих - нарушений защиты, особенно CGI-скриптов на веб-сайтах. Для имен файлов - вам нужно уделять особое внимание путям ("../", "/"), символическим - ссылкам и экранирующим символам оболочки.</para> - - <para>В perl имеется такая очень полезная вещь, как "безупречный" (taint) - режим, который можно использовать для запрещения скриптам использовать - данные, порожденные вне программы, не безопасным способом. Этот режим - проверяет аргументы командной строки, переменные окружения, информацию - локализации, результаты некоторых системных вызовов - (<function>readdir()</function>, <function>readlink()</function>, - <function>getpwxxx()</function> и весь файловый ввод.</para> - </sect1> - - <sect1> - <title>Неожиданное поведение</title> - - <para>Неожиданное поведение - это аномальное поведение, вызванное - непредусмотренной зависимостью от относительной последовательности - событий. Другими словами, программист неправильно предположил, что - некоторое событие всегда случается перед другим.</para> - - <para>Некоторые из широко распространенных причин возникновения таких - проблем являются сигналы, проверки доступа и открытия файлов. Сигналы - по своей природе являются асинхронными событиями, так что по отношению - к ним нужно проявлять особое внимание. Проверка доступа функцией - <function>access(2)</function> с последующим вызовом - <function>open(2)</function> полностью не атомарно. Пользователи могут - переместить файлы в промежутке между двумя вызовами. Вместо этого - привилегированное приложение должно выполнить - <function>seteuid()</function>, а затем сразу вызвать - <function>open()</function>. В тех же строках приложение должно всегда - устанавливать явно маску прав доступа (umask) перед вызовом функции - <function>open()</function> во избежание беспорядочных вызовов - <function>chmod()</function>.</para> - </sect1> -</chapter>
\ No newline at end of file |