Synchronize with English 1.26

Submitted by:   Vitaly Bogdanov <gad@gad.glazov.net>
Obtained from:  The FreeBSD Russian Documentation Project
This commit is contained in:
Andrey Zakhvatov 2005-07-14 04:44:25 +00:00
parent 3a44d0360e
commit 7b63d5a37c
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=25102

View file

@ -2,21 +2,29 @@
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 $
$FreeBSDru: frdp/doc/ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml,v 1.4 2005/07/11 11:54:33 gad Exp $
Original revision: 1.1
Original revision: 1.26
-->
<chapter id="secure">
<title>Безопасное программирование</title>
<chapter id="secure">
<chapterinfo>
<authorgroup>
<author>
<firstname>Murray</firstname>
<surname>Stokely</surname>
<contrib>Материал предоставил: </contrib>
</author>
</authorgroup>
</chapterinfo>
<para>Эту главу написал Мюррей Стокели (Murray Stokely).</para>
<title>Безопасное программирование</title>
<sect1>
<sect1 id="secure-synopsis">
<title>Обзор</title>
<para>Эта глава описывает некоторые из проблем обеспечения безопасности,
которые десятилетиями преследовали программистов Unix, а также
которые десятилетиями преследовали программистов &unix;, а также
несколько новых доступных инструментов, помогающих программистам
избежать написания небезопасного кода.</para>
</sect1>
@ -32,45 +40,80 @@
код должен использоваться там, где только это возможно для избежания
общих ошибок, которые могли быть уже исправлены другими.</para>
<para>Одной из неприятностей в среде Unix является легкость в
<para>Одной из неприятностей в среде &unix; является легкость в
предположении безопасности этого окружения. Приложения никогда не
должны верить пользовательскому вводу (во всех его формах), ресурсам
системы, межпроцессному взаимодействию или времени выполнения событий.
Процессы Unix выполняются не синхронно, так что логические операции
Процессы &unix; выполняются не синхронно, так что логические операции
редко бывают атомарными.</para>
</sect1>
<sect1>
<sect1 id="secure-bufferov">
<title>Переполнения буфера</title>
<para>Переполнения буфера появились вместе с появление архитектуры
Фон-Неймана <xref linkend="COD">. Впервые широкую известность они
получили в 1988 году вместе с Интернет-червем Мурса (Moorse). К
сожалению, точно такая же атака повторилась и в наши дни. Из 17
бюллетеней безопасности CERT за 1999 год, 10 были непосредственно
вызваны ошибкам в программном обеспечении, связанным с переполнениями
буфера. Самые распространенные типы атак с использованием переполнения
буфера основаны на разрушении стека.</para>
Фон-Неймана <xref linkend="COD">.
<indexterm><primary>переполнение буфера</primary></indexterm>
<indexterm><primary>Фон-Нейман</primary></indexterm>
Впервые широкую известность они получили в 1988 году вместе с
Интернет-червем Морриса (Morris). К сожалению, точно такая же атака
<indexterm><primary>интернет червь Морриса</primary></indexterm>
остаётся эффективной и в наши дни. Из 17 бюллетеней безопасности CERT за 1999 год,
<indexterm>
<primary>CERT</primary><secondary>бюллетени безопасности</secondary>
</indexterm>
10 были непосредственно вызваны ошибкам в программном обеспечении, связанным
с переполнениями буфера. Самые распространенные типы атак с использованием
переполнения буфера основаны на разрушении стека.</para>
<indexterm><primary>стек</primary></indexterm>
<indexterm><primary>аргументы</primary></indexterm>
<para>Самые современные вычислительные системы используют стек для
передачи аргументов процедурам и сохранения локальных переменных. Стек
является буфером типа LIFO (последним вошел первым вышел) в верхней
части области памяти процесса. Когда программа вызывает функцию,
создается новая "граница стека". Эта граница состоит из аргументов,
<indexterm><primary>LIFO</primary></indexterm>
<indexterm>
<primary>область процесса</primary>
<secondary>указатель стека</secondary>
</indexterm>
переданных в функцию, а также динамического количества пространства
локальных переменных. "Указатель стека" является регистром, хранящим
<indexterm><primary>граница стека</primary></indexterm>
<indexterm><primary>указатель стека</primary></indexterm>
текущее положение вершины стека. Так как это значение постоянно
меняется вместе с помещением новых значений на вершину стека, многие
реализации также предусматривают "указатель границы", который
расположен около начала стека, так что локальные переменные можно легко
адресовать относительно этого значения. <xref linkend="COD"> Адрес
<indexterm><primary>указатель границы</primary></indexterm>
<indexterm>
<primary>область процесса</primary>
<secondary>указатель границы</secondary>
</indexterm>
<indexterm><primary>возвращаемый адрес</primary></indexterm>
<indexterm><primary>переполнение стека</primary></indexterm>
возврата из функции также сохраняется в стеке, и это является причиной
нарушений безопасности, связанных с переполнением стека, так как
перезаписывание локальной переменной в функции может изменить адрес
возврата из этой функции, потенциально позволяя злоумышленнику
выполнить любой код.</para>
<para>Хотя атаки с переполнением стека являются замыми распространенными,
<para>Хотя атаки с переполнением стека являются самыми распространенными,
стек можно также перезаписать при помощи атаки, основанной на выделении
памяти (malloc/free) из "кучи".</para>
@ -78,7 +121,7 @@
автоматической проверки границ в массивах или указателях. Кроме того,
стандартная библиотека C полна очень опасных функций.</para>
<informaltable>
<informaltable frame="none" pgwide="1">
<tgroup cols=2>
<tbody>
<row>
@ -132,8 +175,7 @@
следующей непосредственно за вызовом функции. (По мотивам <xref
linkend="Phrack">)</para>
<programlisting>
#include <sgmltag>stdio.h</sgmltag>
<programlisting>#include <sgmltag>stdio.h</sgmltag>
void manipulate(char *buffer) {
char newbuffer[80];
@ -151,8 +193,7 @@ int main() {
i=2;
printf("The value of i is : %d\n",i);
return 0;
}
</programlisting>
}</programlisting>
<para>Давайте посмотрим, как будет выглядеть образ процесса, если в
нашу маленькую программу мы введем 160 пробелов.</para>
@ -170,10 +211,23 @@ int main() {
использование только памяти фиксированного размера и функций
копирования строк. Функции <function>strncpy</function> и
<function>strncat</function> являются частью стандартной библиотеки
<indexterm>
<primary>функции копирования строки</primary>
<secondary>strncpy</secondary>
</indexterm>
<indexterm>
<primary>функции копирования строки</primary>
<secondary>strncat</secondary>
</indexterm>
C. Эти функции будут копировать не более указанного количества байт
из исходной строки в целевую. Однако у этих функций есть несколько
проблем. Ни одна из них не гарантирует наличие символа NUL, если
размер входного буфера больше, чем целевого. Параметр длины также
<indexterm><primary>завершение символом NUL</primary></indexterm>
по-разному используется в strncpy и strncat, так что для
программистов легко запутаться в правильном использовании. Есть
также и значительная потеря производительности по сравнению с
@ -182,27 +236,47 @@ int main() {
NUL пространство до указанной длины.</para>
<para>Для избежания этих проблем в OpenBSD была сделана другая
<indexterm><primary>OpenBSD</primary></indexterm>
реализация копирования памяти. Функции <function>strlcpy</function>
и <function>strlcat</function> гарантируют, что они они всегда
терминируют целевую строку нулевым символом, если им будет передан
аргумент ненулевой длины. Более подробная информация об этом
находится здесь <xref linkend="OpenBSD">. Инструкции OpenBSD
<function>strlcpy</function> и <function>strlcat</function> были
во FreeBSD начиная с 3.5.</para>
<function>strlcpy</function> и <function>strlcat</function> существуют
во FreeBSD начиная с версии 3.3.</para>
<indexterm>
<primary>функции копирования строки</primary>
<secondary>strlcpy</secondary>
</indexterm>
<indexterm>
<primary>функции копирования строки</primary>
<secondary>strlcat</secondary>
</indexterm>
<sect3>
<title>Вкомпилированная проверка границ во время выполнения</title>
<para>К несчастью, все еще широко используется очень большой объем
<indexterm><primary>проверка границ</primary>
<secondary>вкомпилированная</secondary></indexterm>
<para>К сожалению, все еще широко используется очень большой объём
кода, который слепо копирует память без использования только что
рассмотренных функций с проверкой границ. Однако есть другое
решение. Существует несколько расширений к компилятору и
библиотекам C/C++ для выполнения контроля границ во время
выполнения.</para>
библиотек для выполнения контроля границ во время
выполнения (C/C++).</para>
<indexterm><primary>StackGuard</primary></indexterm>
<indexterm><primary>gcc</primary></indexterm>
<para>Одним из таких добавлений является StackGuard, который
реализован как маленький патч к генератору кода gcc. Согласно
сайту StackGuard, http://immunix.org/stackguard.html:
реализован как маленький патч к генератору кода gcc. Согласно <ulink
url="http://immunix.org/stackguard.html">web сайту StackGuard</ulink>:
<blockquote>
<para>"StackGuard распознает и защищает стек от атак,
не позволяя изменять адрес возврата в стеке. При вызове
@ -219,12 +293,14 @@ int main() {
кода gcc, а именно процедур function_prolog() и
function_epilog(). function_prolog() усовершенствована для
создания пометок в стеке при начале работы функции, а
function_epilog() проверяет челостность пометки при возврате из
function_epilog() проверяет целостность пометки при возврате из
функции. Таким образом, любые попытки изменения адреса
возврата определяются до возврата из функции."</para>
</blockquote>
</para>
<indexterm><primary>переполнение буфера</primary></indexterm>
<para>Перекомпиляция вашего приложения со StackGuard является
эффективным способом остановить большинство атак переполнений
буфера, но все же полностью это проблемы не решает.</para>
@ -234,6 +310,11 @@ int main() {
<title>Проверка границ во время выполнения с использованием
библиотек.</title>
<indexterm>
<primary>проверка границ</primary>
<secondary>основана на библиотеке</secondary>
</indexterm>
<para>Механизмы на основе компилятора полностью бесполезны для
программного обеспечения, поставляемого в двоичном виде, которое вы
не можете перекомпилировать. В этих ситуациях имеется некоторое
@ -246,7 +327,7 @@ int main() {
<itemizedlist>
<listitem><simpara>libsafe</simpara></listitem>
<listitem><simpara>libverify</simpara></listitem>
<listitem><simpara>libparnoia</simpara></listitem>
<listitem><simpara>libparanoia</simpara></listitem>
</itemizedlist>
<para>К сожалению, эти защиты имеют некоторое количество недостатков.
@ -260,16 +341,27 @@ int main() {
</sect2>
</sect1>
<sect1>
<sect1 id="secure-setuid">
<title>Проблемы с установленным битом UID</title>
<indexterm><primary>seteuid</primary></indexterm>
<para>Имеется по крайней мере 6 различных идентификаторов (ID), связанных
с любым взятым процессом. Поэтому вы должны быть очень осторожны с
тем, какие права имеет ваш процесс в каждый момент времени. В
частности, все seteuid-приложения должны понижать свои привилегии, как
только в них отпадает необходимость.</para>
<para>ID реального пользователя может быть изменен только процессом
<indexterm>
<primary>идентификаторы пользователя</primary>
<secondary>реальный ID пользователя</secondary>
</indexterm>
<indexterm>
<primary>идентификаторы пользователя</primary>
<secondary>эффективный ID пользователя</secondary>
</indexterm>
<para>Реальный ID пользователя может быть изменен только процессом
администратора. Программа <application>login</application>
устанавливает его, когда пользователь входит в систему, и он редко
меняется.</para>
@ -283,10 +375,12 @@ int main() {
предыдущее значение сохраняется в сохраняемом set-user-ID.</para>
</sect1>
<sect1 id="chroot">
<sect1 id="secure-chroot">
<title>Ограничение среды работы вашей программы</title>
<para>Традиционно используемым методом ограничения доступа к процессу
<indexterm><primary>chroot()</primary></indexterm>
<para>Традиционно используемым методом ограничения процесса
является использование системного вызова <function>chroot()</function>.
Этот системный вызов меняет корневой каталог, относительно которого
определяются все остальные пути в самом процессе и всех порожденных ими
@ -312,6 +406,8 @@ int main() {
<sect2>
<title>Функциональность джейлов (jail) во FreeBSD</title>
<indexterm><primary>jail</primary></indexterm>
<para>Концепция джейлов (Jail) расширяет возможности
<function>chroot()</function>, ограничивая власть администратора
созданием настоящих `виртуальных серверов'. Как только тюремная
@ -337,16 +433,16 @@ int main() {
<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:
@ -358,7 +454,7 @@ int main() {
доступа к файлу, изменять его владельца, группу, размер, время
доступа и модификации.</simpara>
</listitem>
<listitem><simpara>Осуществлять привязку к привилегированному порту
в области портов Интернет (порты с номерами < 1024)</simpara>
</listitem>
@ -374,38 +470,46 @@ int main() {
</sect2>
<sect2>
<title>Возможности процессов POSIX.1e</title>
<title>&posix;.1e возможности процессов</title>
<para>Posix выпустил рабочий документ, который добавляет аудит событий,
<indexterm><primary>POSIX.1e возможности процессов</primary></indexterm>
<indexterm><primary>TrustedBSD</primary></indexterm>
<para>&posix; выпустила рабочий документ, который добавляет аудит событий,
списки управления доступом, тонко настраиваемые привилегии, метки
информации и жесткое управление доступом.</para>
<para>Этот документ находится в работе и находится в центре внимания
проекта <ulink url="http://www.trustedbsd.org">TrustedBSD</ulink>.
проекта <ulink url="http://www.trustedbsd.org/">TrustedBSD</ulink>.
Некоторая начальная функциональность уже была добавлена во
FreeBSD-current (cap_set_proc(3)).</para>
&os.current; (cap_set_proc(3)).</para>
</sect2>
</sect1>
<sect1>
<sect1 id="secure-trust">
<title>Доверие</title>
<para>Приложение никогда не должно полагать, что среда пользователя
безопасна. Сюда включается (но этим не ограничено): ввод пользователя,
сигналы, переменные среды, ресурсы, IPC, отображаемая в файл память,
сигналы, переменные среды, ресурсы, IPC, отображаемая в файл память (mmap),
рабочий каталог файловой системы, дескрипторы файлов, число открытых
файлов и прочее.</para>
<indexterm><primary>позитивная фильтрация</primary></indexterm>
<indexterm><primary>подтверждение правильности данных</primary></indexterm>
<para>Никогда не думайте, что сможете предусмотреть все формы
неправильного ввода, который может дать пользователь. Вместо этого
ваше приложение должно осуществлять позитивную фильтрацию, пропуская
только конечное множество возможных вариантов ввода, которые вы
считаете безопасными. Неполная праверка данных была причиной многих
считаете безопасными. Неполная проверка данных была причиной многих
нарушений защиты, особенно CGI-скриптов на веб-сайтах. Для имен файлов
вам нужно уделять особое внимание путям ("../", "/"), символическим
ссылкам и экранирующим символам оболочки.</para>
<para>В perl имеется такая очень полезная вещь, как "безупречный" (taint)
<indexterm><primary>Безупречный режим в Perl</primary></indexterm>
<para>В Perl имеется такая очень полезная вещь, как "безупречный" (taint)
режим, который можно использовать для запрещения скриптам использовать
данные, порожденные вне программы, не безопасным способом. Этот режим
проверяет аргументы командной строки, переменные окружения, информацию
@ -414,7 +518,7 @@ int main() {
<function>getpwxxx()</function> и весь файловый ввод.</para>
</sect1>
<sect1>
<sect1 id="secure-race-conditions">
<title>Неожиданное поведение</title>
<para>Неожиданное поведение - это аномальное поведение, вызванное
@ -422,6 +526,15 @@ int main() {
событий. Другими словами, программист неправильно предположил, что
некоторое событие всегда случается перед другим.</para>
<indexterm><primary>неожиданное поведение</primary>
<secondary>сигналы</secondary></indexterm>
<indexterm><primary>неожиданное поведение</primary>
<secondary>проверки на доступ</secondary></indexterm>
<indexterm><primary>неожиданное поведение</primary>
<secondary>открытия файлов</secondary></indexterm>
<para>Некоторые из широко распространенных причин возникновения таких
проблем являются сигналы, проверки доступа и открытия файлов. Сигналы
по своей природе являются асинхронными событиями, так что по отношению
@ -436,4 +549,4 @@ int main() {
<function>open()</function> во избежание беспорядочных вызовов
<function>chmod()</function>.</para>
</sect1>
</chapter>
</chapter>