Рекомендации по безопасности для разработчиков клиентов

См. также:
Совершенная Прямая Секретность
Секретные чаты, конец-в-конец шифрования
Идеальная прямая секретность в секретных чатах
MTProto 2.0, Подробное Описание

Хотя MTProto разработан как достаточно быстрый и безопасный протокол, его преимущества могут быть легко сведены на нет небрежной реализацией. На этой странице мы собрали некоторые рекомендации по безопасности для разработчиков клиентского программного обеспечения. Все клиенты Telegram обязаны соблюдать эти требования.
Обратите внимание, что начиная с версии 4.6 основные клиенты Telegram используют MTProto 2.0. MTProto v.1.0 устарел и в настоящее время постепенно прекращается.

Обмен ключами Диффи-Хеллмана

Мы используем обмен ключами ДХ в двух случаях:В обоих случаях при использовании ДХ необходимо провести некоторые проверки:

Проверка параметров ДХ

Ожидается, что клиент проверит, является ли p = dh_prime безопасным 2048-битным простым числом (это означает, что и p, и (p-1)/2 являются простыми, и что 2^2047 < p < 2^2048), и что g генерирует циклическую подгруппу простого порядка (p-1)/2, т. е. Является квадратичным вычетом mod p. Поскольку g всегда равен 2, 3, 4, 5, 6 или 7, это легко сделать с помощью квадратичного закона взаимности, дающего простое условие на p mod 4g, а именно p mod 8 = 7 для g = 2; p mod 3 = 2 для g = 3; никаких дополнительных условий для g = 4; p mod 5 = 1 или 4 для g = 5; p mod 24 = 19 или 23 для g = 6; и p mod 7 = 3, 5 или 6 для g = 7. После того, как g и p были проверены клиентом, имеет смысл кэшировать результат, чтобы не повторять длительные вычисления в будущем.
Если проверка занимает слишком много времени (что имеет место для более старых мобильных устройств), можно сначала выполнить только 15 итераций Миллера - Рабина (использовать параметр 30 в Java) для проверки простоты p и (p-1)/2 с вероятностью ошибки, не превышающей одной миллиардной, и сделать больше итераций в фоновом режиме позже.
Другой способ оптимизировать это - встроить в код клиентского приложения небольшую таблицу с некоторыми известными парами (g,p) (или просто безопасными простыми числами p, поскольку условие на g легко проверяется во время выполнения), проверяемыми на этапе генерации кода, чтобы вообще избежать такой проверки во время выполнения. Сервер редко изменяет эти значения, поэтому обычно нужно поместить текущее значение dh_prime сервера в такую таблицу. Например, текущее значение dh_prime равно (в порядке байтов big-endian)
C7 1C AE B9 C6 B1 C9 04 8E 6C 52 2F 70 F1 3F 73 98 0D 40 23 8E 3E 21 C1 49 34 D0 37 56 3D 93 0F 48 19 8A 0A A7 C1 40 58 22 94 93 D2 25 30 F4 DB FA 33 6F 6E 0A C9 25 13 95 43 AE D4 4C CE 7C 37 20 FD 51 F6 94 58 70 5A C6 8C D4 FE 6B 6B 13 AB DC 97 46 51 29 69 32 84 54 F1 8F AF 8C 59 5F 64 24 77 FE 96 BB 2A 94 1D 5B CD 1D 4A C8 CC 49 88 07 08 FA 9B 37 8E 3C 4F 3A 90 60 BE E6 7C F9 A4 A4 A6 95 81 10 51 90 7E 16 27 53 B5 6B 0F 6B 41 0D BA 74 D8 A8 4B 2A 14 B3 14 4E 0E F1 28 47 54 FD 17 ED 95 0D 59 65 B4 B9 DD 46 58 2D B1 17 8D 16 9C 6B C4 65 B0 D6 FF 9C A3 92 8F EF 5B 9A E4 E4 18 FC 15 E8 3E BE A0 F8 7F A9 FF 5E ED 70 05 0D ED 28 49 F4 7B F9 59 D9 56 85 0C E9 29 85 1F 0D 81 15 F6 35 B1 05 EE 2E 4E 15 D0 4B 24 54 BF 6F 4F AD F0 34 B1 04 03 11 9C D8 E3 B9 2F CC 5B

Проверка g_a и g_b

Помимо условий на простом dh_prime Диффи-Хеллмана и генераторе g, обе стороны должны проверить, что g, g_a и g_b больше 1 и меньше dh_prime - 1. Мы рекомендуем также проверить, что g_a и g_b находятся между 2^{2048-64} и dh_prime - 2^{2048-64}.

Проверка хеш-значения SHA1 при генерации ключей

Как только клиент получает ответ server_DH_params_ok на шаге 5) протокола генерации ключа авторизации и расшифровывает его, получая answer_with_hash, он ДОЛЖЕН проверить, что:
answer_with_hash := SHA1(answer) + answer + (0-15 random bytes)
Другими словами, первые 20 байт answer_with_hash должны быть равны SHA1 оставшейся части расшифрованного сообщения без заполнения случайными байтами.

Проверка полей nonce, server_nonce и new_nonce

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

Использование защищенного генератора псевдослучайных чисел для создания секретных параметров ДХ a и b

Клиент должен использовать криптографически защищенный PRNG для генерации секретных показателей a или b для обмена ключами ДХ. Для секретных чатов клиент может запросить некоторую энтропию (случайные байты) от сервера при вызове messages.getDhConfigи передать эти случайные байты в свой PRNG (например, PRNG_seed, если используется библиотека OpenSSL), но никогда не использовать эти "случайные" байты сами по себе или заменять ими локальное PRNG seed. Смешать байт, полученных от сервера в локальной PRNG seed.

Зашифрованные сообщения MTProto

Некоторые важные проверки должны быть сделаны при отправке и особенно получении зашифрованных сообщений MTProto.

Проверка хэш-значения SHA256 в msg_key

msg_key используется не только для вычисления ключа AES, но и для расшифровки полученного сообщения. После дешифрования клиент ДОЛЖЕН проверить, что msg_key действительно равен SHA256 открытого текста, полученного в результате дешифрования (включая последние 12...1024 байта заполнения), к которым добавляются 32 байта, взятые из auth_key, как описано в описании MTProto 2.0.
Если ошибка возникает до того, как эта проверка может быть выполнена, клиент должен выполнить проверку msg_key в любом случае, прежде чем возвращать какой-либо результат. Обратите внимание, что ответ на любую ошибку, возникшую перед проверкой msg_key, должен быть таким же, как и ответ на неудачную проверку msg_key.

Проверка длины сообщения

Клиент должен проверить, что длина сообщения или контейнера, полученного из расшифрованного сообщения (вычисленного из его поля длины), не превышает общего размера открытого текста и что разница (т. е. Длина случайного заполнения) лежит в диапазоне от 12 до 1024 байт.
Длина всегда должна быть делимой на 4 и неотрицательной. Ни в коем случае клиент не должен получать доступ к данным после окончания буфера дешифрования, содержащего открытое текстовое сообщение.

Проверка идентификатора session_id

Клиент должен проверить, что поле session_id в расшифрованном сообщении действительно равно полю активного сеанса, созданного клиентом.

Проверка параметр msg_id

Клиент должен проверить, что msg_id имеет четную четность для сообщений от клиента к серверу и нечетную четность для сообщений от сервера к клиенту.
Кроме того, идентификаторы (msg_id) последних N сообщений, полученных с другой стороны, должны быть сохранены, и если сообщение приходит с msg_id ниже всех или равно любому из сохраненных значений, то это сообщение должно быть проигнорировано. В противном случае новое сообщение msg_id добавляется в набор, и если число сохраненных значений msg_id больше N, то самое старое (то есть самое низкое) отбрасывается.
Кроме того, значения msg_id, которые принадлежат более чем 30 секундам в будущем или более чем 300 секундам в прошлом, должны быть проигнорированы (напомним, что msg_id приблизительно равен unixtime * 2^32). Это особенно важно для сервера. Клиент также счел бы это полезным (для защиты от повторной атаки), но только если он уверен в своем времени (например, если его время было синхронизировано с временем сервера).
Некоторые служебные сообщения клиент-сервер, содержащие данные, отправленные клиентом на сервер (например, msg_id недавнего запроса клиента), тем не менее могут быть обработаны на клиенте, даже если время кажется “неправильным”. Особенно это касается сообщений об изменении server_salt и уведомлений о недопустимом времени на клиенте. См. раздел Мобильный протокол: Служебные сообщения.

Поведение в случае несоответствия

Если одна из перечисленных выше проверок завершается неудачей, клиент должен полностью отбросить сообщение, полученное от сервера. Мы также рекомендуем закрыть и восстановить TCP-соединение с сервером, а затем повторить операцию или весь протокол генерации ключей.
Никакая информация из неверных сообщений не может быть использована. Даже если приложение выдает исключение и выключается, это гораздо лучше, чем продолжать работу с недопустимыми данными.
Обратите внимание, что недопустимые сообщения редко появляются во время обычной работы, даже если не происходит злонамеренного вмешательства. Это происходит из-за ошибок передачи данных по сети. Мы рекомендуем проигнорировать недопустимое сообщение и закрыть TCP-соединение, затем создать новое TCP-соединение с сервером и повторить исходный запрос.
Наверх