|
|
|
|
|
|
| Сетевая газета InfoSecurity.ru |
Безопасность при межпроектном взаимодействии
ВведениеСегодня множество интернет-сервисов взаимодействуют друг с другом через интернет. Особый класс взаимодействий — те, в которых осуществляется передача конфиденциальной информации (личные данные, секретные сообщения) или команд, выполнение которых должно быть кем-то однозначно подтверждено (например, перевод денег или публикация сообщения от чьего-то имени). Очевидно, что подобные сервисы должны быть надёжно защищены от злоумышленников.К сожалению, не все разработчики задумываются о степени защищённости своих приложений. Проблема несколько усугубляется тем, что многие представители электронного бизнеса разрабатывают протоколы, которые, будучи реализованными в конечных сервисах, могут создать серьёзные уязвимости, если использовать их без должного понимания. Задача данной статьи — кратко описать возможные типы атак при межпроектном (т. е. сервер-сервер) взаимодействии и средства защиты от них — с тем, чтобы более вдумчиво использовать готовые протоколы и разрабатывать свои. Предварительно будут рассмотрены основы информационной безопасности, так как зачастую знания конечных разработчиков в этой области бывают несколько отрывочными. Защита (или отсутствие защиты) от различных типов атак демонстрируется на примере протоколов популярных сегодня систем: Assist, Cyberplat, WebMoney, ChronoPay, Robokassa и PayPal (платёжные системы), а также OpenID, OpenAuth, OAuth (децентрализованная аутентификация). Безопасное взаимодействиеИтак, давайте определимся, что мы подразумеваем под словами «безопасное взаимодействие».1. Аутентификация. Пусть сервер А хочет передать сообщение серверу Б. Б должен иметь возможность проверить, что сообщение отправлено именно от А. Данная проверка называется аутентификацией сервера А на сервере Б. 2. Целостность данных. Мы хотим быть уверены, что сообщение при передаче не было изменено (например, было оплачено 50$, а подтверждение получено на 500$). 3. Конфиденциальность взаимодействия. Данный пункт подразумевает, что сообщение получают только те стороны, которые имеют на это право. Как правило, данный пункт подразумевает шифрование информации при передаче. В некоторых случаях можно рассматривать ещё два пункта: проверку прав доступа и невозможность отказа от авторства (non-repudiation), но сейчас мы оставим это в стороне. Криптографические примитивыЗдесь необходимо сделать некоторое отступление в теорию. Я не буду подробно расписывать основы криптографии (иначе объём статьи выйдет за рамки разумного), но кратко упомяну основные «криптографические примитивы», чтобы обозначить знания, необходимые для понимания дальнейшей части статьи. Желающие могут пройти по ссылкам на Википедию и узнать подробности.
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.
Реализация безопасности на практикеИтак, давайте теперь вернёмся ненадолго к «безопасному взаимодействию» и посмотрим, как реализуются на практике обозначенные нами пункты.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 лет. А всего-то надо — добавить цифровую подпись. Итак, каким образом осуществляют проверку авторства и целостности сообщения.
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, если сервер модифицировать нет возможности? Для защиты от такого типа атак существует несколько способов.
6. Для полноты описания (а также поскольку это иногда забывают) стоит упомянуть также банальности. Если система построена на секретности пароля или ключа, то эти данные должны быть надёжно защищены. Выставление UNIX-привилегий 07ХХ на доступ ко всем файлам на Shared-хостинге может закончиться тем, что файл сертификата или пароль к БД, где хранятся «секреты», прочитает «сосед по серверу». Не стоит забывать выставлять пароли, привилегии, разграничивать доступ. Впрочем, не буду долго распространяться, так как все это знают (хотя, не все делают). 7. Ещё один вид уязвимостей — те, что создаются программистами при реализации протокола. Приведу один простой пример (к счастью, не являющийся сколько-то серьёзной уязвимостью): 2 года назад в двух из пяти наиболее популярных реализациях OpenID-сервера разработчики перепутали понятия life_time (время жизни ключа в секундах) и expires_time (время истечения ключа в секундах от 1 января 1970). Особо критичные участки кода желательно подвергать просмотру другими участниками проекта (ОК, это тоже банальность? — тогда перейдём к заключению). ВыводыОсновная мысль, которую я хотел донести в статье — не стоит полагаться на разработчиков того или иного протокола, пусть даже авторами являются компании с громким именем. Думайте сами, решайте сами.Немножко про практику, а также что вышло за пределы статьи.
Источник: habr.ru
| |
|
|