← Все статьи
Безопасность в Эхофоне: как мы защищаем ваши уведомления
24 мая 2026
Пересылка уведомлений с телефона на компьютер — это передача крайне чувствительных данных. Коды подтверждения из SMS, банковские уведомления, личная переписка. Если сервис относится к безопасности легкомысленно, последствия могут быть катастрофическими. В этой статье я расскажу, как мы защищаем данные в Эхофоне, где храним чувствительную информацию и почему некоторые решения, популярные у конкурентов, для нас неприемлемы.
Почему безопасность уведомлений — это важно
Представьте: вы фрилансер. Клиент присылает в Telegram доступ к серверу. Это уведомление уходит на ваш телефон, потом — на сервер пересылки. Если сервер не шифрует данные, разработчик сервиса или хакер, взломавший базу данных, получает доступ к вашему серверу клиента.
Другой сценарий: SMS с кодом от банка. Если такой код перехватят, злоумышленник может подтвердить перевод. Именно поэтому мы считаем, что сервер пересылки не должен видеть содержимое сообщений. Ни при каких обстоятельствах.
Главный принцип: сервер не знает текста
В Эхофоне сообщение шифруется на телефоне до отправки на сервер. Сервер получает уже шифрованный набор байтов, сохраняет его в базу данных и передаёт в браузер. Расшифровка происходит только в браузере пользователя, с использованием ключа, который сервер никогда не получает.
Это называется сквозное шифрование (end-to-end encryption, E2EE). Даже если база данных сервера будет полностью скопирована злоумышленником, он не сможет прочитать сообщения — они выглядят как случайные строки Base64. Без ключа расшифровка невозможна.
Как мы храним чувствительные данные на сервере
Никаких открытых текстов. Вот что и как мы храним:
- Пароль пользователя. Хранится в виде bcrypt-хеша с солью (10 раундов). Даже мы не можем восстановить исходный пароль. При логине пароль проверяется через bcrypt.compare.
- Соль для шифрования (encryption_salt). Случайная строка из 64 символов. Хранится в БД, но бесполезна без пароля. Соль нужна, чтобы одинаковые пароли у разных пользователей давали разные ключи шифрования.
- Зашифрованные сообщения. Хранятся в колонке
encrypted_body. Это Base64-строка, содержащая IV (12 байт) + зашифрованный текст + authentication tag (16 байт). Сервер никогда не пытается расшифровать эти данные.
- JWT-токены. Хранятся только на клиенте. Сервер проверяет подпись, но не хранит токены в БД.
- API-ключи устройств. Хранятся в открытом виде в БД, потому что сервер должен проверять их при каждом запросе от телефона. Но API-ключ даёт доступ только к отправке зашифрованных сообщений, а не к чтению.
Что мы не храним на сервере
- Открытый текст сообщений — никогда.
- Пароль пользователя в открытом виде — никогда.
- Ключ шифрования — никогда. Он генерируется на лету из пароля и соли.
Как мы храним чувствительные данные на клиенте
Клиент — это браузер. Хранение чувствительных данных в браузере — всегда компромисс между удобством и безопасностью. Вот как мы его решаем:
- Пароль. Больше не хранится. В ранних версиях мы сохраняли пароль в localStorage, чтобы не запрашивать его каждый раз. Это было ошибкой. Сейчас мы генерируем производный ключ (AES-256) из пароля и соли через PBKDF2, и сохраняем только этот ключ, а не сам пароль. Злоумышленник, получивший доступ к localStorage, увидит ключ, но не узнает пароль пользователя (который может использоваться и для других сервисов).
- Ключ шифрования. Хранится в localStorage в виде hex-строки. Это необходимо, чтобы не требовать пароль при каждом открытии Эхокамеры. Мы осознаём риск: если злоумышленник получит физический доступ к браузеру, он сможет расшифровать сообщения. Но не сможет получить пароль.
JWT-токен. Хранится в httpOnly cookie — JavaScript не может прочитать этот токен, что полностью защищает от кражи через XSS-атаки. Срок жизни токена — 7 дней. Для дополнительной защиты мы используем Content Security Policy (CSP), ограничивающий запуск скриптов только с нашего домена.
Почему нельзя хранить пароль в localStorage
Многие сервисы грешат этим, особенно на старте. Это плохая практика по трём причинам:
- XSS-уязвимость. Если на сайте есть возможность внедрить скрипт (а она есть почти всегда), злоумышленник прочитает localStorage и получит пароль.
- Пользователи переиспользуют пароли. Пароль от вашего сервиса может совпадать с паролем от почты или банка.
- Физический доступ. Отошли от ноутбука — коллега открыл консоль и скопировал пароль.
В Эхофоне мы заменили хранение пароля на хранение производного ключа. Это не идеальное решение, но значительно лучше: ключ привязан к конкретному сервису и соли, его компрометация не раскрывает пароль.
Честно о рисках
Мы не можем обещать «абсолютную безопасность». Вот что остаётся уязвимым на сегодняшний день:
- Физический доступ к устройству. Если злоумышленник имеет доступ к вашему разблокированному компьютеру, он может открыть консоль и прочитать ключ из localStorage. Решение: блокируйте компьютер, когда отходите.
- Вредоносное ПО на телефоне. Если телефон заражён, уведомления могут быть перехвачены до шифрования. Эхофон не может защитить от этого.
- Слабый пароль. Если пароль «123456», злоумышленник с дампом БД может подобрать ключ перебором. Мы требуем минимум 6 символов, но рекомендуем использовать длинные пароли.
- XSS на сайте. Если злоумышленник найдёт XSS-уязвимость на echophone.ru, он сможет прочитать localStorage и украсть JWT-токен и ключ шифрования. Мы тщательно экранируем весь пользовательский ввод, но риск остаётся.
Мы планируем усилить безопасность: перейти на httpOnly cookies для JWT, добавить двухфакторную аутентификацию, внедрить Content Security Policy (CSP) для защиты от XSS.
Что делать пользователю прямо сейчас
- Используйте длинный и уникальный пароль для Эхофона.
- Не устанавливайте подозрительные расширения браузера.
- Блокируйте компьютер, когда отходите.
- Не храните пароль в стикерах на мониторе :)
Попробуйте безопасную пересылку уведомлений
Первые 7 дней бесплатно. Сквозное шифрование, никаких паролей в открытом виде.
Попробовать →