- PVSM.RU - https://www.pvsm.ru -
Мы разрабатываем Flash клиент для клиент-серверного приложения с постоянным сокетным соединением и нам важно защититься от прослушки трафика. Один из способов такой защиты — SSL/TLS шифрование. Во Flash сделать это можно двумя путями — использовать родной SecureSocket [1] или TLSSocket из библиотеки as3crypto [2]. Ниже мы обсудим плюсы и минусы, производительность, а также проблемы с которыми мы столкнулись при внедрении обоих вариантов.
SSL/TLS это надстройка над сокетом для предотвращения прослушивания и выполняет две функции — аутентификация участников (сервер и клиент) и шифрование трафика. Основной функционал сокетов для наглядности оформлен в виде таблицы:
Сравнение SecureSocket и TLSSocket, “+” — не выявелено проблем, “-” — не поддерживается или не работает, “±” — работает но с ошибками или работает не для всех случаев, “?” — не удалось проверить из-за предыдущих ошибок, “-?” — заявлено что работает, но подтвердить не удалось
Для работы SecureSocket требуется Flash Player 11-й версии и выше, который установлен только у 75% пользователей [3], т.е. для оставшихся 25% в любом случае придется использовать TLSSocket.
SecureSocket интегрирован в систему, что позволяет ему работать с системным хранилищем сертификатов и системными средствами проверки их подлинности, т.е. серверный сертификата реально будет проверен через центр сертификации, чего никогда не сможет сделать TLSSocket. SecureSocket так же позволяет добавить собственный сертификат, который будет считаться доверенным, но все равно проверит его на другие ошибки (срок годности, несоответствие Common Name в сертификате и имени сервера) и если что не так, обрубит соединение, поэтому старые тестовые сертификаты (думаю, почти у каждого разработчика такие найдутся) скорее всего не подойдут.
SSL 3.0 (далее по тексту под SSL всегда подразумевается SSL 3.0) тестировали на своих серверах в принудительном SSL режиме. Клиент закрывал соединение с неопознанным статусом проверки сертификата (serverCertificateStatus = invalid) на всех сертификатах, что мы пробовали, в том числе официально подписанном. Замечу, что на 443й порт публичных серверов (google.com, yandex.ru) сокет заходит успешно, но там скорее всего выбирается TLS протокол, а форсировать использование только одного из двух протоколов TLS или SSL SecureSocket не позволяет, так же как и не обращает внимание на настройки TLS/SSL в браузере, в котором запускается swf. Не берусь утверждать, что SSL 3.0 в принципе не работает, все-таки его поддержка заявлена в официальной документации, но нам заставить его работать не удалось.
TLS заработал сразу и на обоих сертификатах. С работающим сокетом удалось оценить скорость работы по сравнению с незащищенным протоколом, здесь нас ждало большое разочарование, об этом ниже.
В работе с сертификатами TLSSocket имеет несколько слабых мест:
Однако есть и положительный момент, библиотека предоставляет несколько флагов для работы даже с невалидными сертификатами (несовпадение имени сервера в сертификате и реального, самоподписанные сертификаты) открытость кода позволяет дописать недостоющий функционал (например флаг игнорирования истечения срока годности сертификата или то же добавление собственных сертификатов)
/**
* Add own your own trusted certificate
* @param cert A ByteArray object containing a DER-encoded X.509 digital certificate.
*/
public function addTrustedCertificate(cert:ByteArray):void
{
var md5:String = Hex.fromArray(new MD5().hash(cert));
trustedCertificates[md5] = true;
}
/**
* Check whether the certificate is marked as trusted
* @param cert X509Certificate object to check
*/
public function isTrustedCertificate(cert:X509Certificate):Boolean
{
var md5:String = cert.md5;
return trustedCertificates[md5];
}
private function load():void
{
...
} else if (p is ByteArray) {
b = p;
}
_bytes = b;
...
}
private var _bytes:ByteArray;
private var _md5:String;
/**
* get md5 hash for certificate
*/
public function get md5():String
{
if(_md5)
{
return _md5;
}
if (_bytes)
{
_md5 = Hex.fromArray(new MD5().hash(_bytes));
} else
{
throw new Error("get md5: Invalid x509 Certificate parameter");
}
return _md5;
}
...
} else if (_config.isTrustedCertificate(firstCert)) {
certTrusted = true;
} else if(_config.trustSelfSignedCertificates )
{
// Self-signed certs
certTrusted = firstCert.isSelfSigned(new Date);
}else
{
...
Пример использования:
package
{
import com.hurlant.crypto.tls.TLSConfig;
import com.hurlant.crypto.tls.TLSEngine;
import com.hurlant.crypto.tls.TLSSecurityParameters;
import com.hurlant.crypto.tls.TLSSocket;
import com.hurlant.util.der.PEM;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.utils.ByteArray;
public class addcerttest extends Sprite
{
[Embed(source="cert.pem", mimeType="application/octet-stream")]
private static const cert_pem:Class;
public function addcerttest()
{
var cert_pem_bytes:ByteArray = new cert_pem();
var cert_der:ByteArray = PEM.readCertIntoArray(cert_pem_bytes.readUTFBytes(cert_pem_bytes.bytesAvailable));
var config:TLSConfig = new TLSConfig(TLSEngine.CLIENT, null, null, null, null, null, TLSSecurityParameters.PROTOCOL_VERSION);
config.addTrustedCertificate(cert_der);
var socket:TLSSocket = new TLSSocket(null, 0, config);
socket.addEventListener(Event.CONNECT, log);
socket.addEventListener(Event.CLOSE, log);
socket.addEventListener(IOErrorEvent.IO_ERROR, log);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, log);
socket.connect("my.app.server", 443);
}
private function log(event:Event):void
{
trace(event.type);
}
}
}
У TLSSocket шифрование трафика заработало в обоих протоколах, но в SSL ломается шифрование пакетов на клиенте после нескольких минут работы клиента. Ломается скорее всего из-за какой-то баги в библиотеке, искать не стали, т.к. TLS работает без проблем.
В as3crypto вообще довольно большой список багов [6] и проблема усугубляется тем, что разработчики перестали обновлять библиотеку.
С SecureSocket возникла новая проблема — периодически (раз в 5-10 запросов) сокет «уходит в себя» на 2-8 секунд без видимых причин. Я не берусь утверждать, что такие лаги будут у всех, но у нас они были, причем на том же сервере. на котором TLSSocket работал быстро, т.е. дело на клиентской стороне. Тестировали в “чистой” демке без обвязки в виде приложения. Зависимость времени парсинга от размера пакета установить не удалось, пробовали пакеты от 30 байт до 5 кб, зависания появлялись в разные времена на случайных пакетах, процессор во время зависаний не грузился, fps не падал. Сам же парсинг пакетов быстрый, если брать только пакеты без зависаний разницы между Socket и SecureSocket незаметно, в то время как TLSSocket все же медленнее чем Socket. Попробую разобраться с этим позже, т.к. хотелось бы все же иметь быстро работающий родной вариант.
Поскольку вся реализация здесь на as3 время парсинга пакетов линейно пропорционально размеру и для пакетов на 2-7 кб (максимальные в нашем проекте) на core i7 составило 40-120 мс соответственно, мелкие пакеты с runtime оповещениями парсятся влёт (5-20 мс для пакетов в 100-500 байт) и никаких лагов не вызывают. Для пользователя добавление SSL/TLS будет заметно только на больших пакетах.
Все проверили и отладили, теперь, выкладываем сборку на http сервер, не забыв настроить socket policy server [7]. Запускаем приложение, видим, что оба сокета не работают. Причины у каждого свои: TLSSocket не работает из-за issue 4 [8] — клиент посылает запрос на «рукопожатие» раньше, чем устанавливается соединение. С SecureSocket немного сложнее, чтобы Flash Player разрешил открыть TLS/SSL соединение, файл политик с сервера придется отдавать так же по TLS/SSL протоколу, т.е. потребуется доработка раздатчика этого файла.
SecureSocket интегрирован в систему, что позволяет ему работать с системным хранилищем сертификатов и системными средствами проверки их подлинности, чем не может похвастаться TLSSocket. Однако на этом преимущества SecureSocket заканчиваются. Из явных недостатков отмечу секундные лаги при парсинге входящих данных, неработающий SSL 3.0 и вообще отладочную молчаливость если что-то не работает, свойственную многим родным as3 решениям. TLSSocket же отличается быстрой скоростью и возможностью поправить (или по крайней мере разобраться в причине) ошибки в работе, предоставляя свои исходники.
Спасибо, кто дочитал до конца, надеюсь материал окажется полезным и кому-то сэкономит время. Опечатки и ошибки прошу отправлять в личку. Неточности и дополнения буду рад обсудить в комментариях.
Ссылка на GitHub as3crypto_patched [9] с патчами, которые упоминались в статье и функционалом добавления внешних доверенных сертификатов.
Автор: FSB
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/as3/23470
Ссылки в тексте:
[1] SecureSocket: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/SecureSocket.html
[2] as3crypto: http://code.google.com/p/as3crypto/
[3] 75% пользователей: http://www.statowl.com/flash.php
[4] issue 26: http://code.google.com/p/as3crypto/issues/detail?id=26
[5] дыру в безопасности: http://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:%D0%9A%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D1%81_%D0%BE%D1%82%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D0%BC_%D0%BA%D0%BB%D1%8E%D1%87%D0%BE%D0%BC_%D0%B8_%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%BC_%D0%BF%D0%B5%D1%80%D0%B5%D1%85%D0%B2%D0%B0%D1%82%D1%87%D0%B8%D0%BA%D0%BE%D0%BC.png
[6] список багов: http://code.google.com/p/as3crypto/issues/list
[7] socket policy server: http://www.adobe.com/cn/devnet/flashplayer/articles/socket_policy_files.html
[8] issue 4: http://code.google.com/p/as3crypto/issues/detail?id=4
[9] as3crypto_patched: https://github.com/fsbmain/as3public/tree/master/as3crypto_patched
[10] Источник: http://habrahabr.ru/post/155625/
Нажмите здесь для печати.