НИЛИТ П::01::Вводная и бонусом - как можно безопасно хранить и проверять пароли

Уф... В процессе суровой почти круглосуточной работы в последние 2 недели наметился просвет (в 23:30, что символично...). Так вот, подумал я, подумал, да и решил публиковать маленькие хитрости ИТ до которых дошел сам (что не исключает, что кто-то дошел до них раньше/позже).


Итак, прежде всего обо мне нужно знать 2 вещи:

1. Говнокодю пишу (или это надо зачеркнуть?) я в подавляющем случае для себя.

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


Еще мой большой недостаток - работа в "режиме FullStack". Те кто читали/читают Хабр наверно думают, что FS - это миф (https://habrahabr.ru/company/Voximplant/blog/275229/), но я больше склоняюсь к такой концепции (с того же Хабра) https://habrahabr.ru/post/278467/


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


Можно разжечь цельный холивар о том что лучше FS или OO (Only One - разработчик только в одной технологии), но лучше сразу признать, что нужны обе категории специалистов, а с учетом современных реалий для 95-99% задач нужны именно FS разработчики. Почему? Потому что в 95-99% случаев заказчику требуется куча всего и он не настолько квалифицирован чтобы отличить говнокод от высококлассного. Поэтому (к моему глубочайшему сожалению) говнокодеры нынче в моде.


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


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


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


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


Пароли в открытом виде хранятся только в двух случаях:

1. У полных идиотов

2. Для обеспечения автоматического использования в сторонних программах

Во всех остальных случаях хранят не пароли, а их хеши. Хеш-функция - односторонняя функция преобразования с потерей точности. Самая простая иллюстрация хеш-функции это остаток от деления. Например простейший хеш можно изобразить как: хеш = остаток(число / 12345). Совершенно очевидно, что если число больше чем 12345 то одному хешу будет соответствовать несколько значений, а значит исходным паролем может быть любой из возможных вариантов. Это приводит к двум очевидным особенностям:

Положительная: даже если хеш подобран, это не гарантирует что именно это решение - верное. Если один и тот же пароль используется на нескольких сайтах, то при небольшом везении можно частично избежать взлома всего.

Отрицательная: как пароль подойдет любой из возможных вариантов хеша.

Атаки на хеши разнообразны и порой весьма оригинальны, но самой действенной атакой остается банальный перебор вариантов (особенно помогают "Радужные таблицы" https://ru.wikipedia.org/wiki/Радужная_таблица ). Хорошая статья по методам защиты от перебора написана здесь: https://habrahabr.ru/post/139974/


Так вот, посидел я, подумал и решил, что пора двигаться дальше, потому что предложенное в статье решение хоть и рабочее, но приводит к сильной нагрузке на сервер. В принципе это не проблема если ресурс очень слабо нагружен или есть много денег на кучу серверов. Но если мы бедны и убоги?


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


Регистрация:


Запрашиваем: логин, пароль

Случайно генерируем "соль" т.е. последовательность символов.

Вычисляем длину пароля.

Генерируем n паролей той же длинны и заносим в массив n[x] (лучше чтобы 30-40 % вариантов были из радужных таблиц)

Вычисляем хеши логин+соль+n[x] и заносим его в отдельную таблицу (отдельная таблица для y пользователей)

Обход цикла n (циклично проходим по массиву подставляя значения n): Вычисляем хеши логин+соль+n[x] и заносим эти значения в ту же таблицу



Авторизация:

Запрашиваем: логин, пароль

Вычисляем хеши логин+соль+n[x] и сверяем его с таблицей

Если хеш в таблице есть, то авторизацию разрешаем


В чем плюсы:

- низкая нагрузка на сервер

- нужно пересчитывать пароли для каждого пользователя

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


В чем минусы:

- к аккаунту подходят y*n паролей


Этот минус можно нивелировать если детектировать перебор паролей как связку IP/логин и разрешать запросы на авторизацию по 1 в 5-10 секунд.


Разумная критика приветствуется.

2
Автор поста оценил этот комментарий

Что-то не уловил, в чем выигрыш вашей схемы.

Классика - это когда каждый пароль хранится в хэшированном виде вместе со своей солью (см. /etc/passwd, /etc/shadow).

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


У вас, получается, соль будет одна на всех, я правильно понимаю? По факту у вас получается модифицированная хэш-функция, которая от обычной отличается только тем, что начальные значения переменных не "канонические", а соответствуют состоянию, когда прохэширована заранее известная соль.

Ну а в качестве самой соли вы предлагаете использовать логин и/или IP.


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


Например, присылаем клиенту соль и уникальное число - nonce - и получаем от него хэш hash('nonce:' + hash('salt:password')). На стороне сервера хэшируем то же самое (hash('salt:password') нам уже известен) и сравниваем с присланным - если совпало, то клиент молодец, а если нет - то не молодец и не клиент. Большой плюс этой схемы - пароль не передается по сети в открытом виде и не хранится на сервере, а значит, его не получится перехватить прослушиванием трафика.


Конечно, плохо хранить пароли на сервере в открытом виде, но. Если вашу базу данных увели - поздно пить боржоми, там и без паролей есть чем поживиться (фио-адреса-телефоны-явки-карты-емейлы и т.п.).

раскрыть ветку
Автор поста оценил этот комментарий
Смс? Не? А ип тебе генерить можно всегда, тут защиты ноль
раскрыть ветку
1
Автор поста оценил этот комментарий
Ребят, убейте, но не понял ,вроде русский язык...
раскрыть ветку