Зачем хранить пароли пользователей вообще?

10

Иногда я вижу вопросы, задающие вопрос, как безопасно хранить пароли пользователей для веб-приложения (используя СУБД, я не говорю о Facebook или Twitter). Обычный ответ - «посолить пароль, а затем хешировать его с помощью надежного алгоритма, такого как TDES или SHA512».

Мой вопрос: как пользователю СУБД, зачем мне вообще беспокоиться о хранении пароля, так как большинство движков имеют встроенный механизм аутентификации.

Например, если какой-то пользователь X хочет создать пароль пользователя учетной записи Y в моем веб-приложении, как неправильно выполнить следующий запрос:

CREATE USER X WITH ENCRYPTED PASSWORD Y IN GROUP baseuser;

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

Я вижу много преимуществ этого метода:

  • Если СУБД решит, что алгоритм шифрования необходимо изменить, мне не нужно ничего трогать, только чтобы применить обновления безопасности;
  • Мне легко управлять авторизацией пользователей. Если пользователь повышен до роли администратора, мне просто нужно добавить пользователя в соответствующую группу;
  • Инъекции SQL теперь не имеют смысла, так как я управляю разрешениями, чтобы разрешить именно то, что я хочу разрешить каждому пользователю в базе данных (например, на форуме, таком как SO, добавляя новые сообщения, отвечая на сообщения, комментируя и редактируя / удаляя его собственные вопросы). / ответы / комментарии);
  • Учетная запись пользователя «анонимный» может использоваться для неаутентифицированных подключений к моему приложению;
  • Каждый пользователь является владельцем предоставленных им данных.

Но практически по каждому вопросу, который я вижу по этой теме, по-видимому, существует общее мнение о том, что это не так, как нужно делать. Мой вопрос: почему?

Примечание. Третий момент допускается политиками в PostgreSQL и политиками безопасности в Microsoft SQL Server. Я понимаю, что эти концепции являются новичками, но в любом случае, теперь, когда они здесь, почему описанная мною техника не становится стандартным способом обработки учетных записей пользователей?

Фабиан Пийке
источник
2
Комментарии не для расширенного обсуждения; этот разговор был перенесен в чат .
Пол Уайт 9
Между прочим, обычный ответ неверен. Вы должны посолить пароль, а затем хешировать его с помощью медленного алгоритма, такого как bcrypt или argon2.
Tgr

Ответы:

27

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

Как администратор БД, я не хочу, чтобы на уровне базы данных управляли 10 000 активных пользователей какого-либо общедоступного веб-приложения среднего размера или, возможно, более 2 миллионов пользователей некоторых неожиданно популярных приложений.

В очень реальном смысле, это различие в философии между разработчиками приложений и разработчиками баз данных / администраторами баз данных.

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

В некоторых случаях это может быть близоруким; многие РСУБД имеют потрясающие функции, которые могут значительно облегчить жизнь разработчикам приложений (безопасность на уровне строк, столбчатые индексы, хранилище файловых потоков и т. д.).

Но некоторые из этих кулеров доступны только в новых версиях, и организации не всегда могут быстро обновить существующие среды (см. Эту диаграмму за 2014 год ).

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

BradC
источник
2
Существует «священная война» за то, идет ли бизнес-логика в приложении или в базе данных. Если вы создали приложение, в котором вся бизнес-логика (в частности, безопасность) находится в базе данных (с использованием хранимых процедур, представлений и т. Д.), То может быть аргумент для использования механизмов безопасности базы данных, потому что никто не может подключиться напрямую и обойти вашу безопасность. Я полностью согласен с тем, что вам следует избегать «перестройки» механизма безопасности (например, логин / пароль) в пользовательской таблице. Зачем это делать, если у вас уже есть активный каталог / безопасность O365.
Nick.McDermaid
1
@ Nick.McDermaid Я хотел бы убедиться в том, что я справедливо смешиваю бизнес-логику между БД и приложением, чтобы исключить возможность для будущих разработчиков иметь какое-либо чертовски ключ к пониманию происходящего, это также помогает мне поддерживать безопасность моей работы, поскольку никто не сумасшедший достаточно, чтобы хотеть управлять этим.
Der Kommissar
Добавьте туда веб-службу и сервер приложений tomcat, и вы сможете работать в IBM
Nick.McDermaid
8

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

Я бы предпочел не давать приложениям разрешения, необходимые для управления объектами схемы (логины, пользователи и разрешения), поскольку нужны новые пользователи и уходят старые, потому что, если это приложение взломано, злоумышленник получает доступ к этим разрешениям. облегчая взлом базы данных дальше. В MS SQL Server, если вы не используете полностью автономные базы данных, логины являются объектами уровня сервера, поэтому вам нужно выдавать права за пределы единой базы данных приложения, что делает ее еще более рискованной.

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

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

Дэвид Спиллетт
источник
1
Итак, «приложение не должно изменять схему», на мой взгляд, является первым хорошим аргументом против предложенной мной техники. Однако анонимная учетная запись, способная создавать новых пользователей, должна иметь возможность создавать новых пользователей с наиболее простым доступом. Только администраторы могут продвигать пользователей и удалять пользователей, что, как мне кажется, является тем, что требуется в приложениях :-) Общие данные видны анонимному пользователю, поэтому это соединение может использоваться для контента, где аутентификация не требуется. Переносимость также является хорошим моментом, но я думаю, что пользовательские команды теперь являются частью стандарта (не уверен, это было не много лет назад)
Фабиан Пийке
Кстати, с помощью этого параметра, если хакер получит доступ к базе данных как анонимный пользователь, он сможет создать столько пользователей, сколько захочет, но это не проблема безопасности, он также может наверняка раздуть базу данных, используя один из созданные учетные записи, это будет раздражать, но опять-таки не будет проблем с безопасностью (и он мог бы сделать это с помощью стандартного интерфейса в любом случае, хотя это было бы намного медленнее: p)
Фабиан Пийке
3
Я согласен, что с точки зрения безопасности пользователи уровня базы данных будут лучше. Однако в принципе это невозможно сделать, например, с помощью онлайн-магазинов, в которых может быть 50 миллионов зарегистрированных пользователей. Каждый из них должен быть пользователем базы данных. Плюс: это обычно не хорошо работает с веб-приложениями, использующими пул соединений.
a_horse_with_no_name
6

Повторяю вопрос

Зачем хранить пароли пользователей вообще?

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

Это также не могло бы быть лучше. Если я скомпрометирую базу данных и получу копии файлов, я смогу получить доступ к таблицам напрямую. Так что нет смысла использовать блестящую систему управления паролями. Потому что, если кто-то может получить доступ к таблице системного уровня, содержащей пароли или хешированные пароли, он также может получить доступ к файлам напрямую. Зачем взламывать пароли, когда у вас уже есть данные? Вы не можете легко зашифровать данные. Каждый пользователь должен иметь возможность получить к нему доступ. Так что шифрование на уровне пользователя не будет работать так хорошо.

Но то, что вы действительно спрашиваете, это

Зачем использовать схему аутентификации на уровне приложения, если в базе данных она уже есть?

Безопасность

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

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

В слоях с луком безопасности нормальная система:

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

В этой системе:

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

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

  1. Подделка или компрометация авторизованного сервера.
  2. Увеличьте доступ к учетной записи с ограниченными правами.

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

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

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

mdfst13
источник
5

То, что вы описываете, будет обрабатывать аутентификацию, но не авторизацию (к каким данным пользователь может получить доступ) или только в самом простом случае использования.

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

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

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

Другой момент: как бы вы создали пул соединений? Я знаю только jdbc (java <-> db), и вам нужно указать имя пользователя + пароль, чтобы получить соединение, которое вы затем сможете объединить.

Я подумал о некоторых других моментах, которые будет сложнее / сложнее реализовать, чем при установленном способе:

  • обработка восстановления пароля
  • Через 2 года после первоначального внедрения менеджер по продукту попросит вас добавить поддержку oauth-схемы или разрешить двухфакторную аутентификацию.
Thierry
источник
Нечто подобное CREATE POLICY deleted_posts_high_rep ON posts FOR SELECT TO baseuser USING ((SELECT rep FROM users WHERE name = current_user()) > 10000)отвечает на ваш первый вопрос. Я никогда не говорил, что мне больше не нужна таблица пользователей, и обеспечить синхронизацию с таблицей пользователей БД довольно сложно, но возможно. Основным вопросом обсуждаемой техники является безопасность. Что касается пула соединений, я работаю с OCaml и должен сказать, что не понимаю, зачем мне нужен пул соединений. В настоящее время я использую хэш-карту, связывающую значения cookie с 0-ю функциями, возвращающими соединения :-)
Fabian Pijcke
5
Пул соединений реализован для повышения производительности: с ними вам не нужно устанавливать соединение для каждого пользовательского запроса (поэтому вы сохраняете cpu / io / latency при создании tcp-ссылки + все соединения и аутентификационный обмен с базой данных). Что касается определения политики: ваша база данных будет постоянно проверять право доступа при каждом доступе к данным, даже если вы уже проверили их один раз. Также «доступ запрещен или запрещен» - это не то же самое, что «ОК, нет результата». Не уверен, что парни из службы безопасности предпочтут версию ОК.
Тьерри
3
Фабиан, пул соединений является фундаментальным в любом масштабе, это действительно значение по умолчанию, которое вы даже не подумаете не использовать. Вот несколько тестов, чтобы дать вам представление о том, насколько это важно: увеличение производительности в 600 раз с пулами соединений ( vladmihalcea.com/2014/04/17/the-anatomy-of-connection-pooling ) и увеличение производительности в 4000 раз с пул соединений ( progress.com/tutorials/jdbc/… ). Разница в несколько порядков, это не очень приятно, приложения без него остановятся.
Иван
1
Интересные цифры. И действительно, я никогда не видел приложение, не использующее пулы соединений. Но я не знал (и не ожидал), что они так сильно увеличатся. Другим аспектом, который вы получаете с пулом соединений, является управление ресурсами: благодаря им огромное увеличение количества клиентов, пытающихся подключиться сразу, замедлит работу вашего приложения, но на вашу базу данных это не повлияет так сильно (если пул хорошо настроен) ,
Тьерри
Хорошо, я просто искал дополнительную информацию о пулах соединений, и я согласен с тем, что это очень важный момент, поскольку веб-сайт должен обрабатывать более ста соединений в секунду, что не так уж и много. Кажется, что каждое соединение в PostgreSQL потребляет около 10 МБ ОЗУ! Я никогда не думал, что это так много.
Фабиан Пийке
1

Еще один момент: многие [1] веб-приложения позволяют вам зарегистрироваться и создать учетную запись пользователя через само приложение. Это означает, что ваш анонимный пользователь (у которого должно быть наименьшее количество привилегий), должен иметь права для создания пользователей и предоставления привилегий!

Хорошо, возможно, можно ограничить те привилегии, которые он может предоставить, и предоставить пользователям более высокого уровня больше возможностей предоставления (хотя я не знаю, так ли это - часто «не предоставляйте привилегии» одной привилегии). Но, тем не менее, это означает размещение чего-то с привилегиями предоставления в режиме онлайн, чтобы каждый мог взломать. Я почти уверен, что мой DBA не понравится мне, если я сделаю это :)

Я знаю, что на одном уровне эта проблема все равно существует, но у вас есть уровни защиты, особенно для удаления данных, если вы не разрешаете веб-приложению управлять пользователями БД.

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

[1] Большинство, я бы сказал, но не цифры, чтобы поддержать это

Адам
источник