Недавно я участвовал в Ethereum-хакатоне, и сегодня хочу рассказать о проекте EtherAuth, с которым команда MixBytes заняла третье место. EtherAuth — это попытка сделать децентрализованную версию входа на сайт при помощи внешней учетной записи. Как кнопка войти через Facebook, только без Facebook.
Проблема и пути решения
Если вы хотите сделать на своем сайте закрытую область для пользователей, вам приходится выбирать: разработать свою систему идентификации, аутентификации и авторизации пользователей, или воспользоваться готовым решением. Готовое решение означает, что у вашего пользователя уже есть учетная запись в какой-то системе (Facebook, Google, Yahoo, Outlook, или даже просто email). И вы используете соответствующий механизм (чаще всего протокол OAuth 2.0), чтобы убедиться, что некто пытающийся залогиниться на ваш сайт с использованием внешнего идентификатора пользователя и есть этот пользователь.
Последний вариант проще в реализации, но возникает риск для пользователя: если что-то случится с его основным аккаунтом (например, Facebook заблокирует аккаунт без объяснения причин), он потеряет также доступ и к своей информации на вашем сайте.
Кроме того, если я как пользователь хочу войти на какой-то сайт, которому я пока не доверяю, я сталкиваюсь с необходимостью предоставить этому сайту доступ к своей персональной информации, например email или возраст. Если сайт поддерживает только вход внешней учетной записью, я должен буквально сделать выбор: отказаться от использования сайта или пожертвовать своей анонимностью.
Большинство пользователей заканчивает тем, что жертвует анонимностью со словами «да что страшного может случиться, мне нечего скрывать». К несчастью, большинство атак, ориентированных на неподготовленного пользователя и заканчивающихся денежными потерями, начинаются с похожих слов. «Что страшного может случиться, если я перешлю сотруднику банка код из смс?». «Что страшного может случиться если я перешлю сотруднику техподдержки заголовки запроса?». Ответ на этот вопрос чаще всего узнают когда уже ничего нельзя сделать.
Как тут может помочь Ethereum? Мы уже поняли, что основных проблем три:
- Пользователь не обязан доверять сайту, на который заходит, и хочет избежать утечки персональной информации.
- Сайт хочет использовать внешнюю систему аутентификации, чтобы избежать хранения пользовательских данных и связанных с этим затрат на обеспечение безопасности.
- Существующие внешние системы, предоставляющие сайтам возможность аутентификации пользователей, несут в себе опасность цензуры. Любой аккаунт может быть заблокирован в любой момент без объяснения причин и иногда без возможности восстановления.
Мы можем использовать сеть Ethereum вместо внешней системы и хранить в ней только необходимый набор данных. Надо позаботиться о том, чтобы не хранить в публичном доступе секретную информацию, но поскольку любой кошелек в сети Ethereum фактически является парой криптографически стойких ключей, в которой публичный ключ определяет адрес кошелька, а приватный ключ никогда не передается по сети и известен только владельцу, мы можем использовать асимметричное шифрование для аутентификации пользователей.
В простейшем случае можно использовать адрес Ethereum-кошелька как идентификатор пользователя. Но здесь возникает проблема: в случае утечки ключа пользователь теряет доступ к системе навсегда. Точнее, с момента, когда секретный ключ пользователя стал известен злоумышленнику или просто случайно попал в публичный доступ, мы не можем использовать такой ключ для аутентификации.
Реализация
В нашем решении я написал простой смарт-контракт EtherAuth для хранения идентификаторов пользователей и связанных с ними адресов кошельков. Идентификатор пользователя — это просто строка UTF-8 размером от 2 до 32 байт. Ее придумывает один раз сам пользователь и позже использует для входа на любой сайт, поддерживающий EtherAuth. Сегодня я бы добавил еще ограничение на возможные символы, входящие в строку, оставив возможность использования символов латинского алфавита и арабских цифр (подмножества 7-битной кодировки ASCII), чтобы ограничить возможность создания внешне похожих логинов.
При создании аккаунта в EtherAuth задается пара ключей: авторизационный ключ (authAddr) и ключ для восстановления доступа (recoveryKey). Название recoveryKey не совсем удачное, поскольку этот адрес используется для управления учетной записью, а не только для восстановления. При создании оба адреса равны адресу кошелька, от имени которого отправлена транзакция. Но пользователю, который заботится о своей безопасности, стоит создать отдельный управляющий ключ и хранить его в месте, недоступном по сети. Я бы даже хранил его на бумаге в сейфе в виде 12 мнемонических слов, позволяющих при необходимости воссоздать пару ключей.
Также разумно использовать отдельный адрес кошелька для аутентификации, отделяя его от адреса кошелька, в котором хранится весь ваш Эфир. Связь authKey с адресом кошелька, создавшего учетную запись, все еще можно проследить, анализируя последовательность транзакций смарт-контракта. Сейчас нельзя задать отдельный authKey и recoveryKey при создании аккаунта. Однако, если доработать смарт-контракт в этом направлении, адрес, создавший аккаунт, не обязательно будет связан с владельцем аккаунта, что позволит все желающим защитить свою анонимность.
Для взаимодействия пользователя со смарт-контрактом мы создали отдельную веб-страницу. На ней можно создать аккаунт, поменять его ключи или удалить. Для работы пользователю потребуется установить браузерный плагин MetaMask. Если вы уже активно используете сеть Ethereum, скорее всего вы этот плагин уже установили, то есть основная масса пользователей, желающих войти на сайт через Ethereum, не столкнется с дополнительной преградой на своем пути.
Общий процесс аутентификации пользователя с использованием EtherAuth выглядит так:
- Сайт (backend) обращается в смарт-контракт и получает Ethereum-адрес пользователя;
- Сайт (backend) генерирует и запоминает какое-то сообщение и просит пользователя подписать это сообщение при помощи адреса authKey;
- Пользователь, находясь на сайте (frontend), подписывает сообщение при помощи плагина MetaMask и отправляет его в backend;
- Сайт (backend) проверяет подпись, и если все в порядке, активирует сессию пользователя в соответствии со своей выбранной логикой.
В нашем решении для хакатона мы для простоты совместили backend- и frontend-части, получился один большой frontend. В реальной жизни важно, чтобы проверка аутентификации происходила в неподконтрольной пользователю среде, то есть не в браузере, а на сервере.
Из проблем, с которыми мы столкнулись, можно отметить проверку подписи во frontend-части. В браузере не оказалось поддержки эллиптических кривых, поэтому пришлось добавить в смарт-контракт функцию, которая возвращает результат ecrecover от сообщения и научиться правильно передавать в нее параметры (доставать их из подписанного MetaMask-ом сообщения).
В результате за два дня мы получили proof-of-concept децентрализованной аутентификации с использованием сети Ethereum и плагина MetaMask. Мы понимаем, как нужно доработать эту систему, чтобы добавить в нее анонимность для пользователя. Пользователь имеет возможность восстановить доступ в случае утечки его основного ключа (но не в случае утечки ключа восстановления). Децентрализованная система неподвластна цензуре крупных структур, таких как Google или Facebook. При необходимости цензуры сайт должен осуществлять ее самостоятельно, но он может сделать это только в рамках собственной системы, не влияя на доступ пользователя к другим системам. Сеть Ethereum не очень быстро проводит транзакции (при создании аккаунта пользователю может быть придется подождать несколько минут), но доставать данные и осуществлять проверку аутентификации пользователя можно очень быстро. Это решение хорошо масштабируется, поскольку узлов с данными очень много, и любой желающий может добавить еще один в любой момент. Трудоемкость же внедрения такого решения для владельцев сайтов не выше, чем трудоемкость внедрения поддержки OAuth 2.0.
Заключение
Безусловно, сегодня пользователей использующих сеть Ethereum ничтожно мало в сравнении с числом пользователей Facebook. Однако популярность блокчейн-технологий растет, и я верю, что в обозримом будущем таких пользователей будет становиться все больше и больше, а значит появится возможность для использования децентрализованной аутентификации в промышленных системах.
Ссылки
- Исходный код https://github.com/mixbytes/etherauth
Автор: mxpaul