Pull to refresh

Повышение доверия к РОИ при сохранении секретности персональных данных

Information Security *
Sandbox
Этот пост — ответ на habrahabr.ru/post/244753

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

Предлагаемый протокол действий.

Для начала, РОИ генерирует 2048 битный RSA ключ-пару (SK, PK) для использования в качестве электронной цифровой подписи (ЭЦП), где SK-секретный ключ и PK-публичный ключ. Публичный ключ публикуется в открытом доступе, а секретный хранится и используется только на сервере РОИ. Таких ключей может быть один для всего РОИ или много разных для разных инициатив. Например, можно генерировать свой отдельный ключ для каждой инициативы. Или обновлять ключ для всего РОИ время от времени. Для идентификации ключа будем использовать понятие «версия ключа» (или индекс, номер ключа). Дополнительно, но совсем не обязательно для первой версии системы, РОИ может публиковать сертификат ключа.

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

1. При голосовании пользователем, РОИ формирует следующий вектор V, длинною 49 байт:
Версия (номер) ключа: 4 байта
Номер инициативы: 4 байта
Время события (UTC время): 8 байт
Тип события: 1 байт (ЗА, ПРОТИВ, ОТЗЫВ)
Хеш проголосовавшего пользователя, вычисляемый как
H = SHA256(UserSecret; СНИЛС; Номер Инициативы): 32 байта.

UserSecret это секрет, источник которого — сам пользователь. Например, это может быть пароль на голос, который пользователь вводит на сайте РОИ при голосовании. Если технически РОИ позволяет, то это может быть и пароль при входе на РОИ или его хеш, в таком случае РОИ может автоматически подставлять его в поле. В любом случае, это должно быть то, что исходит от пользователя, и что известно ему одному и никому другому. О причинах нововведения — читайте в спойлер-комментарии.
UPD: Изменения к первой редакции, мотивация
Было: H = SHA256(SK; СНИЛС; Номер Инициативы): 32 байта.
В результате обсуждений вяснилось, что в системе дыра. Представим себе следующий сценарий: РОИ кэширует результаты и выдает их, скажем, раз в 5 минут. Допустим какой то пользователь проголосовал, и ему генерируется и отсылается правильный код (Vx, Sx). Допустим кто то другой тоже голосует в эти 5 минут, и РОИ может отослать ему не новый код, а код предыдущего пользователя (Vx, Sx). Позже, при проверке своих кодов, оба пользователя увидят что их код есть в выписке, но счетчик на РОИ увеличится только на 1, и это проверить невозможно. То есть мы получим сценарий, при котором на РОИ может пропасть голос. Слабое звено тут — вектор Hx. Поэтому необходимо, чтобы сам пользователь мог проверить правильность исходных данных этого вектора, но никто другой не мог бы. Это немного усложняет систему.

Тут надо отметить, что если пользователь производит несколько действий, например, ЗА-ОТЗЫВ-ПРОТИВ, то UserSecret должен оставаться неизменным для всех этих действий, чтобы в логах Hx был один и тот же для этих операций для одного пользователя и выбранной инициативы. В случае, когда отзывать голос нельзя (как это сейчас на РОИ), то этот вопрос становится не актуальным и проблемы тут нет.

Следствие: Теперь пользователю необходимо не только проверить, что его код (Vx, Sx) находится в списке выгружаемых логов, но и проверить, что уникальный вектор Hx из Vx был сформирован верно.


2. Далее, РОИ использует соответствущий секретный RSA ключ SK для того, чтобы получить вторую часть кода — цифровую подпись (ЭЦП):
S = RSA_Sign(SK; V) – результат будет 256 байт.

3. Пара (V; S) высылается электронной почтой проголосовавшему пользователю, а также помещается в публичный доступ (например, в текстовом PEM формате).

Плюсы:

• Любой человек по открытому списку пар {V;S} может подсчитать общее число голосов для выбранной инициативы, предварительно верифицировав каждое значение Vx, используя публичный ключ РОИ следующим образом: RSA_Verify(PK; Sx; Vx) возвращает значение «успех» или «не успех». По сути, функция дешифрует подпись Sx с помощью открытого ключа PK и сверяет результат с Vx, если равно то «успех».

• Любой по списку {V;S} может найти свой код голосования, так как он должен быть послан по электронной почте пользователю сразу после голосования. Если код не найден в общем списке, пользователь может предъявить свою пару (Vx, Sx) как доказательство неучтенного голоса. Кроме того, пользователь должен проверить что его собственный вектор Hx из Vx был сформирован верно, исключая возможность сценария, где РОИ отсылает одну и ту же пару (Vx, Sx) двум пользователям, а учитывает только один голос.

• Третьи лица не смогут говорить об неучтенном голосе Vx без предоставления соответствующей пары-подписи Sx, так как для этого необходимо знать секретный ключ РОИ. Таким образом, РОИ защищено от необоснованных претензий такого рода.

• Поле H добавлено в строку V для того, чтобы однозначно идентифицировать действия одного и того же пользователя в рамках выбранной инициативы. Например, последовательность ЗА-ОТМЕНА-ПРОТИВ должна быть привязана к конкретному пользователю, чтобы можно было отследить эту последовательность в списке событий {V;S}. При этом сам СНИЛС пользователя является недоступным, так как в хеш, который генерируется на сервере РОИ, включен секретный ключ РОИ. По хешу невозможно узнать ни секретный ключ, ни СНИЛС человека. И даже если СНИЛС известен, то невозможно узнать секретный ключ РОИ по хешу. Также, невозможно проверить каким образом голосовал тот или иной человек, зная его СНИЛС, так как связь между СНИЛС и H не является публичной информацией, она известна только проголосовавшему, как и сам результат голосования – эта информация и сейчас высылается пользователю по электронной почте. Таким образом, данная конструкция не изменяет нынешний уровень безопасности личной информации (как голосовал человек), а также нет утечки информации по СНИЛС или секретному ключу РОИ.

• При предъявлении потерянного голоса (Vx, Sx) конкретным пользователем в публичный доступ, создается связующая пара между голосом и конкретным человеком, и тогда всем становится ясно как этот конкретный человек голосовал. Но и сейчас ситуация похожая – если я голосовал а мой голос не был учтен, то я, заявляя об этом, выдаю публично информацию о том как я проголосовал. Однако, плюс в том, что потерянный голос (Vx, Sx) и, таким образом, претензия к РОИ, может быть передан в публичное пространство анонимно, не выдавая при этом связь с конкретным пользователем.

Минусы:

• Невозможно отследить сценарий, в котором РОИ может добавлять голоса ЗА или ПРОТИВ для несуществующих СНИЛС. Но этот сценарий возможен и сейчас.

Техническая реализация:

Для реализации идеи, РОИ может установить OpenSSL (открытая и бесплатная криптографическая библиотека, широко используемая во многих системах а также при установления зашифрованных каналов в IP соединениях, в браузерах и многих других приложениях), и использовать ее из своих скриптов для всех вышеперечисленных операций: генерация RSA ключа (для ЭЦП), подписывание и хеширование SHA256. Генерация ключа – медленная операция, но редкая (один раз или при открытии новой инициативы). Подписывание секретным ключем и хеширование – быстрые операции. OpenSSL можно использовать как из коммандной строки или скрипта, так и из различных компилируемых языков программирования, таких как C/C++. Реализация не требует никаких инфраструктурных или других сложных шагов, и вполне может уложиться в несколько строк скрипта или кода.

UPD: Уточнения и дополнения по просьбам читателей.
У меня такое ощущение, что если все мнения сложить, то получится ноль. Но я попробую:

1. Уточнил по тексту, что RSA ключ генерируется на стороне РОИ для использования в качестве ЭЦП. Также RSA_Encrypt/RSA_Decrypt были заменены на RSA_Sign/RSA_Verify, соответственно.

2. Поступил вопрос, почему не ECDSA 256 бит (elliptic curve digital signing algorithm). Да, преимущества есть в размере цифровой подписи S. Будет не 256 байт, как в случае RSA, а 72. Но есть и минусы по скорости. Операция RSA_Verify работает в разы быстрее ECDSA_Sign и Verify. И если мы просто поменяем RSA_Sign/Verify на RSA_Encrypt/Decrypt и опубликуем SK вместо PK, то мы получим сервер который может быстро подписывать, в разы быстрее чем ECDSA.

3. Почему не ГОСТ? Про наши советские стандарты вообще слышал краем уха, знаю только что какие то из них скопированы с зарубежных идей и там что то добавлено немного чтобы выглядело по-другому. Пример — шифр «GOST», созданные в КГБ (ну, мне он известен под таким именем в научной среде) который копирует 3DES с небольшими вариациями. Те же вопросы и по ГОСТ хеш алгоритму — понятия не имею.

4. Давайте, чтобы предотвратить подобные вопросы китайцев (у них там тоже что то свое есть), как в пп.2-3, сразу просто заменим: ассиметричный алгоритм пусть будет X, а алгоритм хеширования Y, и выбирайте какой хотите. Просто соблюдайте уровень безопасности минимум 128 бит для используемых алгоритмов (а лучше 256), а в остальном это дело выбора и на суть сильно не влияет.

Спасибо!
Tags: РОИрои2014электронная демократияголосование
Hubs: Information Security
Total votes 47: ↑33 and ↓14 +19
Comments 88
Comments Comments 88