Статьи

Не просто рандомизировать, действительно рандомизировать!

Состояние криптографии веб-приложений изменилось, и каждый язык разработки предоставляет свой собственный способ работы с ним. Я коснусь текущего состояния генерации случайных чисел и различий, обнаруженных с ним в языках разработки Java и JavaScript.

При разработке и создании веб-приложений вопросы безопасности, очевидно, играют решающую роль. Термин «безопасность» довольно широк и охватывает множество областей, включая, но не ограничиваясь:

  • проверка ввода
  • аутентификация
  • управление сеансом
  • защита от изменения параметров
  • криптография

В предыдущем проекте Министерства обороны США и правительства мне посчастливилось поработать над компонентом безопасности Java, который непосредственно касался этой последней области безопасности: криптографии. В частности, генерация случайных чисел. Исходя из чисто бизнес-разработки Java, изначально мне пришлось отступить от технического документа проектирования и выяснить, как мы хотим, чтобы это веб-приложение обеспечивало конфиденциальность и целостность.

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

Шифрование и Случайность

В разработке безопасных веб-приложений этот последний вопрос играет большую роль в преимуществах безопасности при использовании случайности. Некоторые могут сказать: «Привет, что касается шифрования, как насчет использования только кодировки Base64 или UTF8?». Проще говоря, это старая школа! В настоящее время большинство аналитиков безопасности даже не рассматривают эти два надежных метода безопасного шифрования.

Другими примерами использования случайности могут быть генерация случайных проблем при входе в систему, создание идентификаторов сеансов или использование секретных ключей для различных целей шифрования. Что касается последнего примера, для генерации таких секретных ключей необходим пул энтропии. Энтропийный пул, который непредсказуем. Это может быть достигнуто путем проверки неповторяемого вывода криптографически сильного генератора случайных чисел (CSPRNG).

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

Некоторые могут спросить: «Ну, что не так с http://random.org Ничего особенного… он отлично работает как «настоящий» генератор случайных чисел. Тем более, что он утверждает, что генерирует случайность через атмосферный шум. Однако, если шаблоны действительно обнаруживаются в этом атмосферном шуме, этот вид разоблачает их действительно случайное утверждение. С теоретической точки зрения немного сложно найти объективное измерение физических источников случайности. Но я отвлекся!

Кто-то может просто использовать Random.org через SSL через HTTPS? Да, но это не очень хорошая идея, если вы реализуете это внутри криптобезопасной системы. Даже сам сайт http://random.org говорит не использовать его для криптографии. Опять же, аутсорсинг вашего рода генерации случайных чисел наносит ущерб цели безопасной системы.

Ява

Давайте посмотрим, что может предложить язык Java. С точки зрения серверной части Java язык Java стандартно поставляется с традиционным классом Random. Это прекрасно работает для обычных, небезопасных приложений, которые вы можете выбрать случайным образом, например, игра с переворотом монет или игра с интерактивными картами. Этот класс имеет довольно короткий период (2 ^ 48), учитывая его seed = (seed * множитель + 0xbL) & ((1L << 48) — 1). Это создаст только небольшую комбинацию значений.

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

Другое ограничение, по крайней мере для версий Java до 1.4, заключается в том, что при использовании конструктора Random по умолчанию для генерации случайных чисел по умолчанию используется текущее системное время с 1 января 1970 года, измеренное в миллисекундах. Таким образом, внешний пользователь может легко определить случайные числа, сгенерированные, если они узнают время выполнения приложения.

SecureRandom на помощь! SecureRandom, с другой стороны, создает криптографически устойчивые случайные числа. CSPRNGS использует истинный случайный источник: энтропию.

Например, щелчки мыши пользователя, движения мыши, ввод с клавиатуры, конкретное событие синхронизации или любые другие связанные с ОС случайные данные. Так что это близко к тому, чтобы стать ИСТИННЫМ генератором случайных чисел. Я говорю близко, потому что, по крайней мере, они не генерируются детерминированным алгоритмом.

Но опять же, теоретически, является ли что-нибудь действительно случайным? Хорошо, не обращайте внимания на этот вопрос. Имейте в виду, что SecureRandom использует реализации PRNG из других классов, которые являются частью поставщиков криптографических услуг Java. Например, в Windows SUN CSP по умолчанию использует SHA1PRNG. Это хорошо, потому что, используя конструктор SecureRandom () по умолчанию, пользователь может получить 128-битное начальное число. Таким образом, исходя из его исходного источника, шансы на повторение чрезвычайно меньше, чем у исходного java-класса Random.

Простая, простая реализация самозапускающегося генератора SecureRandom:

1
2
3
4
5
6
7
// Very nice...
// Instantiate secure random generator using the SHA1PRNG algorithm
SecureRandom randomizer = SecureRandom.getInstance(“SHA1PRNG”);
 
// Provide a call to the nextBytes method.  This will force the SecureRandom object to seed itself.
byte[] randomBytes = new byte[128];
randomizer.nextBytes(randomBytes);

С другой стороны… Знаменитый стандартный метод «Гарантия случайности»:

1
2
3
4
// No bueno
public int getRandomNumber() {
    return 7// shhhh no one will know... teehee
}

Итог: самое важное, что нужно принять во внимание, это… семя! Все генераторы псевдослучайных чисел являются детерминированными, если известно начальное число. Таким образом, тот факт, что SecureRandom намного лучше подходит для работы с сильным источником энтропии, чем Random, дает ему преимущество в криптографической среде. Недостатком является то, что чем больше нужна энтропия, тем хуже производительность. Что-то, чтобы рассмотреть.

JavaScript

Так что насчет JavaScript? Может ли клиентская сторона быть достаточно надежной для криптографии? В целом, насколько по-настоящему безопасен язык JavaScript? Теперь, когда JavaScript и одностраничные приложения становятся все более популярными, это актуальные и важные вопросы.

Одним из наиболее распространенных недостатков безопасности на стороне клиента является внедрение HTML, при котором приложение может неосознанно разрешать третьим сторонам внедрять JavaScript в свой контекст безопасности. Сегодня веб-сайтам и многим веб-приложениям требуется своего рода шифрование на стороне клиента. Тем более что браузеры остаются инструментом выбора при взаимодействии с удаленными серверами. К счастью для нас, JavaScripters, самые современные браузеры поставляются со сложными мерами для борьбы с этими опасностями.

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

В любом случае это не должно иметь значения, так как JavaScript поставляется только с функцией Math.random (), которая не принимает аргументов. Эта функция Math.random () поставляется автоматически, аналогично классу Java в Random, но что можно сделать, чтобы заполнить ее вручную? Не важно. JavaScript не поддерживает возможность ручного заполнения Math.random (). Есть несколько дропинов, один из которых является популярным на основе RC-4 и доступен на GitHub . Он даже поддерживает Node.js и Require.js.

Давайте помнить, что все браузеры поставляются с различными генераторами случайных чисел. Chrome использует генератор «Multiply-with-carry». Firefox и IE используют линейные конгруэнтные генераторы (класс Java Random также изменяется с использованием линейной конгруэнтной формулы), поэтому было бы неразумно использовать Math.random () в качестве единственного источника энтропии. Посмотрим правде в глаза, эта функция не является криптографически сильной.

Некоторые библиотеки JavaScript crypto действительно предоставляют некоторую помощь, одной из которых является CryptoJS . CryptoJS включает в себя множество безопасных криптографических алгоритмов, написанных на JavaScript. Но давайте пропустим сторонние библиотеки и посмотрим, что может предложить Javascript.

В последнее время МДН не разочаровал. Они делают успехи в мире криптографии. Например, функция window.crypto.getRandomValues ​​() работает довольно хорошо. Все, что необходимо для этой функции сбора энтропии, — это передать TypeArray на основе целых чисел, и функция заполнит массив криптографически случайными числами. Имейте в виду, что это экспериментальный API, то есть он все еще находится в рабочем состоянии, но, похоже, работает только в нескольких последних браузерах, которые используют сильные (псевдо) генераторы случайных чисел. Вот отличная ссылка, которая показывает совместимость браузера с этой конкретной функцией.

Вывод

Пока такие угрозы безопасности, как внедрение кода, атаки по побочным каналам и межсайтовый скриптинг, больше не являются угрозой, трудно полагаться на JavaScript как на серьезную криптографическую среду. Держись, хотя! Я не предлагаю полагаться на полноценную криптографию в браузере. Можно было бы открыть целую банку червей, если бы клиентская сторона должна была обрабатывать большинство функций безопасности приложений.

Однако это не значит, что в будущем ничего не изменится. Возможно, однажды будет полный криптографический стек, встроенный в HTML / JavaScript. Кроме того, учитывая популярность SPA и таких инструментов, как Angular, у меня есть ощущение, что window.crypto.getRandomValues ​​() будет поддерживаться всеми будущими браузерами в один прекрасный день.

До тех пор ничто не сравнится с генерацией случайных чисел на сервере. Тем не менее, я смотрю на это с лучшей стороны и всегда слежу за тем, что ждет нас в будущем для разработки безопасных веб-сайтов SPA!