Хранение уникальных паролей для всех сайтов и приложений — целое искусство. Невозможно запомнить сотню длинных паролей с высокой энтропией. Может быть, в мире есть десяток высокоразвитых аутистов, способных на такое, не больше. Остальным людям приходится использовать технические трюки. Самый распространённый вариант — записать все пароли в один файл, который защищён мастер-паролем. По такому принципу работает большинство парольных менеджеров.

У этого способа много преимуществ, но есть два главных недостатка: 1) трудно синхронизировать пароли между устройствами; 2) нужно всегда иметь в распоряжении сам файл с паролями. То есть потерял файл с паролями — и до свидания.

Новый парольный менеджер LessPass с открытым исходным кодом лишён этих недостатков, потому что работает на чистой детерминированной функции. У него есть другие недостатки, конечно. Об этом ниже. Сначала о достоинствах.

Концепция


Концепция LessPass заключается в том, что регенерация одноразовых паролей происходит на лету при помощи чистой функции, которая выдаёт детерминированные значения каждый раз при расчёте каждого уникального пароля.

На вход функции подаются четыре аргумента:

  • мастер-пароль
  • логин на сайте
  • адрес сайта
  • опции генерации пароля

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

Как это выглядит.



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

Разработчик программы Гийом Винсент (Guillaume Vincent) постарался реализовать безопасность, насколько он её понимает. Какая безопасность нужна для детерминированной функции? В первую очередь — чтобы по результату её работы нельзя было определить все её аргументы, тем более что некоторые аргументы уже известны злоумышленнику, как и сама функция.

Проще говоря, если злоумышленник знает два или три из четырёх аргументов, а также результат функции, он не должен узнать четвёртый аргумент — мастер-пароль.

Для защиты мастер-пароля от брутфорса вычисление уникальных паролей LessPass прогоняет 8192 итерации функции PBKDF2 с хэш-функцией SHA-256.



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

Теперь, чтобы «вспомнить» уникальный пароль для конкретного сайта — просто запускаем программу LessPass. Это крошечная программа состоит всего из 109 строчек.

Код программы
import crypto from 'crypto';

module.exports = {
    encryptLogin: _encryptLogin,
    renderPassword: _renderPassword,
    createFingerprint: createFingerprint,
    _deriveEncryptedLogin,
    _getPasswordTemplate,
    _prettyPrint,
    _string2charCodes,
    _getCharType,
    _getPasswordChar,
    _createHmac
};

function _encryptLogin(login, masterPassword, {iterations = 8192, keylen = 32}={}) {
    return new Promise((resolve, reject) => {
        if (!login || !masterPassword) {
            reject('login and master password parameters could not be empty');
        }
        crypto.pbkdf2(masterPassword, login, iterations, keylen, 'sha256', (error, key) => {
            if (error) {
                reject('error in pbkdf2');
            } else {
                resolve(key.toString('hex'));
            }
        });
    })
}

function _renderPassword(encryptedLogin, site, passwordOptions) {
    return _deriveEncryptedLogin(encryptedLogin, site, passwordOptions).then(function (derivedEncryptedLogin) {
        const template = passwordOptions.template || _getPasswordTemplate(passwordOptions);
        return _prettyPrint(derivedEncryptedLogin, template);
    });
}

function _createHmac(encryptedLogin, salt) {
    return new Promise(resolve => {
        resolve(crypto.createHmac('sha256', encryptedLogin).update(salt).digest('hex'));
    });
}

function _deriveEncryptedLogin(encryptedLogin, site, passwordOptions = {length: 12, counter: 1}) {
    const salt = site + passwordOptions.counter.toString();
    return _createHmac(encryptedLogin, salt).then(derivedHash => {
        return derivedHash.substring(0, passwordOptions.length);
    });
}

function _getPasswordTemplate(passwordTypes) {
    const templates = {
        lowercase: 'vc',
        uppercase: 'VC',
        numbers: 'n',
        symbols: 's',
    };
    let template = '';
    for (let templateKey in templates) {
        if (passwordTypes.hasOwnProperty(templateKey) && passwordTypes[templateKey]) {
            template += templates[templateKey]
        }
    }
    return template;
}

function _prettyPrint(hash, template) {
    let password = '';

    _string2charCodes(hash).forEach((charCode, index) => {
        const charType = _getCharType(template, index);
        password += _getPasswordChar(charType, charCode);
    });
    return password;
}

function _string2charCodes(text) {
    const charCodes = [];
    for (let i = 0; i < text.length; i++) {
        charCodes.push(text.charCodeAt(i));
    }
    return charCodes;
}

function _getCharType(template, index) {
    return template[index % template.length];
}

function _getPasswordChar(charType, index) {
    const passwordsChars = {
        V: 'AEIOUY',
        C: 'BCDFGHJKLMNPQRSTVWXZ',
        v: 'aeiouy',
        c: 'bcdfghjklmnpqrstvwxz',
        A: 'AEIOUYBCDFGHJKLMNPQRSTVWXZ',
        a: 'AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz',
        n: '0123456789',
        s: '@&%?,=[]_:-+*$#!\'^~;()/.',
        x: 'AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz0123456789@&%?,=[]_:-+*$#!\'^~;()/.'
    };
    const passwordChar = passwordsChars[charType];
    return passwordChar[index % passwordChar.length];
}

function createFingerprint(str) {
    return new Promise(resolve => {
        resolve(crypto.createHmac('sha256', str).digest('hex'))
    });
}

Генерация паролей работает в виде скрипта на сайте LessPass, или на клиентском компьютере. Выпущены соответствующие расширения для Chrome и для Firefox. Скрипт генератора можно запустить и в локальном облаке. Например, с помощью локального облака Cozy.

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

Недостатки LessPass очевидны и вытекают из его достоинств. Самое главное, что при компрометации мастер-пароля все десятки или сотни производных уникальных паролей для всех сайтов сразу можно считать потерянными.

Второй недостаток — вы не можете нормально и удобно поменять пароль для конкретного сайта. Для этого придётся изменить один из параметров генерации паролей (Counter). Впоследствии придётся помнить, какой конкретно параметр использовался для каждого сайта. Где единица, где двойка, где тройка, и так далее. Кроме того, нужно помнить уникальные требования каждого сайта к паролям. Например, какие-то банковские приложения могут ограничить пароль только цифрами и длиной в шесть цифр. Для решения этой проблемы в LessPass реализованы профили для сайтов. В профиле хранитеся вся информация, необходимая для генерации пароля, кроме мастер-пароля.


Профили в LessPass

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

Ситуация ухудшается тем, что в данной конкретной реализации LessPass использует всего 8192 итерации PBKDF2-SHA256. По мнению специалистов, этого крайне недостаточно для надёжной защиты от брутфорса на GPU. Ещё несколько лет назад рекомендовалось минимум 100 000 итераций, а вычислительная мощность брутфоса примерно удваивается каждый год. Так что будем считать, что нынешняя реализация LessPass — просто демонстрационная версия, доказательство работоспособности концепции.

LessPass — не единственный детерминированный менеджер паролей, работающий на чистой функции. Есть и другие аналогичные программы, в том числе Master Password App и Forgiva. У всех этих программ те же недостатки, о которых упоминалось выше. К тому же, в них нельзя импортировать свои старые пароли, так что при миграции на такую программу придётся заново генерировать все пароли.

Несмотря на все недостатки, генератор детерминированных паролей на чистой функции — интересная концепция. Возможно, кому-то именно такой парольный менеджер покажется наиболее удобным.
Поделиться с друзьями
-->

Комментарии (38)


  1. Revertis
    07.11.2016 22:02
    +1

    На Хабре уже пару лет назад автор писал о подобном генераторе, который работает на vpass.info.
    А я давненько на его основе сделал расширение для ФФ: https://addons.mozilla.org/ru/firefox/addon/vpass-password-generator/
    На сайте, где хотите залогиниться, вводите логин, переходите на поле пароля, там нажимаете F9, в появившемся окошке вводите только свой мастер-пароль и нажимаете Enter. Сгенерированный пароль вводится в поле пароля.


    1. ValdikSS
      07.11.2016 23:03
      +1

      А еще есть supergenpass, он раньше всех появился (в то время назывался genpass).


      1. vtyulb
        08.11.2016 04:13

        Я тоже аналогичный генератор себе написал весной 2013-ого года. Rupass, функционала немного, но работает же. Пользовался им несколько лет, но потом узнал про keepassx.

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


      1. glazunoff
        08.11.2016 12:57

        да, SuperGenPass наше всё!


  1. KennyGin
    07.11.2016 22:06
    +13

    Четвертый и главный недостаток: вам надо помнить все логины, либо использовать один единственный логин и один адрес почты на вообще всё


    1. stdenis
      08.11.2016 00:35
      +2

      А если есть несколько аккаунтов на одном сайте, то вообще беда


    1. saboteur_kiev
      08.11.2016 01:19

      Зачем? Главное ведь не lesspass а сама идея.

      Можно написать себе свой менеджер или плагин, в котором будет сохраняться и сайт и логин, а пароль генериться по первому, по второму или по обоим вместе + соль. В общем додумать можно.


  1. dartraiden
    07.11.2016 22:09
    +2

    1) трудно синхронизировать пароли между устройствами; 2) нужно всегда иметь в распоряжении сам файл с паролями. То есть потерял файл с паролями — и до свидания.

    Обе проблемы решаются с помощью облачных хранилищ. База у всех приличных менеджеров паролей хорошо зашифрована.


    1. alexvoz
      08.11.2016 00:58

      Вот только если это не ваш личный менеджер паролей — на 100% ему доверять нельзя. Кто знает — все ли там по честному или оставлены бэкдоры для себя или еще кого-то. А написать свой личный менеджер паролей смогут не все.


      1. dartraiden
        08.11.2016 03:37

        К KeePass, если не изменяет память, можно писать плагины с собственной реализацией шифрования.
        На худой конец, можно банально шифровать с помощью открытого 7-zip.


  1. DenimTornado
    07.11.2016 22:17
    +7

    Блин, читал-читал статью, и только когда пролистал по новой понял, что речь не про LastPass!


    1. Sild
      07.11.2016 22:28
      +1

      Так это ж хорошо.


  1. Sild
    07.11.2016 22:20
    +9

    Хе, что ж получается…
    плюсы: у злоумышленника нет возможности украсть у вас файл с паролями, потому что его нет!
    недостатки: для брутфорса вашего пароля злоумышленнику не нужен никакой файл.


    1. Revertis
      07.11.2016 23:18
      +2

      Ага, для того, чтобы сбрутить пароль, ему нужно… сбрутить пароль :)


      1. Loki3000
        07.11.2016 23:30
        +1

        Да, но достаточно его сбрутить на одном сайте, чтобы получить доступ ко всем.


        1. Revertis
          08.11.2016 08:56

          Ага, только ему еще нужно догадаться, что вы используете какой-то из генераторов :)


          1. Loki3000
            08.11.2016 09:26

            Если атакуем конкретного человека то это, скорее всего, известно. Заманили его к себе на сайт и попросили зарегистрироваться — вот тебе и материал для работы сразу. Или человек проговорился где-то что использует подобную штуку… На хабре в комментариях, например.


    1. rusher
      08.11.2016 07:21

      Из за PBKDF2, брутить придется долго


  1. klev
    07.11.2016 23:43
    +1

    При частичной смене URL сайта, будет генерироваться неправильный пароль


    1. areht
      08.11.2016 00:37
      +1

      При наличии на одном сайте 2-х сервисов с разными паролями — вообще беда


  1. Baton34
    08.11.2016 00:34

    а если сайт сменил адрес|домен, заново регаться?


    1. Karpion
      08.11.2016 09:48
      +1

      Вводить старый домен.


  1. timelle
    08.11.2016 00:52

    База KeePass2 в облачном хранилище с мастер-паролем и ключом. Для мобильных устройств не подойдет, но для ноутбуков и ПК — вполне.


    1. chesterset
      08.11.2016 01:00
      +5

      Почему для мобильных не подойдёт? База и ключ в облаке (скажем, том же Я.Диске), прекрасно работает на и на ПК, и на ноутбуке, и на смартфоне (Android).


      1. nicknishim
        08.11.2016 09:48
        +3

        Подтверждаю, база KeePass2 лежащая в облаке (в моем случае домашний owncloud) прекрасно работает на всех платформах (Windows, Linux, Android, IOS)


      1. sumanai
        08.11.2016 18:55

        Вот у меня работает, но так как я настраивал на число циклов хеширования пароля на задержку в 1 сек, то на телефоне задержка вышла более 10 сек.


  1. anitspam
    08.11.2016 07:42

    Интересно, словом «свободный» было переведено «LessPass is open-source» или «LessPass is free
    and always will be».


    1. K0styan
      08.11.2016 13:56

      Полные исходники — в статье же, под спойлером. Абзацем ниже синей картинки со схемой генерации.
      Другой вопрос, что open source не всегда равно free. Но сходить на сайт автора за лицензионным соглашением тоже никто не мешает.


  1. somniator
    08.11.2016 09:41
    +1

    есть два главных недостатка: 1) трудно синхронизировать пароли между устройствами;

    в 2016 уже не трудно

    2) нужно всегда иметь в распоряжении сам файл с паролями.

    не является недостатком как следствие п. 1


  1. ruzhovt
    08.11.2016 10:31

    Недостатки сильно превышают преимущества.

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

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

    Украсть/увидеть мастер пароль довольно просто. Украсть куки из хттпс канала куда сложнее.


  1. n00b1k
    08.11.2016 11:23
    +1

    — Пароли рекомендуют менять раз в несколько месяцев. Некоторые сайты настойчиво «предлагают» сменить пароли. Как тут быть?
    — Есть сайты где спец символы не поддерживаются. Нужно помнить состав типов символов для каждого сайта.
    — Скомпрометировал мастер пароль. В нормальном менеджере перешифровал БД, что делать в этой ситуации с этим менеджером?


    1. flerant
      08.11.2016 13:28

      На второй вопрос есть ответ в тексте.


    1. dpantele
      08.11.2016 23:59

      1. Изменить counter. Например, просто поставить его в 201611 и менять каждый месяц для важных паролей.
      3. Если делать с синхронизацией, как предлагают многие, то после компрометации масетр-пароля всё равно надо менять все пароли.


  1. guai
    08.11.2016 13:48

    а после того, как надо было поменять пароль на сайте на новый, придется запоминать настройки генерации :)
    для каждого сайта


  1. mafia8
    08.11.2016 14:49

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


  1. ruwebstyle
    08.11.2016 15:55

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


    1. ESP
      08.11.2016 20:02

      > более менее безопасно
      Надеюсь, среди разработчиков подобного рода софта не многие мыслят подобным образом.


  1. avas
    08.11.2016 20:25

    Эээх — давно то было… Наша компания придумала такое же — вот только в архивах нашел https://www.helpnetsecurity.com/2006/03/20/amust-software-announces-amust-1-password/


    Мы решили проблему с запоминанием логинов — генерили файлик, который открывался по мастер паролю и синкали его в Gmail/Hotmail/etc просто как драфт письма
    Если пользователь находился вдали от родного компьютера с софтом просили его зайти в его почту взять текст из этого драфта и закопипастить на страничку, а далее расшифровывали все с мастер паролем с помощью чистого ДжаваСкрипта.