Pull to refresh

Безопасность при межпроектном взаимодействии

Reading time15 min
Views5.2K

Введение


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

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

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

Защита (или отсутствие защиты) от различных типов атак демонстрируется на примере протоколов популярных сегодня систем: Assist, Cyberplat, WebMoney, ChronoPay, Robokassa и PayPal (платёжные системы), а также OpenID, OpenAuth, OAuth (децентрализованная аутентификация).

Безопасное взаимодействие


Итак, давайте определимся, что мы подразумеваем под словами «безопасное взаимодействие».

1. Аутентификация. Пусть сервер А хочет передать сообщение серверу Б. Б должен иметь возможность проверить, что сообщение отправлено именно от А. Данная проверка называется аутентификацией сервера А на сервере Б.

2. Целостность данных. Мы хотим быть уверены, что сообщение при передаче не было изменено (например, было оплачено 50$, а подтверждение получено на 500$).

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

В некоторых случаях можно рассматривать ещё два пункта: проверку прав доступа и невозможность отказа от авторства (non-repudiation), но сейчас мы оставим это в стороне.

Криптографические примитивы


Здесь необходимо сделать некоторое отступление в теорию. Я не буду подробно расписывать основы криптографии (иначе объём статьи выйдет за рамки разумного), но кратко упомяну основные «криптографические примитивы», чтобы обозначить знания, необходимые для понимания дальнейшей части статьи. Желающие могут пройти по ссылкам на Википедию и узнать подробности.
  • Существуют различные системы симметричного шифрования. Основа этих систем — один ключ К, который известен обеим сторонам. Данный ключ используется как для шифрования, так и для расшифровки сообщения. Примеры стандартов: RC2, RC4, RC5, DES, 3-DES, AES, Blowfish, ГОСТ 28147-89 и т. д.
  • Существуют асимметричные системы шифрования. Здесь каждая сторона имеет секретный ключ и открытый ключ. Открытый известен всем (в том числе, криптоаналитикам, желающим взломать систему), секретный — только одной стороне. Любой человек может использовать открытый ключ стороны А, чтобы зашифровать сообщение ДЛЯ стороны А. Расшифровать же это сообщение может ТОЛЬКО владелец секретного ключа, то есть А. Пример стандарта: RSA.
  • Как правило, открытый ключ распространяется в виде т. н. сертификатов. Вообще говоря, открытый ключ — только часть сертификата, но в дальнейшем я буду использовать эти термины как синонимы.
  • Эта же пара, секретный и открытый ключ, как правило, может использоваться для формирования цифровой подписи (ЦП). В этом случае, подобно тому, как в бумажном документе присутствует подпись человека, в тело электронного сообщения включается цифровая подпись, сгенерированная на основе сообщения и секретного ключа. Подпись невозможно сгенерировать без использования секретного ключа, но проверить её могут все, используя соответствующий открытый ключ. Таким образом мы можем убедиться в том, что сообщение отправлено именно нужным нам сервером или человеком, а не было «фальшивкой». Протоколы: RSA, DSA, ECDSA, ГОСТ Р 34.10-2001.
  • Существуют протоколы, которые позволяют двум сторонам сгенерировать общий ключ К, не передавая его по каналу. Примеры протоколов — Diffie-Hellman Key Exchange Protocol (далее для краткости просто Diffie-Hellman), SRP. Первый, к примеру, используется в популярной сегодня системе OpenID.
  • Существуют хеш-функции, сопоставляющие тексту набор бит фиксированной длины. Считается, что задача нахождения двух текстов, имеющих один и тот же хеш, «очень сложная». Примеры: MD5 (который уже «сломали»), SHA-1, SHA-256, ГОСТ Р 34.11-94.
  • Существуют коды Hash Message Authentication Code (HMAC). Это функция от сообщения и некоторого ключа, также дающая на выходе хеш-строку фиксированной длины. Если обе стороны обладают секретным ключом K, то можно использовать HMAC-функцию как способ формирования цифровой подписи в симметричной криптосистеме, так как сформировать и проверить подпись сообщения смогут только 2 стороны, имеющих ключ.

SSL/TLS и HTTPS


Говоря о «безопасности взаимодействия», можно задать резонный (в чём-то) вопрос: всё это: аутентификация, поддержка целостности, шифрование, есть в SSL/TLS (HTTPS). Зачем нужно что-то ещё?

Поэтому вторым экскурсом в теорию будет краткое напоминание того, что такое SSL/TLS и HTTPS.

Протокол SSL (Secure Socket Layer) и его «потомок» TLS (Transport Layer Security) был разработан в ответ на потребность в безопасном клиент-серверном взаимодействии. Протокол работает на транспортном уровне модели OSI. При грамотном использовании он позволяет установить шифрованное соединение между клиентом и сервером. Протокол защищён от модификации и чтения сообщений, отправляемых в обе стороны. Также протокол позволяет клиенту (повторюсь: при грамотном использовании) убедиться в том, что он установил соединение именно с нужным сервером, а не с сервером мошенника (другими словами, клиент может аутентифицировать сервер). Существуют модификации, которые позволяют пройти аутентификацию клиенту, т. е. обеспечить двустороннюю аутентификацию.

HTTPS (HTTP Secure) — это тот же HTTP, но отправляемый по каналу, защищённому протоколом SSL/TLS.

Очень важно понимать, что наличие SSL/TLS-канала в неполной реализации означает только то, что соединение между вашей точкой и удалённым сервером проходит по протоколу, хорошо защищённому с точки зрения прослушивания и подмены информации. Но это ничего не значит, пока вы не убедились, что удаленная сторона — именно та, с которой вы хотели связаться. Убедиться же в этом можно, только если сертификат удалённой стороны известен вам заранее, и вы ему доверяете, либо если тот же сертификат вы получаете по незащищённому каналу, но подписанный «третьей стороной», т. н. сертификационным центром (Certification Authority или CA). При этом открытый ключ CA, используемый для проверки подписи, опять же должен быть известен вам заранее, чтобы не пришлось его передавать по незащищённому каналу. К примеру, как обеспечивается эта безопасность в браузерах? Сертификаты основных CA (наиболее известные — COMODO, VeriSign, Go Daddy, Thawte и т. д., всего их несколько десятков), встраиваются в ваш браузер заранее.

А как осуществить проверку сертификата в коде своего сервиса? Если у вас есть сертификат заранее, сделать это довольно просто (например, PHP-программистам можно смотреть в сторону curl_setopt(), опции CURLOPT_CAINFO и CURLOPT_CAPATH). Именно подобным образом обеспечивается безопасность соединения в коде взаимодействия с сервером WebMoney. Если же вам заранее неизвестен CA-сервер, сделать подобную проверку на практике несколько сложнее, потому что вам придётся самим подбирать и поддерживать коллекцию сертификатов различных CA.

На практике проверку сертификата в коде часто не выполняют, что может привести к одной из двух атак: подмене сервера или атаке «Человек посередине» (Man in the Middle, MITM). Последнее означает, что между вами (А) и конечным сервером (Б) находится ещё один сервер (М). Вы (А) устанавливаете абсолютно защищённое соединение с М, думая, что установили соединение с Б. После этого М устанавливает безопасное соединение с Б и начинает передавать ему ваши запросы, а вам — его ответы. Таким образом, М может прослушивать взаимодействие А — Б и даже модифицировать передаваемые сообщения.

Логичен вопрос, насколько атаки подмены сервера и «Человек посередине» осуществимы на практике.

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

Итак, почему нас не всегда устраивает SSL/TLS.
  • Cложность проверки подлинности произвольного сервера в коде приложения. Как следствие — частичное использование протокола, без защиты от атаки «Человек посередине».
  • Односторонняя аутентификация (да, есть модификации протокола для двусторонней, но это используется реже, и не для всех языков программирования легко найти готовое решение).
  • Кроме того, архитектура SSL/TLS не позволяет сохранить сообщение с цифровой подписью отправителя с тем, чтобы позже использовать это для доказательства того, что сообщение действительно было отправлено автором (т. е. не работает защита от отказа от авторства).

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


Итак, давайте теперь вернёмся ненадолго к «безопасному взаимодействию» и посмотрим, как реализуются на практике обозначенные нами пункты.

1. Для аутентификации используют обычно либо пару «логин — пароль», либо цифровую подпись, сгенерированную тем или иным методом.

2. Для проверки целостности данных используют SSL/TLS и формируемые приложением цифровые подписи.

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

Говоря о веб-сервисах, чаще всего SSL/TLS используют в виде HTTPS.

Типы защищаемых приложений


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

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

2. Централизованная архитектура. Каждые 2 стороны не имеют возможности договориться друг с другом заранее, но любой участник сети доверяет некоторой третьей стороне, которая подписывает сертификаты взаимодействующих сторон и гарантирует их валидность. В качестве примера можно назвать инфраструктуру открытых ключей (Public Key Infrastructure, PKI) или, с некоторыми оговорками, тот же интернет, в котором браузеры доверяют конечному числу сертификационных центров (CA), и на основе этого могут убедиться, что они взаимодействуют с нужным сайтом.

3. Децентрализованная архитектура. В подобных приложениях нет единой третьей стороны. Важно понимать, что в подобных архитектурах основная задача — убедиться в том, что во второй раз к вам пришёл тот же самый человек, что приходил ранее. То есть, в первый раз вы позволяете пройти аутентификацию кому угодно (например, на сайтах, поддерживающих OpenID, любой может пройти аутентификацию). Пусть далее вы сделали какой-то вклад в систему: например, написали сообщение. Когда вы придёте сюда в следующий раз, сайт должен будет предоставить вам (и только вам) доступ к редактированию этого сообщения. Примеры притоколов: OpenID, OAuth, протоколы Peer-to-Peer.

Атаки и способы защиты


Ну и, наконец, давайте рассмотрим основные типы атак, осуществляемых на протоколы — и как от них защищаются.

1. Отсутствие проверки авторства или подлинности сообщения

Позволю себе вспомнить старую шутку. В программировании существует два типа ошибок: отсутствие проверки входных данных — и все остальные ошибки.

Если вам пришло сообщение М от стороны А, то надо убедиться, что: а) сообщение действительно пришло от А; б) что А отсылал именно сообщение М, и оно не было изменено по пути.

Примером неграмотно спроектированного протокола является протокол взаимодействия платёжной системы Assist с интернет-магазином. После оплаты покупки на сервере Ассиста, пользователь возвращается по некоторому адресу URL_RETURN_OK, который передаётся в открытом виде и может быть модифицирован самим пользователем-покупателем. То есть, пользователь возвращается после оплаты покупки в наш интернет-магазин, ему говорят: «Спасибо, вы только что оплатили платёж на сумму 1000$», — но у магазина нет абсолютно никакой возможности убедиться в том, что это действительно так. Только позже, руками менеджера или автоматизировано (но не чаще 1 раза в 10 минут!) можно проверить, что платёж действительно прошел. Протокол Ассиста, к слову, не модифицировался уже более 4 лет. А всего-то надо — добавить цифровую подпись.

Итак, каким образом осуществляют проверку авторства и целостности сообщения.
  • Используют цифровые подписи на базе пары из секретного и открытого ключа. Вероятно, это самый надёжный и универсальный (т. е. работающий в любых условиях) способ. Открытый ключ может передаваться принимающей стороне заранее (подобный способ используют сегодня WebMoney, Cyberplat, OAuth и многие другие). Также открытый ключ может быть получен позже по незащищённому соединению и проверен при помощи сертификата сертификационного центра (Certification Authority, CA). Этот способ лежит в основе функционирования инфраструктуры открытых ключей (Public Key Infrastructure, PKI), используемой в крупных компаниях.
  • Формируют общий ключ К — например, на основе протокола Diffie-Hellman или аналогичного и используют его для подписывания сообщений (например, с использованием HMAC-SHA1). Используется в OpenID.
  • Если нам не важна целостность сообщения, а важно только подтверждение авторства, иногда используют пару «логин — пароль» или секретную строку для доступа к защищённому ресурсу. Например, Flickr отдаёт фотографии по протоколу XML-RPC в ответ на запрос, содержащий логин и пароль. Система reCAPTCHA позволяет проверить CAPTCHA-код, введённый пользователем, аутентифицируя проверяющего по секретной строке. Надо понимать, что этот способ, хотя и прост, крайне плох тем, что перехват сообщения раскрывает ваш пароль, и в дальнейшем злоумышленник может свободно отправлять запросы от вашего имени. В случае использования цифровой подписи перехват сообщения ничего не позволит сделать злоумышленнику.
  • Есть более простой (хотя и незащищённый от атак подмены сервера и «Человек посередине») способ проверки подлинности сообщения. Например, PayPal в своём протоколе Instant Payment Notification (IPN) обязывает сервер, принимающий подтверждение о проведённой оплате, отправлять копию сообщения обратно на сервер с вопросом «действительно ли ты мне это посылал»? Аналогичный способ используется в протоколе OpenID (правда, при работе в нерекомендованном режиме), только обратно отсылается не просто сообщение, а сообщение с цифровой подписью, и запрос выглядит уже как «проверь, ты ли ставил эту цифровую подпись». Похожая схема работает и в OpenAuth. Преимуществом подхода можно считать отсутствие необходимости реализовывать криптографические алгоритмы с одной или с двух сторон.
  • Робокасса придумала свой оригинальный способ формирования цифровой подписи: цифровая подпись формируется как хеш-функция MD5 от сообщения и секретного пароля. К данному способу надо относиться с осторожностью хотя бы потому, что пароль должен быть достаточно надёжен. Если пароль короткий, и, тем более, если он выбирается человеком, расшифровка вашего пароля может оказаться несложной задачей для хакера.

2. Надежда на надёжность HTTPS.

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

Ни один из протоколов децентрализованной аутентификации — будь то OpenID, OpenAuth, OAuth, не защищён от атаки подмены сервера или «Человек посередине». В некоторых случаях платёжные системы (PayPal, Assist) можно атаковать подобным способом. В итоге, вы можете убедить приложение интернет-магазина в том, что произошла оплата, хотя на самом деле её не было.

Подчеркну ещё раз, что от этой атаки можно защититься, если устанавливающий HTTPS-соединение сервер обладает достаточным количеством сертификатов основных CA Интернета (VeriSign, COMODO и т. д.), но на практике это иногда сложно реализуемо.

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

3. Атака «Человек посередине» (Man in the Middle, MITM).

Мы рассмотрели атаку MITM для протокола HTTPS. Однако, другие протоколы также могут быть уязвимы для такого типа атак.

Пример тому — Diffie-Hellman, использующийся в OpenID. Как указывалось выше, его суть в генерации общего ключа К двумя сторонами: А и Б. Но если у нас есть кто-то «посередине» (М), кто может изменять трафик, то может оказаться так, что А сгенерировал общий с М ключ К1, а Б — общий с М ключ К2. В итоге «Человек посередине» М может подписывать и читать любые данные, идущие в любом направлении.

Разумеется, подобная атака не пройдёт в OpenID, если клиент и сервер (OpenID Provider и Relying Party) взаимодействуют по HTTPS с полноценной проверкой сертификата.

4. Передача секретного ключа по открытому каналу.

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

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

Если вы создаёте протокол для платёжной системы, идеальным является передача открытого ключа вашего сервера лично в руки владельцу интернет-магазина (на дискете или флешке) при подписании договора в офисе. Да, по тем или иным причинам это не всегда реально осуществить. Поэтому сертификат часто распространяют через интернет. Но в этом случае надо предпринять все возможные меры по предотвращению подмены ключа. Нельзя присылать ключ по электронной почте. Нельзя давать его скачивать по HTTP — только HTTPS. На сайте должна быть размещена информация по проверке скаченной информации (например, хеш от ключа для проверки его подлинности).

5. Повторная отправка запроса.

Данный вид атаки мы рассмотрим на двух примерах.

Пример 1: платёжная система. Пусть я, добропорядочный сервер, хочу отправить 10$ через платёжную систему. При этом для соединения с сервером платёжной системы я использую HTTP или «плохой» HTTPS (без проверки сертификата). Я честно формирую запрос и подписываю его своим сертификатом. Другая сторона получает запрос, и мои 10$ уходят адресату. Но поскольку я использовал открытый протокол, злоумышленник смог прочитать мой запрос к серверу. Если этот злоумышленник хочет меня разорить, он берёт и отправляет тот же самый запрос серверу платёжной системы ещё раз. Сервер проверяет подпись (она верная, так как сформирована «правильным» сервером), и другие 10$ списываются с моего счёта.

Пример 2: протокол OpenID. В протоколе OpenID Authentication 1.1 была следующая уязвимость. Если злоумышленник прослушивал взаимодействие OpenID-клиента (Relying Party) и конечного пользователя, он мог через какое-то время инициировать повторную аутентификацию этого пользователя на Relying Party с использованием его OpenID. В этом случае в логах Relying Party появилась бы запись, что человек заходил на сайт. В особо бездумных случаях реализации злоумышленник мог даже пройти аутентификацию под именем этого пользователя. Да, против этого есть способы защиты, но они не были заявлены как обязательные в протоколе.

Данную уязвимость устранили в версии OpenID Authentication 2.0, введя изменения в поведение как сервера (OpenID Provider), так и клиента (Relying Party). Читателям, знакомым с протоколом OpenID Authentication, предлагаю задачку на понимание: как реализовать подобную защиту в клиенте OpenID версии 1.1, если сервер модифицировать нет возможности?

Для защиты от такого типа атак существует несколько способов.
  • Cyberplat, например, обязует своих клиентов в каждый запрос вставлять уникальный номер сессии. Такой уникальный номер называют также словом nonce (Number used ONCE). Два запроса с одинаковым номером сессии платёжная система просто откажется обрабатывать. А изменить номер сессии злоумышленник не сможет, так как он не имеет возможности сформировать правильную цифровую подпись для изменённого сообщения.
  • Можно также использовать защиту по времени, вставляя в запрос метку с текущим временем. «Старые» запросы отсекаются.
  • OpenID 2.0 использует оба эти метода для защиты от подобного типа атак: nonce включает текущее время и (необязательно) случайную строку.

6. Для полноты описания (а также поскольку это иногда забывают) стоит упомянуть также банальности. Если система построена на секретности пароля или ключа, то эти данные должны быть надёжно защищены. Выставление UNIX-привилегий 07ХХ на доступ ко всем файлам на Shared-хостинге может закончиться тем, что файл сертификата или пароль к БД, где хранятся «секреты», прочитает «сосед по серверу». Не стоит забывать выставлять пароли, привилегии, разграничивать доступ. Впрочем, не буду долго распространяться, так как все это знают (хотя, не все делают).

7. Ещё один вид уязвимостей — те, что создаются программистами при реализации протокола. Приведу один простой пример (к счастью, не являющийся сколько-то серьёзной уязвимостью): 2 года назад в двух из пяти наиболее популярных реализациях OpenID-сервера разработчики перепутали понятия life_time (время жизни ключа в секундах) и expires_time (время истечения ключа в секундах от 1 января 1970). Особо критичные участки кода желательно подвергать просмотру другими участниками проекта (ОК, это тоже банальность? — тогда перейдём к заключению).

Выводы


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

Немножко про практику, а также что вышло за пределы статьи.
  • Инфраструктура открытых ключей (Public Key Infrastructure, PKI) — решение, поражающее своей масштабностью (и, в частности, числом протоколов). Вероятно, это не то, что стоит изучать для написания сервиса автоматического кросспостинга заголовков блога в Твиттер. Также вам, скорее всего, не сюда, если речь идёт про децентрализованные системы. Но даже в этом случае ознакомиться в общих чертах — полезно. Начать можно с Internet X.509 Public Key Infrastructure: Roadmap.
  • Также сегодня разработано большое количество стандартов для обеспечения безопасности веб-сервисов (в первую очередь, построенных на SOAP). Этому посвящена масса статей. (Например, в заметке Securing Web Services собрано некоторое количество ссылок по тематике.) Поэтому перед разработкой своего решения, может быть, стоит познакомиться с уже существующими разработками.
Tags:
Hubs:
+23
Comments28

Articles

Change theme settings