Чтение онлайн

на главную - закладки

Жанры

19 смертных грехов, угрожающих безопасности программ

Виега Джон

Шрифт:

Например, можно записать в скрытое поле news значение 1. Тогда сообщение будет помещено на первую страницу в качестве новости!

Или можно параметру allmem (все члены) присвоить значение true. Тогда все члены сообщества получат почтовое сообщение. Таким образом можно завалить пользователей системы спамом.

Искупление греха

Анализируя угрозы, исходящие от загадочных URL и скрытых полей формы, а также возможные контрмеры, рассматривайте следующие варианты:

□ противник просматривает данные;

□ противник воспроизводит данные;

□ противник предсказывает данные;

□ противник изменяет данные.

Противник просматривает данные

Это представляет собой угрозу, только если данные конфиденциальны, например речь идет о пароле или идентификаторе,

позволяющем войти в систему. Любая персональная информация также должна приниматься во внимание. Исправить ситуацию поможет использование протоколов Secure Socket Layers (SSL),

Transport Layer Security (TLS), Internet Protocol Security (IPSec) и других технологий шифрования секретных данных. Например, данные можно зашифровать на сервере, а потом отправить клиенту в скрытом поле или в виде кука, тогда клиент автоматически вернет те же данные серверу при следующем запросе. Поскольку ключ хранится на сервере, то эта строка не может быть интерпретирована клиентом, так что с точки зрения криптографии метод вполне приемлем.

Противник воспроизводит данные

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

...

SHA1Managed s = new SHA1Managed;

byte [] h = s.ComputeHash(UTF8Encoding.UTF8.GetBytes(uid + ":" + pwd));

h = s.ComputeHash(h);

string b64 = Convert.ToBase64String(h); // в кодировке base64

А вот аналогичный код на языке JavaScript (вызываемый из HTML или ASP–страницы) с применением СОМ–объекта CAPICOM в Windows:

...

// Результат хэширования в 16-ричном виде

var oHash = new ActiveXObject("CAPICOM.HashedData");

oHash.Algorithm = 0;

oHash.Hash("mikey" + ":" + "ABCDE");

oHash.Hash(oHash.Value);

var b64 = oHash.Value; // результат в 16-ричном виде

Тот же код для вычисления свертки имени и пароля пользователя на Perl:

...

use Digest::SHA1 qw(sha1 sha1_base64);

my $s = $uid . ":" . $pwd;

my $b64 = sha1_base64(sha1($s)); # в кодировке base64

Отметим, что во всех этих примерах результат хэширования конкатенированной строки снова хэшируется, чтобы обойти уязвимость, которая называется атакой с увеличением длины (length extension attack). Объяснение этой уязвимости выходит за рамки данной книги [2] , но если говорить о практической стороне дела, то не ограничивайтесь просто хэшированием конкатенированных данных, а сделайте одно из двух:

...

Result = H(data1, H(data2))

или

...

Result = H(H(data1 CONCAT data2))

Ниже приводится криптографически стойкая версия:

...

static string IterateHashAppendSalt(string uid, string pwd, UInt32 iter)

{

// границы числа итераций

const UInt32 MIN_ITERATIONS = 1024;

const UInt32 MAX_ITERATIONS = 32768;

// ограничить переданное значение параметра для безопасности

if (iter < MIN_ITERATIONS) iter = MIN_ITERATIONS;

if (iter > MAX_ITERATIONS) iter = MAX_ITERATIONS;

// получить 24-байтовое начальное значение (затравку)

const UInt32 SALT_BYTE_COUNT = 24;

byte[] salt = new byte[SALT_BYTE_COUNT];

new RNGCryptoServiceProvider.GetBytes(salt);

// закодировать имя и пароль

byte[] uidBytes = UTF8Encoding.UTF8.GetBytes(uid);

byte[] pwdBytes = UTF8Encoding.UTF8.GetBytes(pwd);

UInt32 uidLen = (UInt32)uidBytes.Length;

UInt32 pwdLen = (UInt32)pwdBytes.Length;

// скопировать uid, pwd и salt в буфер (массив байтов)

byte[] input = new byte[SALT_BYTE_COUNT + uidLen + pwdLen];

Array.Copy(uidBytes, 0, input, 0, uidLen);

Array.Copy(pwdBytes, 0, input, uidLen, pwdLen);

Array.Copy(salt, 0, input, uidLen + pwdLen, SALT_BYTE_COUNT);

//

вычислить хэш uid, pwd и salt

// H(uid || pwd || salt)

HashAlgorithm sha = HashAlgorithm.Create("SHA256");

byte[] hash = sha.ComputeHash(input);

// вычислить хэш от результата первого хэширования, начального

// значения и номера итерации N раз

// R0 = H(uid || pwd || salt)

// Rn = H(Rn-1 || R0 || salt || i) ... N

const UInt32 UINT32_BYTE_COUNT = 32/8;

byte[] buff = new byte[hash.Length +

hash.Length +

SALT_BYTE_COUNT +

UINT32_BYTE_COUNT];

Array.Copy(salt, 0, buff, hash.Length + hash.Length, SALT_BYTE_COUNT);

Array.Copy(salt, 0, buff, hash.Length, hash.Length);

for (UInt32 i = 0; i < iter; i++) {

Array.Copy(hash, 0, buff, 0, hash.Length);

Array.Copy(BitConverter.GetBytes(i), 0, buff,

hash.Length + hash.Length + SALT_BYTE_COUNT,

UINT32_BYTE_COUNT);

hash = sha.ComputeHash(buff);

}

// построить строку вида base64(hash) : base64(salt)

string result = Convert.ToBase64String(hash) + ":" +

Convert.ToBase64String(salt);

return result;

}

Но даже эта версия уязвима для атаки! В чем же уязвимость? Пусть, например, имя и пароль пользователя сворачиваются в строку «xE/fl/XKonG+/XFyq+ Pg4FXjo 7g=», и вы включаете ее в состав URL в качестве доказательства того, что верительные грамоты были проверены. Противнику нужно лишь увидеть эту свертку и воспроизвести ее. Пароль ему знать вовсе необязательно! Вся эта «навороченная» криптография оказалась не стоящей и ломаного гроша! Исправить это упущение помогут такие технологии шифрования канала, как SSL, TLS или IPSec.

Противник предсказывает данные

В этом случае пользователь заходит на сайт, вводя свое имя и пароль по шифрованному соединению (SSL/TLS), сервер проверяет их и генерирует автоинкрементное значение для представления данного пользователя. В ходе дальнейшего взаимодействия с пользователем используется именно это значение, чтобы не проходить каждый раз всю процедуру аутентификации. Такую схему легко атаковать даже при наличии SSL/TLS. И вот как это делается. Настоящий, хотя и злонамеренный, пользователь соединяется с сервером и предъявляет свои верительные грамоты. Он получает от сервера идентификатор 7625. Затем он закрывает браузер, открывает его снова и входит с тем же именем и паролем. На этот раз он получает идентификатор 7267. Похоже, что для каждого нового пользователя идентификатор увеличивается на единицу, причем между двумя его заходами вошел кто–то еще. Чтобы перехватить чужой сеанс (защищенный протоколом SSL/ TLS!), противнику остается лишь задать идентификатор равным 7266. Технологии шифрования не защищают от такого рода предсказаний. Но вы можете установить идентификатор соединения равным криптографически случайному числу. На языке JavaScript для этого можно воспользоваться СОМ–объектом CAPICOM:

...

var oRNG = new ActiveXObject(«CAPICOM.Utilities»);

var rng = oRNG.GetRandom(32, 0);

Примечание. CAPICOM вызывает функцию Windows CryptGenRandom.

При использовании PHP в ОС Linux или UNIX (в предположении, что система поддерживает специальное устройство /dev/random или /dev/urandom) можно написать такой код:

...

// наличие @ перед fopen не дает fopen вывести излишне много

// информации пользователю

$hrng = @fopen("/dev/random", "r");

if ($hrng) {

$rng = base64_encode(fread($hrng,32));

fclose($hrng);

}

И на языке Java:

...

try {

SecureRandom rng = SecureRandom.getInstance("SHA1PRNG");

byte b[] = new byte[32];

rng.nextBytes(b);

} catch (NoSuchAlgorithmException e) {

// Обработать исключение

}

Примечание. Стандартная реализация класса SecureRandom в Java обладает очень небольшим энтропийным пулом. Для управления сеансами и опознанием пользователей в Web–приложениях этого, может быть, и достаточно, но для генерирования долгосрочных ключей маловато.

Поделиться:
Популярные книги

Как я строил магическую империю 4

Зубов Константин
4. Как я строил магическую империю
Фантастика:
боевая фантастика
постапокалипсис
аниме
фантастика: прочее
фэнтези
5.00
рейтинг книги
Как я строил магическую империю 4

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Попаданка 3

Ахминеева Нина
3. Двойная звезда
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попаданка 3

Муж на сдачу

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Муж на сдачу

Призыватель нулевого ранга. Том 3

Дубов Дмитрий
3. Эпоха Гардара
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Призыватель нулевого ранга. Том 3

На границе империй. Том 10. Часть 5

INDIGO
23. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 5

Адвокат

Константинов Андрей Дмитриевич
1. Бандитский Петербург
Детективы:
боевики
8.00
рейтинг книги
Адвокат

На границе империй. Том 7

INDIGO
7. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
6.75
рейтинг книги
На границе империй. Том 7

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

О, Путник!

Арбеков Александр Анатольевич
1. Квинтет. Миры
Фантастика:
социально-философская фантастика
5.00
рейтинг книги
О, Путник!

Чужбина

Седой Василий
2. Дворянская кровь
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Чужбина

Бестужев. Служба Государевой Безопасности. Книга четвертая

Измайлов Сергей
4. Граф Бестужев
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бестужев. Служба Государевой Безопасности. Книга четвертая

Локки 5. Потомок бога

Решетов Евгений Валерьевич
5. Локки
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Локки 5. Потомок бога

На границе империй. Том 10. Часть 4

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 4