id: Гость   вход   регистрация
текущее время 17:12 28/03/2024
Владелец: SATtva (создано 08/03/2007 19:01), редакция от 03/07/2007 21:34 (автор: SATtva) Печать
Категории: криптография, софт, gnupg, аутентификация, эцп, разное, расширения, сообщество
создать
просмотр
редакции
ссылки

Общая спецификация интеграции GnuPG


Оглавление документа:

Задачи


Задачами, решаемыми интеграцией GnuPG, являются:


  1. Валидация загружаемого пользователем (в свой профиль) открытого ключа на корректность с последующим внесением отпечатка в базу данных.
  2. Авторизация (по протоколу запрос-ответ) ряда чувствительных операций: смены пользовательского пароля доступа и почтового адреса.
  3. Защита приватной связи между пользователями сайта.
  4. Защита отправляемого пользователю восстановленного пароля.
  5. Функциональное обеспечение публичного доступа к серверам ключей.
  6. Функциональное обеспечение публичного декодировщика OpenPGP-пакетов.
  7. Проверка цифровых подписей для пользовательских комментариев.

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


Тем не менее, список задач остается открыт для дополнений.

Функции


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

Загрузка ключа


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


Все этапы загрузки/валидации ключа выполняются в контексте специальной временной связки. Валидация ключа состоит из двух этапов: 1) имеет ли пользователь доступ к закрытой части ключа (это лишь защита от случайной загрузки пользователем чужого ключа, который он в дальнейшем не сможет заменить) и 2) пригоден ли ключ для операций шифрования. Первый этап производится в простом протоколе запрос/ответ и для верификации использует функцию VerifyMsg(). На втором этапе производится вызов CheckPK(). Если ключ удовлетворяет всем условиям, то он перемещается в основную связку сервера.

UploadPK(keyASCII)

Импортирует загруженный ключ на временную связку. Единственный аргумент, keyASCII, представляет собой загруженный пользователем блок открытого ключа, передаваемый в GnuPG через STDIN с параметром --import. Сразу после исполнения вызывается CheckPK(keyID), которая анализирует ключ с целью определения его пригодности для зашифрования.

RecievePK(keyID[, ksURL])

Импортирует ключ с сервера ключей на временную связку. Передает GnuPG указанный пользователем (в профиле) ID ключа в параметре командной строки --recv-keys. Опциональный аргумент ksURL позволяет пользователю задать URL сервера ключей, вместо дефолтного.


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


Хотя вся указанная функциональность реализована, тестирование показало, что большинство серверов ключей не способны корректно обходить коллизии в ID: одни обязывают передавать ID в восьмизначном формате (который и образует коллизию), а другие, хоть и не устанавливают такого требования, все равно возвращают пакеты открытых ключей и главные UserID по их восьмизначным ID, независимо от реальной длины ввода.

AcceptPK(keyID)

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

Шифрование данных


Универсальное исполнение обеспечивается одной функцией, что решает как задачу защиты приватных сообщений, так и кода восстановления пароля (при возникновении потребности в шифровании двоичных данных, понадобится дополнительная функция, передающая GnuPG аргумент --no-textmode).

EncryptMsg(plaintext, keyID)

Шифрует произвольное текстовое сообщение. Вызывает GnuPG с параметрами -r <keyID> -e, подает открытый текст через STDIN и возвращает шифртекст, полученный от программы. Следует обратить внимание, что перед вызовом данной функции нужно произвести вызов CheckPK() и проверить, пригоден ли открытый ключ получателя для зашифрования.

Верификация данных

VerifyMsg(data)

Принимает произвольные данные, с которых снимает цифровую подпись (вызов GnuPG: gpg -v; команда --verify не используется, поскольку не возвращает сам заверенный текст). Результаты операции определяются по выданным статус-кодам. Возвращает 1) состояние подписи, 2) отпечаток первичного ключа, 3) метку времени ЭЦП, 4) идентификатор ЭЦП, а также 5) тело подписанного сообщения.

Извлечение ключа


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

GetPK(keyID)

Извлекает блок указанного открытого ключа из рабочей связки сервера и подает его на выход (параметры командной строки: --armor --export <keyID>).

Удаление/замена ключа


Для предотвращения замены ключа лицом, получившим несанкционированный доступ к учетной записи пользователя, его удаление из профиля должно быть подтверждено соответствующим закрытым ключом с помощью протокола запрос/ответ (используя VerifyMsg()). Аналогичная процедура предусмотрена для изменения пользовательского пароля и смены почтового адреса, что не позволит захватить аккаунт, не обладая закрытым ключом пользователя.

Функции обслуживания


Набор функций, используемых для обеспечения ряда вышеназванных задач.

CreateToken(procedure)

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

C = T, P, H(S, U, T, P)

где T — метка времени, P — обозначение операции (передается через аргумент функции), S — секретное значение системы, U — идентификатор PHP-сессии пользователя. (В качестве H применяется хэш-функция SHA-1.) Получаемый идентификатор выглядит примерно так:

1179831196|deletepk
251fb1d6718f7042948d77c583e75d5b3b39e52a

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

ValidateToken(token, procedure, expiry)

После проверки цифровой подписи данная функция проверяет аутентичность заверенного идентификатора. Прежде всего это делается для предотвращения повторной передачи устаревших идентификаторов (аргумент expiry задает время жизни идентификатора) или идентификаторов, использовавшихся в других операциях (определяется аргументом procedure).

CheckPK(keyID)

Парсит сертификат ключа (используются параметры --with-colons --list-public-keys <keyID>) и проверяет следующие условия: 1) ключ содержит по крайней мере один шифровальный подключ и 2) базовый ключ и шифровальный подключ в данный момент действительны. Оба условия не имеют критического значения при загрузке ключа (пользователю выводится только предупреждение), но при восстановлении пароля или отправке зашифрованного приватного сообщения должно привести к неудачному завершению операции.

DeletePK(keyID)

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

Реализация


Ограничивающим фактором в реализации схемы выступает запрет стандартной PHP-функции exec() (что является нормой для любого виртуального хостинга). Таким образом, взаимодействие с GnuPG может осуществляться только через интерфейс CGI. Использовать с этой целью CGI-сборку PHP нерационально, поэтому итоговая конструкция представляет собой:


.                   openSpace Engine
    пользовательский уровень, графический интерфейс
                           /\
                           ||
                           \/
               openSpace-GPG engine class
   функциональная прокладка, реализующая необходимый
    набор функций ввода/вывода для взаимодействия с
         GnuPG и проверки результатов операций
                           /\
                           ||
                           \/
                openSpace-GPG CGI wrapper
    простейшая Perl-оболочка, "тупо" вызывающая GnuPG
    с переданными параметрами командной строки и воз-
       вращающая вывод программы верхнему уровню
                           /\
                           ||
                           \/
                   GnuPG executable
     исполняемый файл программы, лежащий за пределами
           публичной www-директории сервера

Временный контекст


Все операции, требующие сохранения временных данных на диске сервера (по существу, это любые операции, поскольку статус-коды и сообщения об ошибках перенаправляются на диск всегда), выполняются в контексте временного каталога, создаваемого конструктором объекта по номеру PHP-сессии пользователя, и удаляемого деструктором объекта по окончании исполнения скрипта. Таким образом, весь парсинг и анализ входных и выходных данных должен производиться в текущем цикле исполнения движка, либо необходимо идти на особые ухищрения, как то сохранение необходимых данных в сессии пользователя (что не рекомендуется).

Класс openSpace-GPG


Основной функциональный класс. Вызов методов напрямую из класса без создания объекта невозможен без отработки конструктора и определения свойств.


Файл конфигурации gpg.conf


Поскольку GnuPG должен работать в полностью автономном режиме, видится необходимым следующий конфигурационный файл. Корректирующие параметры могут быть переданы как аргументы командной строки (например, --no-default-keyring).


CGI-обертка openSpace-GPG


Идея использования пайпа для передачи данных GnuPG из стандартного ввода принадлежит ПэГусеву, за что ему особая благодарность. В остальном обертка не содержит ничего существенного: HTTP-ввод разбирается на пары переменная=значение, вывод GPG открывается как файловый дескриптор и подается на стандартный вывод сервера для последующего перехвата вызывающей программой (конкретно, методом Call() класса; см. выше).


Для защиты от выполнения произвольных команд GnuPG путем прямого вызова скрипта вызывающее приложение должно передать секретное значение (HTTP-переменная pv), равное значению переменной $protection, заданной в скрипте.



 
На страницу: 1, 2, 3, 4, 5, 6, 7, 8 След.
Комментарии [скрыть комментарии/форму]
— SATtva (04/04/2007 20:50, исправлен 04/04/2007 21:07)   профиль/связь   <#>
комментариев: 11558   документов: 1036   редакций: 4118
spinore, в этом предложении сразу вижу одну большую проблему. Движок WackoWiki, из которого растёт openSpace, изначально был не самой шустрой платформой. openSpace со всеми его нововведениями (даже несмотря на ряд оптимизаций в сравнении с оригиналом) жрёт вообще уйму ресурсов (один только скрипт без учёта MySQL на обычной странице отрабатывается 0.2-0.5 секунды).

А тут ещё при каждой отрисовке комментариев нужно будет создать новый объект из приведённого выше класса, скормить каждое сообщение GnuPG и определить по статус-кодам, имеем ли мы дело с цифровой подписью, а затем вернуть "чистый" без хидеров текст. (Можно, конечно, разменять время на память, и при сохранении сообщения вносить в базу две его копии: одну с цифровой подписью, а другую — "чистую", но учитывая, что мы уже храним две копии каждой страницы (комментарии — это тоже страницы) — одну с исходной вики-разметкой, а другую — с уже скомпилированным html, — это не есть разумный шаг с точки зрения объёма базы данных. В принципе, можно просто добавить в базу одно поле с флагом "подписано/неподписано", а для исходного текста и "чистого" использовать уже существующие поля. Но более меня пока смущает вопрос производительности скрипта.)

Короче, пока эта затея не вызывает у меня большого воодушевления. Прежде всего с позиции соотношения затрат (всех: от разработки до последующей эксплуатации) и получаемых выгод. Но может быть сумеете меня переубедить, как Гость. :-) Кстати, в число задач, решаемых интеграцией GnuPG, добавлены две новых (см. начало документа).

Гость, второй вариант мне, в общем-то, по душе. Только обрезать отпечаток нужно от начала, поскольку именно последние байты и соответствуют keyID. Ну а вообще Ваше предложение принято, спасибо. :-)

Добавлено:

spinore, а добавьте-ка Вы на главную страницу опрос по поводу предлагаемой Вами функции. Мне тоже любопытно, сколько людей видят в ней потребность.

Добавлено:

Кстати, тут пара ребят из Франции написали любопытное расширение а-ля Enigmail для Firefox. Называется FireGPG, позволяет легко шифровать и подписывать текст в веб-формах.
— spinore (04/04/2007 23:22)   профиль/связь   <#>
комментариев: 1515   документов: 44   редакций: 5786
1) Фингерпринт, имхо, должен быть виден чётко и полностью
2) Опрос добавил
3) В веб не разбираюсь, потому подсказать ничего не могу (но внутри себя удивился – неужели на сервере там так мало места для нашей базы?)
4) FireGPG: я не доверял бы доступ к приватному ключу сомнительным проектам, хотя, может быть, это излишняя перестраховка.
— spinore (04/04/2007 23:28)   профиль/связь   <#>
комментариев: 1515   документов: 44   редакций: 5786
Мне кажется что форум пока не тормозит, чтобы так сильно переживать насчёт производительности. И, в конце концов, каковы затраты на проверку подписи? У нас же не случай одновременного коннекта тысяч пользователей....
— ПэГусев (05/04/2007 06:57, исправлен 05/04/2007 06:58)   профиль/связь   <#>
комментариев: 112   документов: 8   редакций: 15
обрезать отпечаток нужно от начала

Мне кажется, три строки – это слишком много для заголовка поста. Предлагаю оставить видимым только KeyID и разместить его в первой строке мелким шрифтом сразу же за ником. А при наведении курсора показывать весь отпечаток. Примерно так:

—- spinore (KeyID: BCBB B732) (04/04/2007 23:28) профиль <#>
комментариев: 374 документов: 4 редакций: 3


1) Фингерпринт, имхо, должен быть виден чётко и полностью

spinore, основание?
— ПэГусев (05/04/2007 07:12, исправлен 05/04/2007 07:17)   профиль/связь   <#>
комментариев: 112   документов: 8   редакций: 15
4) FireGPG: я не доверял бы доступ к приватному ключу сомнительным проектам, хотя, может быть, это излишняя перестраховка.

Ну, код-то открыт.
Хотя я бы не доверил приватный ключ или пароль от него даже самому браузеру,
поскольку он по определению имеет права на отсылку данных во внешний мир.
— SATtva (05/04/2007 19:47)   профиль/связь   <#>
комментариев: 11558   документов: 1036   редакций: 4118
В веб не разбираюсь, потому подсказать ничего не могу (но внутри себя удивился – неужели на сервере там так мало места для нашей базы?)

Одни только страницы (документы, темы форума, комментарии) — под 50Мб. Резервные копии делать мотошно.
— SATtva (05/04/2007 22:09)   профиль/связь   <#>
комментариев: 11558   документов: 1036   редакций: 4118
Я опубликовал немного переработанный вариант страницы персональных настроек, где теперь можно указать предпочтения по защите приватных сообщений (сам интерфейс которых дорабатывается) и восстановленного пароля, и профилей, откуда теперь можно скачивать размещённый на сайте открытый ключ. Если будут замечания — милости прошу.

Отпечаток ключа в заголовках комментариев сейчас сами видите какой. Впихнуть всё в две строчки всё равно трудно (для модераторов это может создать трудности при просмотре). Пока не придумано ничего лучше, просто сократил длину вывода до 16-значного keyID — так он реально нагляднее и запоминается легче: "как телефон", по аналогии unknown'а.
— spinore (06/04/2007 01:12, исправлен 06/04/2007 01:43)   профиль/связь   <#>
комментариев: 1515   документов: 44   редакций: 5786


Уменьшение фингерпринта уменьшает безопасность, потому не по душе. Хотя если ИД определяет ключ однозначно можно использовать и его (если коллизия не реализуема)



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



А сколько у нас места на сервере всего, сколько уже занято, и сколько стоит один мегабайт?
— SATtva (06/04/2007 10:28)   профиль/связь   <#>
комментариев: 11558   документов: 1036   редакций: 4118
Уменьшение фингерпринта уменьшает безопасность, потому не по душе. Хотя если ИД определяет ключ однозначно можно использовать и его (если коллизия не реализуема)

С 8-байтовым ID коллизия весьма вероятна (кому-то даже удалось сформировать ключ с ID ключа Циммермана). Поэтому выводим 16 байт.

А сколько у нас места на сервере всего

Да места-то много, 700Мб. К тому же, как я писал выше, Вашу идею с точки зрения дискового пространства можно оптимизировать (можно обойтись двумя копиями страницы, которые уже есть, а проверять подпись только у тех страниц/комментариев, которые помечены флагом).
— Гость (06/04/2007 22:20)   <#>
Уменьшение фингерпринта уменьшает безопасность

А может проверять наличие коллизий (по базе отпечатков ключей зарегистрированных пользователей) при добавлении нового ключа, отмечать их, и выводить длинные отпечатки только в случае реального наличия коллизии?

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

А теперь представьте, что после того как все уверятся, что сайт не обманывает, SATtve сделают предложение, "от которого он не сможет отказаться"? Уж лучше пусть важные сообщения проверяются каждым самостоятельно.
Имело бы смысл добавить специальное форматирование для размещения подписанного сообщения. Можно, конечно, использовать комментарий (comment), но тогда за подписанным сообщением придётся лезть в исходный текст страницы HTML, что, впрочем, при современных браузерах не проблема.

PS
Не поручайте больше spinore добавлять опросы, ну не его это профиль. :)
— SATtva (06/04/2007 23:50, исправлен 07/04/2007 00:33)   профиль/связь   <#>
комментариев: 11558   документов: 1036   редакций: 4118
А может проверять наличие коллизий (по базе отпечатков ключей зарегистрированных пользователей) при добавлении нового ключа, отмечать их, и выводить длинные отпечатки только в случае реального наличия коллизии?

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

Имело бы смысл добавить специальное форматирование для размещения подписанного сообщения.

Для этой цели можно в необходимых случаях использовать:
%%
-----BEGIN PGP SIGNED MESSAGE-----
и т.д...
%%
— spinore (07/04/2007 03:50, исправлен 07/04/2007 03:51)   профиль/связь   <#>
комментариев: 1515   документов: 44   редакций: 5786


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



Шо опять не так, хлопцi?



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




В том-то и смысл, чтоб не глазеть на заголовки и на хэши без надобности и выводить их только по требованию.
— SATtva (07/04/2007 13:32)   профиль/связь   <#>
комментариев: 11558   документов: 1036   редакций: 4118
С учётом такой выборки, шанс получить коллизию из 16-байтовых шестнадцатеричных строк меньше, чем выиграть джек-пот в лотерее.

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

Предлагаю участникам, более искушённым в математике, чем я (например, Вам, spinore :-), посчитать вероятность коллизии для 64-битовых строк (это как раз 16 байт хэш-значения) при случайной выборке из 10 тычяч пользователей (это с заделом на будущее). Там, по-моему, какие-то очень большие цифры выходят.
— serzh (07/04/2007 16:19)   профиль/связь   <#>
комментариев: 232   документов: 17   редакций: 99
Из всех используемых в настоящее время ключей коализий для 8-ми байтового ID меньше 100, поэтому с 16-ти байтовым ID можно быть спокойным ёще очень долго (поиск коализий с учётом слабостей хэш-функций не рассматриваем).
— SATtva (07/04/2007 16:44)   профиль/связь   <#>
комментариев: 11558   документов: 1036   редакций: 4118
Около двухсот, если быть точным. А по данным на начало 2002-го из более чем полутора миллионов ключей было обнаружено даже пять пар с дубликатными 64-битовыми (16-значными) keyID. Подробную статистику дубликатов (не уверен, насколько актуальную) можно найти здесь.
На страницу: 1, 2, 3, 4, 5, 6, 7, 8 След.
Ваша оценка документа [показать результаты]
-3-2-1 0+1+2+3