Fork me on GitHub

Безопасность «Интернета вещей» - TLS / DTLS

Продолжаем исследовать сетевые протоколы.

TLS (Transport Layer Security) – криптографический протокол, обеспечивающий защищённую от прослушивания и подмены передачу данных между узлами в сети интернет. С технической точки зрения TLS располагается непосредственно над TCP (Transmission Control Protocol), что позволяет более высокоуровневым протоколам (таким как HTTP, MQTT и др.) работать без изменений. Исторически протокол TLS является наследником SSL (Secure Sockets Layer), изначально разработанном в Netscape для повышения безопасности электронной коммерции в Интернете.

Для UDP (User Datagram Protocol) была разработана специальная версия TLS, получившая название DTLS (Datagram Transport Layer Security). В то время как TCP обеспечивает обязательную доставку пакетов от источника к получателю, UDP пакеты могут потеряться и их последовательность не гарантируется. Протокол DTLS учитывает вышеуказанные отличия TCP и UDP.

ДЕМО

На картинке DTLS сервер на микроконтроллере c ОС Contiki на борту. Из коробки Contiki не умеет работать с TLS / DTLS, потому используется сторонняя библиотека TinyDTLS. Для обмена зашифрованными данными использовался нативный DTLS клиент из примеров самой TinyDTLS, но по идее клиент может быть любой с поддержкой IPv6:

~$ ping6 fe80::200:e2ff:fe58:b66e%mazko # bug ?
~$ cat <(echo Hello DTLS) - | \
./tinydtls/tests/dtls-client fe80::200:e2ff:fe58:b66e%mazko

ipv6.dtls.server | исходники

screenshot

В данном примере используется симметричное шифрование TLS_PSK (Pre-Shared Key) по AES алгоритму. Симметричный – значит, что для шифрования и дешифрования используется один и тот же секретный ключ (существуют также асимметричные алгоритмы, для шифрования используется один ключ, для дешифрования – другой). Ключ алгоритма должен сохраняться в секрете обеими сторонами, в данном случае он зашит в коде #define PSK_DEFAULT_KEY "secretPSK" и сервера и клиента.

screenshot

Для тех, кто не знает секретный ключ как например Wireshark на картинке ниже, зашифрованные данные не представляют никакой ценности – это выглядит как беспорядочный и бессмысленный набор байт. При использовании TLS / DTLS, «злоумышленнику» (иногда говорят «человек посередине») будет доступна информация о подключении (хост, порт, тип используемого шифрования), частоте и количестве передаваемой информации. Кроме того, он может разорвать соединение, но обе стороны будут знать, что соединение было прервано третьей стороной.

screenshot

ВВЕДЕНИЕ В КРИПТОГРАФИЮ

Криптография (от др.-греч. κρυπτός — скрытый и γράφω — пишу) — наука о методах обеспечения конфиденциальности (невозможности прочтения информации посторонним), целостности данных (невозможности незаметного изменения информации), аутентификации (проверки подлинности авторства или иных свойств объекта), а также невозможности отказа от авторства. — Википедия

Криптография включает в себя множество различных направлений, таких как шифрование, электронно-цифровая подпись, хеширование и т. д. Шифрование — это преобразование исходных данных («открытого текста») в видоизмененное состояние («закрытый текст») с целью скрыть содержимое «открытого текста» от потенциального «злоумышленника». Дешифрование — это обратная процедура, восстановление «открытого текста» из «закрытого». Понятия «открытый текст» и «закрытый текст» в данном случае подразумевают любую, не обязательно текстовую информацию.

Предположим, что сторона А (Алиса) хочет передать стороне Б (Боб) секретную информацию, чтобы никто, кроме Боба, не смог прочесть её. Для того чтобы «зашифровать» данные, можно переставить местами символы в исходном тесте по определенному алгоритму (шифр подстановки), известному только Алисе и Бобу. Такие алгоритмы шифрования, при которых Алиса и Боб должны заранее (до начала обмена данными) придумать и согласовать одинаковый секрет, называются симметричными.

Современные алгоритмы шифрования предполагают, что «злоумышленник» потенциально знает сам алгоритм шифрования (алгоритм преобразования над открытым тестом), имеет доступ к закрытому тексту и даже может знать фрагменты открытого текста (например «злоумышленник» может предположить, что открытый текст сообщения начинается с фразы «Добрый день!»). Единственное, что неизвестно «злоумышленнику», это некий «секрет» (секретный ключ шифрования) и единственный способ вычислить секретный ключ (и расшифровать информацию целиком) – это полный перебор всех возможных вариантов секретного ключа. Считается, что длина применяемых в современных алгоритмах ключей (например, 256 бит) не позволяет подобрать ключ перебором за приемлемое время. Экзотические способы вроде терморектального криптоанализа в расчёт не берём.

Для закрепления материала пример симметричного шифрования. Алиса хочет передать фразу "Some Secret", для этого она шифрует сообщение. Пароль пусть будет pass:

~$ echo "Some Secret" | \
openssl enc -aes-256-cbc -a -pass pass:pass -nosalt

На выходе Алиса получает зашифрованный текст и отправляет его по незащищённому каналу связи. Боб, получив зашифрованные данные, знает пароль и дешифрует их:

~$ echo "9pIRFLwioGc41Fw+aHLxuw==" | \
openssl enc -aes-256-cbc -d -a -pass pass:pass -nosalt

Чудненько, но как Бобу знать, что это именно Алиса отправила сообщение ? Да, «злоумышленник» не может расшифровать содержимое посылки, но что, если ему это и не нужно ? Ведь ничто не мешает «злоумышленнику» просто повторно отправить перехваченное ранее зашифрованное сообщение в нужный момент.

Предположим у нас есть передатчик и приемник, который управляет исполнительным механизмом (например, открывает дверь). Мы хотим открывать дверь по команде с передатчика. Естественно, мы хотим обезопасить себя, приемник должен реагировать только на «родной» передатчик. Записываем в передатчик и приемник одинаковый «секретный» пароль (ключ). Передатчик отправляет команду, приемник дешифрует паролем и открывает двери. Тем временем «злоумышленник» прослушивает радиоэфир и если он просто повторно отправит перехваченные ранее данные, двери откроются... Выходит одного шифрования недостаточно.

Рассмотрим решение подобной проблемы на «бытовом» примере. Предположим, я общаюсь со своим другом в чате. Я хочу убедиться, что я общаюсь именно с ним, а не с его дедушкой/бабушкой которая села за его компьютер. Я могу задать другу вопрос, ответ на который знает только он и я. У меня и у друга есть одинаковый «секретный» ключ шифрования. Я отправляю ему любой, абсолютно случайный фрагмент текста (случайное число) и прошу его зашифровать. Он шифрует фрагмент своим ключом и отправляет зашифрованный текст мне. Я расшифровываю полученный текст и сравниваю с оригиналом. Если исходный и расшифрованный фрагмент идентичны – значит я общаюсь действительно с другом, так как «правильно» зашифровать текст мог только он. В следующий раз, при необходимости аутентифицировать собеседника я вышлю новый, случайный, фрагмент текста и даже если «злоумышленник» перехватил предыдущий «сеанс аутентификации» – это ему ничего не даст, так как каждый раз будет новый запрос (новый фрагмент открытого текста) и соответственно новый ответ (закрытый текст).

TLS / DTLS

Протоколы TLS / DTLS предназначены для предоставления трёх услуг всем приложениям, работающим над ними: шифрование, аутентификацию и целостность. Для того чтобы установить криптографически безопасный канал данных, клиент и сервер должны согласовать параметры соединения, а именно: версия используемого протокола, способ шифрования данных, а также проверить сертификаты (в случае асимметричного шифрования). Процедура начала соединения называется Handshake (рукопожатие). Также в рамках процедуры Handshake клиент и сервер обмениваются случайными числами, т.е, происходит аутентификация – проверка соответствия субъекта и того, за кого он пытается себя выдать. После Handshake происходит обмен зашифрованными данными с проверкой целостности информации и защиты от её подмены.

PRE-SHARED KEY

Вернёмся к примеру с микроконтроллером. Клиент и сервер обладают общим секретом (ключом) и устанавливают соединение только если была установлена подлинность данного секрета. В общем случае для знакомства с PSK (pre-shared key) удобно воспользоваться каким-либо тестовыми сервером и клиентом.

Сервер DTLS-PSK:

~$ openssl s_server -port 20220 -psk 1a2b3c4d -nocert -dtls1_2

Клиент DTLS-PSK:

~$ openssl s_client -port 20220 -psk 1a2b3c4d -dtls1_2

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

PUBLIC KEY

В современных интернетах наибольшее распространение получило асимметричное шифрование, которое предполагает наличие двух ключей – публичного и приватного. Сообщение шифруется публичным ключом, а расшифровывается приватным. В основе данной магии лежит математика и односторонние функции с потайным входом, то есть такие функции, у которых по известному x довольно просто найти значение f(x), тогда как обратное определение x из f(x) невозможно за разумный срок без специальной информации (секрета), называемой «лазейкой» или «потайным входом».

Упрощённо шифрование с открытым ключом можно представить в виде обычного (например навесного) замка с автоматической защёлкой. Любой способен запереть замок, просто защелкнув его, чтобы он закрылся, но отпереть его может только тот, у кого есть ключ. Запереть замок (зашифровывать данные) легко, почти все могут это сделать, но открыть его (расшифровывать данные) имеет возможность только владелец ключа. Понимание того, как защелкнуть замок, чтобы он закрылся, ничего не скажет вам, как его отпереть.

Для начала экспериментов нужно сгенерировать пару ключей (открытый и закрытый).

~$ openssl req -x509 -days 365 -nodes -newkey rsa:2048  \
    -subj "/CN=localhost" -keyout selfsigned.key -out selfsigned.crt

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

~$ openssl s_server -key selfsigned.key -cert selfsigned.crt -accept 44330 -www

Для установки защищённого соединения по незащищённому каналу клиенту нужен только открытый ключ.

~$ curl https://localhost:44330 -v --cacert selfsigned.crt

Вот что по этому поводу думает Wireshark. Из списка всех поддерживаемых клиентом (Client Hello) алгоритмов шифрования сервер выбрал TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:

screenshot

Нераскрытым остался один вопрос – как передать открытый ключ так, чтобы его нельзя было подменить ? Каждый день в сети появляются / исчезают тысячи ресурсов и физически сложно было бы поставлять / обновлять все их открытые ключи сразу вместе с клиентом (браузером). Тут на помощь приходят т.н. центры сертификации (англ. Certification authority, CA) – стороны, чья честность неоспорима, а открытый ключ широко известен и клиент (curl, браузер) его никогда не запрашивает по незащищённому каналу. Задача центра сертификации – подтверждать подлинность ключей шифрования с помощью сертификатов электронной подписи.

Асимметричное шифрование используется только в процедуре TLS Handshake во время первоначальной настройки соединения. После настройки туннеля в дело вступает симметричная криптография, и общение в пределах текущей сессии зашифровано именно установленными симметричными ключами. Это необходимо для увеличения быстродействия, так как криптография с открытым ключом требует значительно больше вычислительной мощности. Ну как-то так.

links

social