Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
книги хакеры / Питер_Гудлиф_Ремесло_программиста_Практика_написания_хорошего_кода.pdf
Скачиваний:
16
Добавлен:
19.04.2024
Размер:
9.23 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

36m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Глава 1. Держим оборонуClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Технологии защитного программирования

Но хватит общих слов. Что все это значит для программистов на прак% тике?

Защитное программирование предполагает соблюдение ряда разум% ных правил. Обычно, когда заходит речь о защитном программирова% нии, людям приходит в голову использовать операторы контроля, и это правильно. Мы поговорим о них позже. Но существует также мас% са простых приемов программирования, которые неизмеримо повысят надежность вашего кода.

Несмотря на свою очевидность, они часто игнорируются, откуда и про% истекает низкое качество большей части существующего программно% го обеспечения. Большей безопасности и надежной разработки можно достичь на удивление легко, если только программисты проявят бди% тельность и компетентность.

Несколько последующих страниц посвящены перечислению правил защитного программирования. Сначала мы нарисуем общую картину, рассмотрев защитные приемы, процессы и процедуры верхнего уров% ня. Затем займемся деталями и более пристально рассмотрим отдель% ные операторы кода. Некоторые из этих защитных приемов специфич% ны для применяемых языков программирования. И это естественно: если язык допускает какие%то вредоносные действия, то именно от них и нужно защищаться.

Читая этот список, проверьте себя. Многие ли из этих правил вы со% блюдаете в своей практике? Какие из них вы теперь готовы принять на вооружение?

Выберите хороший стиль кодирования и пользуйтесь крепкой архитектурой

Значительной части ошибок можно избежать, придерживаясь доброт% ного стиля кодирования. Это правило согласуется с остальными глава% ми данной части. Такие простые вещи, как выбор осмысленных имен переменных и разумная расстановка скобок, делают код понятнее и уменьшают шансы пропустить ошибку.

Точно так же очень важно изучить проект в целом, прежде чем погру% жаться в написание кода. «Лучшая документация компьютерной про% граммы – это ее четкая структура». (Kernighan Plaugher 78) Если вы начнете с того, что реализуете понятные API, определите логичную структуру системы и четкие роли и задачи компонент, то избавитесь от возможной головной боли в будущем.

Пишите код без спешки

Сплошь и рядом программы пишут сломя голову. Программист быст% ренько ляпает функцию, пропускает ее через компилятор для провер%

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

Технологииm

защитного программирования

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

37Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

ки синтаксиса, запускает, чтобы убедиться в ее работоспособности, и переходит к очередной задаче. Такой подход чреват опасными по% следствиями.

Правило: необходимо обдумывать каждую новую строку. Какие ошиб% ки могут в ней возникнуть? Все ли возможные повороты логики вы рассмотрели? Медленное и методичное программирование может по% казаться скучным, но оно действительно сокращает количество оши% бок в программе.

Чем больше спешки, тем меньше скорость. Всегда думайте, что вы собирае& тесь ввести с клавиатуры.

Пример ловушки, которая поджидает спешащих программистов, пи% шущих на языках семейства C, – это ошибочный ввод = вместо ==. Первый оператор присваивает значение переменной, а второй прове% ряет равенство. Недружественный компилятор (или с отключенным выводом предупреждений) не покажет вам, что программа будет вы% полняться не так, как вам хотелось.

Не бросайтесь вперед, пока не выполните все задачи, необходимые для завершения работы с каким%то разделом кода. Например, если вы со% бираетесь сначала написать основной код, а потом заняться проверкой

иобработкой ошибок, вы должны твердо решить, что сделаете и то,

идругое. Никогда не откладывайте на будущее проверку ошибок ради того, чтобы написать основной код еще нескольких разделов. Ваше на% мерение вернуться к обработке ошибок позже может быть вполне ис% кренним, но «позже» может превратиться в «гораздо позже», когда вы в значительной мере забудете контекст, что в результате потребует еще большего труда и времени. (И разумеется, к тому моменту вам бу% дет поставлен какой%нибудь нереальный срок завершения работы.)

Дисциплинированность – это привычка, которую надо усвоить и укреп% лять. Всякий раз, когда вы откладываете выполнение необходимого дела, вы увеличиваете вероятность того, что не выполните его и в буду% щем. Сделайте это сейчас, не дожидаясь того дня, когда в Сахаре прой% дет дождь. На самом деле, для того чтобы сделать это потом, а не сей% час, требуется обладать еще большей дисциплинированностью!

Не верьте никому

Мама говорила вам, чтобы вы не вступали в разговор с незнакомыми людьми? К сожалению, разработка хороших программ требует еще больше цинизма и еще меньше доверия к человеческой натуре. Даже добропорядочные пользователи могут вызвать проблемы у вашей про% граммы; защищаясь, нельзя доверять никому.

У вас могут возникнуть проблемы по следующим причинам:

Обычный пользователь случайно введет в программу неверные

данные или воспользуется ею некорректно.

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

38m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Глава 1. Держим оборонуClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Злоумышленник сознательно попытается заставить программу ве% сти себя некорректно.

Клиентский код вызовет вашу функцию, неправильно передав ей параметры или задав им недопустимые значения.

Операционная среда не сможет предоставить программе необходи% мый сервер.

Внешние библиотеки окажутся некорректными и не выполнят те контракты по интерфейсам, на которые вы полагались.

А может быть, вы сами сделаете глупую ошибку в какой%то функции или забудете, как работает код, написанный вами три года назад, и не% правильно воспользуетесь им. Не рассчитывайте, что все будет хорошо и весь код будет работать корректно. Ставьте проверки везде, где толь% ко можно. Все время ищите слабые точки и помещайте в них дополни% тельные средства защиты.

Не верьте никому. Кто угодно, включая вас самих, может сделать ошибки в логике вашей программы. Ко всем входным и выходным данным относитесь с подозрением, пока не проверите, что они допустимы.

Стремитесь к ясности, а не к краткости

Когда встает выбор между кратким (но непонятным) и ясным (но скуч% ным) кодом, делайте его в пользу того кода, смысл которого понятен, даже если он менее элегантен. Например, сложные арифметические выражения разбивайте на последовательность отдельных операторов, логика которых понятнее.

Подумайте о тех, кто будет читать ваш код. Возможно, его будет сопро% вождать менее опытный кодировщик, и если он не разберется в логике, то может сделать ошибки. Сложные конструкции или оригинальные фокусы с языком могут свидетельствовать о ваших энциклопедиче% ских знаниях в области приоритетов операторов, но сильно ослабят возможность сопровождения кода. Будьте проще.

Код, который нельзя сопровождать, не может быть безопасным. В от% дельных случаях чрезмерно сложные выражения приводят к генера% ции компилятором некорректного кода – так часто обнаруживаются ошибки в оптимизации, проводимой компилятором.

Простота – это достоинство. Не усложняйте код сверх необходимости.

Не позволяйте никому лезть туда, где ему нечего делать

То, что является внутренним делом, должно оставаться внутри. Ваши личные вещи должны храниться под замком. Не нужно демонстриро% вать свое грязное белье на публике. Несмотря на любые ваши просьбы, стоит только отвернуться, и люди начнут ковыряться в ваших дан%

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

Технологииm

защитного программирования

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

39Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Когда приступать?

Когда начинать программировать в защитном стиле? После того как выявятся неполадки? Или когда попадется непонятный код, написанный кем%то другим?

Нет, технологии защитного программирования нужно применять постоянно. Они должны войти в привычку. Опытные программи% сты знают это по своему опыту; они достаточно часто обжигались, и теперь размещают в программах разумные средства защиты.

Защитные средства гораздо проще применять с самого начала написания кода, нежели пытаться вмонтировать в уже сущест% вующий. Если пытаться втиснуть их в код на поздних стадиях работы с ним, трудно ничего не упустить и быть точным. Если вы начинаете добавлять защитный код уже после того, как воз% никли неполадки, то фактически занимаетесь отладкой, т. е. ре% агируете на события, а не предупреждаете их.

Тем не менее в процессе отладки или добавления новых функций обнаруживаются условия, которые желательно проверять. Вот тогда и полезно добавить защитный код.

ных, если вы оставите для этого малейшую возможность, и станут вы% зывать «внутренние» функции по своему разумению. Не позволяйте им этого делать.

В объектно%ориентированных языках доступ к внутренним данным класса запрещается путем объявления его закрытым. В C++ можно воспользоваться идиомой Чеширского кота (или pimpl) – стандарт% ным приемом, употребляемым для выведения внутренней структу% ры класса из его открытого файла заголовка. (Meyers 97)

В процедурных языках также можно воспользоваться идеями объ% ектно%ориентированной упаковки, заключив закрытые данные внут% ри непрозрачных типов и обеспечив корректные операции над ними.

Дайте всем переменным минимально необходимую область видимо% сти; не делайте их глобальными, если в этом нет необходимости. Ес% ли их можно сделать локальными для функции, не объявляйте их на уровне файла. Если их можно сделать локальными для цикла, не объявляйте их на уровне функции.

Включайте вывод всех предупреждений при компиляции

Большинство компиляторов выдает массу сообщений об ошибках, когда их что%то не устраивает в коде. Они также выводят различные предупре# ждения, если им кажется, что в коде может быть ошибка, например в C или C++ использование переменной до того, как ей присваивается