aboutsummaryrefslogtreecommitdiff
path: root/ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml
diff options
context:
space:
mode:
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.sgml439
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