Криптографические сервисы и защита данных в Windows Azure

OSzone.net » Microsoft » Разработка приложений » Облако/Azure » Криптографические сервисы и защита данных в Windows Azure
Автор: Джонатан Уиггс
Иcточник: Журнал MSDN
Опубликована: 23.01.2011

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

Как и в случае любой другой новой платформы или метода доставки сервисов, вы столкнетесь с новыми вызовами. Кроме того, вам напомнят, что некоторые классические проблемы никуда не делись и что некоторые из решений, применявшихся вами ранее, по-прежнему будут работать нормально. Любой инженер или проектировщик приложения должен подумать об этом, так как это может относиться к тем данным, которые вы храните. И если все это объединить и систематизировать, то в результате все (как вы, так и ваши клиенты) будут довольны.

С чего я решил, что эта информация нужна сообществу разработчиков? За последние несколько месяцев я заметил, насколько увеличилось количество статей на сайтах сообщества, относящихся к безопасности Azure в целом. Microsoft предложила шифрование как элемент защиты данных прикладного уровня для проектов с Azure. Однако проектировщикам и разработчикам на платформе Windows Azure необходимо должное понимание как шифрования, так и модели защиты в .NET.

И в немалой части этих статей предпринимаются попытки разобраться в криптографических сервисах и хранилище ключей. Это особенно важно при использовании сервисов Windows Azure Storage. В общем, мне самому стало любопытно, и я обнаружил, что эту тематику стоит обсудить поглубже.

На протяжении всей статьи я буду интенсивно пользоваться провайдерами криптографических сервисов (Cryptographic Service Providers, CSP), которые являются реализациями криптографических стандартов, алгоритмов и функций, представленных в программном интерфейсе системы. Для целей этой статьи я буду использовать алгоритм симметричного шифрования, предоставляемый криптографическим классом Rijndael.

Основы криптографических сервисов

Windows Azure SDK расширяет базовые библиотеки .NET, чтобы разработчики могли интегрировать и использовать сервисы, предоставляемые Windows Azure. Доступ к CSP в проектах и сервисах Windows Azure не ограничен. То есть с учетом сборок, к которым вы уже привыкли, большая часть работы, относящейся к шифрованию и дешифрованию данных, останется прежней. Однако в нижележащей архитектуре произошли изменения, связанные с тем, когда вы шифруете данные и где вы храните ключи. Хранение ключей и секретных данных мы обсудим чуть позже.

Вы также можете получить доступ к полной функциональности криптографических хешей в Windows Azure, например MD5 и SHA. Они жизненно важны для повышения защиты любых систем за счет обнаружения дублирующихся данных, индексации хеш-таблиц, проверки сигнатур сообщений и паролей и др.

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

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

Ниже приведен код, реализующий единственный статический член, который возвращает 32-битное значение типа int — оно является случайным и отвечает требованиям стойкого шифрования. Это стало возможным благодаря генератору байтов в RNGCryptoServiceProvider, размещенному в пространстве имен Cryptography:

На рис. 1 показан простой пример применения CSP на платформе Windows Azure. Три открытых члена предоставляются любому приложению в Windows Azure. Первый принимает двоичный ключ и вектор инициализации (initialization vector, IV), а также двоичный буфер незашифрованных данных и возвращает их зашифрованных эквивалент. Второй член делает обратное, расшифровывая данные, а третий — возвращает вычисленное хеш-значение для этих данных. Заметьте, что здесь я использую Rijndael CSP для управляемого доступа к провайдеру. Кроме того, я храню данные и ключи в двоичных буферах и перезаписываю их, как только заканчиваю работать с ними. К этому моменту я еще вернусь при обсуждении неизменяемости (immutability).

Рис. 1 Простое шифрование

Это простейший пример шифрования данных и возврата результатов шифрования в виде байтового массива и вовсе не тот код, который следует использовать в защищенной среде; это лишь пример.

Пример на рис. 2 имеет почти идентичную структуру, что и код на рис. 1. В данном случае я расшифровываю данные на основе того же ключа и IV — только в качестве параметра используется расшифрованный байтовый буфер. Единственное значимое различие здесь — при создании потока шифруемых данных я указываю, что создаю компонент симметричного дешифрования, а не шифрования, как ранее.

Рис. 2 Простое дешифрование

Хранилище ключей

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

Когда дело доходит до хранения ключей в облачной среде, возникает важный вопрос: а где же держать ключи? Некоторые выражают озабоченность тем, что, храня ключи в облаке, подвергаешь свою защиту рискам, исходящим из самого облака. То есть некто может получить физический доступ к вашим данным, которые по умолчанию хранятся на диске в незашифрованном виде (как в случае Windows Azure). Учитывая, что SQL Azure пока вообще не поддерживает шифрование, это соображение следует принимать во внимание при планировании и проектировании своего решения. Как и в любой реализации системы безопасности, все риски нужно проанализировать, взвесить и максимально ослабить.

Но это вовсе не означает, что платформы облака в целом и Windows Azure в частности принципиально небезопасны. Какие еще варианты могут быть вам доступны?

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

Собственная библиотека ключей в Windows Azure Storage — хороший способ сохранить некую информацию в секрете, поскольку вы можете полагаться на эти данные как на надежные в многопользовательской среде и защищать их с помощью своих ключей хранилища. Это отличается от использования ключей хранилища в качестве шифровальных. Вместо этого вы могли бы применять ключи сервиса хранилища для доступа к библиотеке ключей, как делали бы это в случае любого другого хранимого файла. Реализовать такой вариант довольно легко. Например, вам нужна собственная библиотека ключей как простой текстовый файл для хранения некой секретной информации. Лучше всего было бы сохранить ее как данные через API сервиса больших двоичных объектов (blob service) в противоположность сервису хранилища очереди или таблиц. Область больших двоичных объектов сервиса хранилища — лучшее место для такой информации, как двоичные аудиоданные, изображения или даже текстовые файлы. Очередь оптимизирована под безопасное хранение малых объектов данных, которые не хранят в течение длительного времени. Система хранилища таблиц отлично подходит для структурированных данных и информации, которые нужно хранить и использовать в определенных местах идентично реляционным данным в базе данных.

Вы начинаете с сохранения ключа в контейнере ключей CSP. Это отличный вариант для хранения открытого ключа — его трудно получить без физического доступа к серверу. В случае Windows Azure, где местонахождение приложений и данных абстрагируется, хранение открытого ключа таким способом еще сильнее затруднит его поиск и получение. Создать контейнер хранилища ключа совсем не сложно; ниже приведен пример с использованием провайдера RSA, создающего наш ключ. Если контейнер ключа уже существует, его ключ автоматически загружается в провайдер:

Также есть другие варианты, которые можно рассмотреть в зависимости от потребностей. Например, можно применять специфические флаги для защиты ключа пользователя, который создал контейнер. Это делается с помощью члена Flags:

Теперь создаем запрос к API больших двоичных объектов с применением вашего ключа хранилища Windows Azure. Сам запрос требует наличия строки подписи и правильно сформированного заголовка запроса. Формат этого заголовка таков:

В этом случае я хочу добиться максимальной безопасности своих сохраняемых секретных данных, поэтому буду использовать метод авторизации SharedKey. Часть заголовка, отведенная под подпись, — это код аутентификации на основе хеша, генерируемый алгоритмом SHA256, и ваш ключ хранилища, применяемый к данным в подписи. Этот хеш затем кодируется в строку по основанию base64. Вот пример подписи:

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

Угрозы безопасности ключа

Есть еще один элемент, о котором стоит рассказать хотя бы вкратце, — защита ключа. Это не совсем то же самое, что и способ хранения ключей. Сами ключи в основном представляют собой строки символов с очень высоким уровнем энтропии, что подразумевает крайне высокую степень рандомизации. Фактически это может привести к тому, что потенциально возможная атака на вашу систему будет направлена на поиск ключей, местонахождение которых выдадут участки с крайне высокой энтропией. Например, если сделать дамп памяти или области данных на жестком диске, то участки с крайне высокой энтропией — именно те места, где стоит начать анализ для обнаружения ключей.

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

Наконец, позаботьтесь о создании схем потоков ваших данных — как защищенных, так и незащищенных. Внимательно изучите, куда и как передаются ваши данные, где вы храните секреты и где ваши данные пересекают границы, например общедоступных и частных сетей. Тогда вы получите хорошее представление о том, где ваши данные раскрываются, и это позволит вам целенаправленно устранить соответствующие риски.

Меня также часто спрашивают о том, поддерживается ли SSL на платформе Windows Azure. Если кратко, то — да! Windows Azure вряд ли имела бы шансы претендовать на роль облачной платформы веб-сервисов и приложений без поддержки SSL.

Шифрование в SQL Azure

В SQL Server 2008 было введено новое средство: прозрачное шифрование данных (transparent data encryption, TDE). Впервые в SQL Server стало возможным полностью шифровать данные с минимальными усилиями с вашей стороны по сравнению с тем, что требовалось для ограниченного шифрования, которое поддерживалось в SQL Server 2005. Однако начальная версия хранилища SQL Azure пока не поддерживает шифрование на уровне базы данных, хотя такая поддержка скорее всего будет включена в следующую версию. Следует заметить, что в настоящее время SQL Azure доступен только через TCP-соединения и только через порт 1433.

Хотя это средство пока не интегрировано в Windows Azure, есть несколько других функций защиты SQL Azure, о которых должны знать разработчики или проектировщики. Во-первых, SQL Azure поддерживает поток табличных данных (tabular data stream, TDS). То есть по большей части вы можете подключаться к базе данных и взаимодействовать с ней точно так же, как вы всегда делали это. Об использовании преимуществ шифрования ADO.NET и сертификатов доверенных серверов определенно стоит подумать, особенно если вы обращаетесь к базе данных SQL Azure извне облака.

Свойства соединения Encrypt = True и TrustServerCertificate = False в должной комбинации обеспечат защиту передаваемых данных и помогут предотвратить атаки с посредниками (man-in-the-middle attacks). Кроме того, это обязательно для подключения к SQL Azure — вы не сможете соединиться с SQL Azure, пока не включите шифрование уровня соединения.

Второе средство защиты SQL Azure, с которым вы должны ознакомиться, — брандмауэр SQL Azure. Он хорошо известен тем, кто пользовался локальными брандмауэрами или даже набором средств защиты SQL Server. Он разрешает или запрещает соединения из различных источников вплоть до конкретных IP-адресов или диапазонов. Брандмауэром SQL Azure можно управлять через портал SQL Azure или напрямую в главной базе данных с помощью хранимых процедур, таких как sp_set_firewall_rule и sp_delete_firewall_rule.

Как и в любой реализации SQL Server, управление пользовательскими учетными записями — еще один аспект, который нужно жестко контролировать. Брандмауэр в SQL Azure — действительно отличное средство, но полагаться только на него не стоит. Вы должны применять стойкие пароли в учетных записях и настраивать для них строго определенные права доступа, а также продумать свою модель защиты данных.

Благодаря этим новым средствам SQL Azure является высокозащищенной управляемой платформой для приложений в облаке. Если вы впервые пробуете работать с этим сервисом, не забудьте, что до попыток подключения вы должны сначала настроить брандмауэр SQL Azure. В первый раз это делается только через веб-портал SQL Azure, но впоследствии им можно управлять с помощью главной базы данных, как уже было сказано.

Неизменяемость и ресурсы в памяти

Неизме...? Неизменяемость в объектно-ориентированном программировании означает лишь то, что состояние объекта нельзя модифицировать после его создания. Конкретный пример в Microsoft .NET Framework — класс string. Когда значение строки изменяется в коде, исходная строка в памяти просто удаляется и вместо нее создается новый объект string, в который помещается новое значение.

Почему это так важно с точки зрения защиты? Ну, строка может оставаться в памяти, пока сервер работает без перезагрузки. У вас нет никакого способа точно выяснить, насколько долго будет храниться строка в памяти. А это очень важно учитывать, принимая решение насчет того, как хранить в коде такую информацию, как шифровальные ключи или копии зашифрованных/дешифрованных данных. Оставляя следы этих данных в памяти, вы оставляете умному взломщику информацию, раскрывающую ваши секреты.

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

Поскольку Windows Azure — облачная среда, меня спрашивают, неужели это до сих пор остается проблемой, и это хороший вопрос. Верно, в системе Windows Azure индивидуальные приложения изолированы друг от друга. В целом, это уменьшает остроту проблемы раскрытия данных в памяти. К тому же, очень трудно сопоставить в облаке приложения и выделенные им пространства памяти. Однако я все равно рекомендую проявлять осторожность и очищать свои данные. Этот блок кода может не всегда выполняться в облаке, а в будущем могут обнаружиться другие уязвимости. Так что пусть такой подход станет вашей второй натурой.

На рис. 3 я модифицировал предыдущий пример, в котором генерировались случайные целые числа. Здесь я добавил кое-какую обработку ошибок, сделав так, чтобы независимо ни от чего у меня всегда выполнялся блок finally. Внутри этого блока я выполняю очень простой цикл, перебирая значения в байтовом массиве и заменяя их нулями. Это приводит к перезаписи данных в памяти, потому что байтовые массивы изменяемы. После этого я уверен, что номер, владельцем которого является процесс выполнения этого члена, больше не в памяти. Подобное можно проделывать над любыми байтовыми массивами, используемыми в качестве буферов для ключей, векторов инициализации и зашифрованных/дешифрованных данных.

Рис. 3 Очистка данных из памяти

Очереди сообщений

Очереди Windows Azure предоставляют функциональность, аналогичную поддерживаемой сервисами Microsoft Message Queuing (MSMQ), которые широко используются в корпоративных Windows-приложениях. Сервис очереди сообщений в Windows Azure хранит текстовые сообщения размером не более 8 Кб в стиле FIFO ("первым вошел — первым вышел"). Это позволяет сервисам и приложениям, выполняемым на разных серверах (или в облаке, как в данном случае), взаимодействовать, безопасно и асинхронно посылая друг другу сообщения.

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

Многие из средств, поддерживаемых MSMQ, пока не поддерживаются API обмена сообщениями в Windows Azure. Однако и в этом случае проблемы решаемы. Как и в случае сервиса больших двоичных объектов данных, сервисы обмена сообщениями используют все те же REST-интерфейсы get и put. Создание и чтение сообщений может осуществляться либо в коде, либо с помощью URI и веб-запросов, которые зашифровываются средствами SSL для передачи по незащищенным сетям. То есть на время передачи запросы зашифровываются.

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

Заключение

В современных условиях перехода к архитектуре и решениям, ориентированным на сервисы, немногие могут игнорировать в своем бизнесе приложения в облаке. Изоляция данных и сервисов в таких многопользовательских средах, как Windows Azure, — одна из основных задач для любого, кто использует закрытую информацию.

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

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

   
public static int GenerateRandomNumber() {
  byte[] GeneratedBytes = null;

  try {
    GeneratedBytes = new byte[4];
    RNGCryptoServiceProvider CSP =
      new RNGCryptoServiceProvider();
    CSP.GetBytes(GeneratedBytes);
    return BitConverter.ToInt32(GeneratedBytes, 0);
  }
  finally {
    for (int x = 0; x < GeneratedBytes.Length; x++) {
      GeneratedBytes[x] = 0;
    }
  }
}

   
"PUT\n\ntext/plain; charset=UTF-8\n\nx-ms-Date:Fri, 12 Sep 2009 22:33:41 GMT\nx-ms-meta-m1:v1\nx-ms-meta-m2:v2\n/exampleaccount/storageclientcontainer/keys.txt"

   
Authorization="[SharedKey|SharedKeyLite] <AccountName>:<Signature>"

   
CspParam.Flags = CspProviderFlags.UseUserProtectedKey;

   
CspParameters CspParam = new CspParameters();
CspParam.KeyContainerName = "SampleContainerName";
RSACryptoServiceProvider RSAProvider = new
  RSACryptoServiceProvider(CspParam);

   
public static byte[] SampleDecrypt(byte[] dataBuffer,
  byte[] Key, byte[] IV) {

  MemoryStream InMemory = new MemoryStream();
  Rijndael SymetricAlgorithm = Rijndael.Create();
  SymetricAlgorithm.Key = Key;
  SymetricAlgorithm.IV = IV;
  CryptoStream EncryptionStream = new CryptoStream(InMemory,
    SymetricAlgorithm.CreateDecryptor(), CryptoStreamMode.Write);
  EncryptionStream.Write(dataBuffer, 0, dataBuffer.Length);
  EncryptionStream.Close();
  byte[] ReturnBuffer = InMemory.ToArray();
  return ReturnBuffer;
}

   
public static byte[] SampleEncrypt(byte[] dataBuffer,
  byte[] Key, byte[] IV) {

  MemoryStream InMemory = new MemoryStream();
  Rijndael SymetricAlgorithm = Rijndael.Create();
  SymetricAlgorithm.Key = Key;
  SymetricAlgorithm.IV = IV;
  CryptoStream EncryptionStream = new CryptoStream(InMemory,
    SymetricAlgorithm.CreateEncryptor(), CryptoStreamMode.Write);
  EncryptionStream.Write(dataBuffer, 0, dataBuffer.Length);
  EncryptionStream.Close();
  byte[] ReturnBuffer = InMemory.ToArray();
  return ReturnBuffer;
}

   
public static int GenerateRandomNumber() {
  byte[] GeneratedBytes = new byte[4];
  RNGCryptoServiceProvider CSP = new RNGCryptoServiceProvider();
  CSP.GetBytes(GeneratedBytes);
  return BitConverter.ToInt32(GeneratedBytes, 0);
}

Ссылка: http://www.oszone.net/14366/Windows-Azure