Иногда я вижу вопросы, задающие вопрос, как безопасно хранить пароли пользователей для веб-приложения (используя СУБД, я не говорю о Facebook или Twitter). Обычный ответ - «посолить пароль, а затем хешировать его с помощью надежного алгоритма, такого как TDES или SHA512».
Мой вопрос: как пользователю СУБД, зачем мне вообще беспокоиться о хранении пароля, так как большинство движков имеют встроенный механизм аутентификации.
Например, если какой-то пользователь X хочет создать пароль пользователя учетной записи Y в моем веб-приложении, как неправильно выполнить следующий запрос:
CREATE USER X WITH ENCRYPTED PASSWORD Y IN GROUP baseuser;
Затем в моем приложении пользователь может открыть соединение с базой данных, используя свои учетные данные, и мне не нужно беспокоиться об управлении паролями.
Я вижу много преимуществ этого метода:
- Если СУБД решит, что алгоритм шифрования необходимо изменить, мне не нужно ничего трогать, только чтобы применить обновления безопасности;
- Мне легко управлять авторизацией пользователей. Если пользователь повышен до роли администратора, мне просто нужно добавить пользователя в соответствующую группу;
- Инъекции SQL теперь не имеют смысла, так как я управляю разрешениями, чтобы разрешить именно то, что я хочу разрешить каждому пользователю в базе данных (например, на форуме, таком как SO, добавляя новые сообщения, отвечая на сообщения, комментируя и редактируя / удаляя его собственные вопросы). / ответы / комментарии);
- Учетная запись пользователя «анонимный» может использоваться для неаутентифицированных подключений к моему приложению;
- Каждый пользователь является владельцем предоставленных им данных.
Но практически по каждому вопросу, который я вижу по этой теме, по-видимому, существует общее мнение о том, что это не так, как нужно делать. Мой вопрос: почему?
Примечание. Третий момент допускается политиками в PostgreSQL и политиками безопасности в Microsoft SQL Server. Я понимаю, что эти концепции являются новичками, но в любом случае, теперь, когда они здесь, почему описанная мною техника не становится стандартным способом обработки учетных записей пользователей?
Ответы:
Потому что для многих приложений они не хотят, чтобы отдельные учетные записи пользователей подключались к базе данных. Все пользователи / пароли / права / разрешения обрабатываются на прикладном уровне, а одна отдельная учетная запись службы используется для подключения к базе данных.
Как администратор БД, я не хочу, чтобы на уровне базы данных управляли 10 000 активных пользователей какого-либо общедоступного веб-приложения среднего размера или, возможно, более 2 миллионов пользователей некоторых неожиданно популярных приложений.
В очень реальном смысле, это различие в философии между разработчиками приложений и разработчиками баз данных / администраторами баз данных.
Многие / большинство разработчиков приложений не захотят передавать ответственность за основные аспекты функциональности приложения и / или бизнес-правил на уровень базы данных. Вместо этого они рассматривают базу данных как инструмент для простого хранения и извлечения данных.
В некоторых случаях это может быть близоруким; многие РСУБД имеют потрясающие функции, которые могут значительно облегчить жизнь разработчикам приложений (безопасность на уровне строк, столбчатые индексы, хранилище файловых потоков и т. д.).
Но некоторые из этих кулеров доступны только в новых версиях, и организации не всегда могут быстро обновить существующие среды (см. Эту диаграмму за 2014 год ).
А в других случаях обработка этих вещей на уровне приложений предпочтительна (и не только для переносимости платформы баз данных, я откровенно считаю, что претензия преувеличена).
источник
В этот момент разделительная линия становится немного пушистой, но я бы посчитал, что пользователи и разрешения на уровне базы данных являются частью схемы, а не частью данных, и в общем случае приложения не имеют места для изменения схемы (есть, как всегда, исключения из этого правила).
Я бы предпочел не давать приложениям разрешения, необходимые для управления объектами схемы (логины, пользователи и разрешения), поскольку нужны новые пользователи и уходят старые, потому что, если это приложение взломано, злоумышленник получает доступ к этим разрешениям. облегчая взлом базы данных дальше. В MS SQL Server, если вы не используете полностью автономные базы данных, логины являются объектами уровня сервера, поэтому вам нужно выдавать права за пределы единой базы данных приложения, что делает ее еще более рискованной.
Более того, даже если у вас есть учетные записи пользователей на уровне приложения на уровне базы данных, вам все равно нужны учетные записи пользователей уровня приложения для обработки неаутентифицированных запросов, т. Е. Если приложению требуется информация из базы данных до успешной аутентификации пользователя приложения (возможно, для отобразить информацию о состоянии на экране приветствия / входа в систему?).
Также, если переносимость между движками баз данных является целью (возможно, ваше приложение хочет иметь возможность работать как на mysql, так и на postgres?), Тогда вашим приложениям нужно будет абстрагировать функции управления пользователями и входом в систему для каждого движка, поскольку они не являются стандартными между ними - если вы собираетесь это сделать, то вы можете также самостоятельно внедрить пароли и получить желаемые варианты управления вместо того, чтобы принимать наименьший общий набор функций, предлагаемый движками.
источник
Повторяю вопрос
Самый простой ответ заключается в том, что вы должны это сделать. Вы все еще храните пароли в вашем альтернативном методе. Просто вы используете встроенную систему базы данных для управления хранилищем. Таким образом, ваш метод так же хорош, как и ваша база данных. Это все еще может быть лучше, чем то, что вы могли бы сделать в противном случае, но это не избежать хранения. Это действительно просто избегать хранения кода.
Это также не могло бы быть лучше. Если я скомпрометирую базу данных и получу копии файлов, я смогу получить доступ к таблицам напрямую. Так что нет смысла использовать блестящую систему управления паролями. Потому что, если кто-то может получить доступ к таблице системного уровня, содержащей пароли или хешированные пароли, он также может получить доступ к файлам напрямую. Зачем взламывать пароли, когда у вас уже есть данные? Вы не можете легко зашифровать данные. Каждый пользователь должен иметь возможность получить к нему доступ. Так что шифрование на уровне пользователя не будет работать так хорошо.
Но то, что вы действительно спрашиваете, это
Безопасность
Игнорируя вероятность того, что вы могли бы написать более безопасную версию, другие предложили ряд причин. Я в целом согласен. Но есть еще один, который еще никто не упомянул. Вы ставите под угрозу безопасность вашей базы данных.
В этой системе каждый пользователь вашего приложения имеет пользователя базы данных и пароль. Конечно, это ограниченный пользователь, но он все еще может подключаться к базе данных. Даже если вы используете безопасность на уровне строк, вы все равно позволяете конечным пользователям знать информацию о подключении к базе данных. Если есть когда-нибудь эксплойт, в котором пользователь может получить доступ даже на уровне таблицы, вы открыли свою базу данных для атаки. И некоторые эксплойты вышли за рамки доступа администратора.
В слоях с луком безопасности нормальная система:
В этой системе:
Мы потеряли весь уровень безопасности приложений. И мы добровольно отказались от части уровня базы данных. Таким образом, нам нужно только два эксплойта:
Если мы сможем сделать эти две вещи, у нас будет доступ к базе данных. Итак, мы идем от трех слоев до двух. (Третий уровень в обычной системе заключается в том, что вам нужен действительный пользователь для подключения к базе данных.)
Вы собираетесь много управлять этими учетными записями. Что делать, если вы допустили ошибку? Вместо того, чтобы ограничивать пользователя X только определенными строками, вы предоставляете им доступ к критической таблице. Такие вещи обычно выполняются вручную, и их всего несколько, поэтому их легко проверить. Но в вашей системе вы можете создавать тысячи, миллионы или даже миллиарды учетных записей пользователей, каждый из которых имеет свой собственный доступ.
В этом отношении система базы данных масштабируется до миллионов или миллиардов пользователей? Если да, то как насчет количества правил? Если каждый пользователь использует сотню или более правил о том, что он может и не может получить, может ли он достигнуть миллиарда пользователей? Вы берете обычно маленькую систему и делаете ее крупной. Это не обязательно сработает. Вы можете найти системные ограничения по мере роста.
источник
То, что вы описываете, будет обрабатывать аутентификацию, но не авторизацию (к каким данным пользователь может получить доступ) или только в самом простом случае использования.
Чтобы продолжить на вашем примере с stackexechange: Как бы вы сделали удаленный пост видимым только для пользователей с высоким уровнем репутации? Так что для правил доступа вам все равно понадобится логика в коде. Вместо того, чтобы разделять логику доступа между правилами базы данных и применимыми правилами доступа, большинство разработчиков предпочитают размещать их в одном месте.
Вам также понадобится таблица для хранения информации о пользователе: пользователь - это не просто имя пользователя + пароль. У него есть электронная почта, репутация и так далее. Таким образом, вам все еще нужна пользовательская таблица, которую вы должны убедиться, что она синхронизирована с пользовательской таблицей базы данных, при условии, что вы можете получить к ней доступ.
С помощью вашего решения вы можете просто опустить столбец паролей, который не так сложно заполнить: есть хорошие библиотеки и документация о том, как обрабатывать / хэшировать пароли.
Другой момент: как бы вы создали пул соединений? Я знаю только jdbc (java <-> db), и вам нужно указать имя пользователя + пароль, чтобы получить соединение, которое вы затем сможете объединить.
Я подумал о некоторых других моментах, которые будет сложнее / сложнее реализовать, чем при установленном способе:
источник
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-ю функциями, возвращающими соединения :-)Еще один момент: многие [1] веб-приложения позволяют вам зарегистрироваться и создать учетную запись пользователя через само приложение. Это означает, что ваш анонимный пользователь (у которого должно быть наименьшее количество привилегий), должен иметь права для создания пользователей и предоставления привилегий!
Хорошо, возможно, можно ограничить те привилегии, которые он может предоставить, и предоставить пользователям более высокого уровня больше возможностей предоставления (хотя я не знаю, так ли это - часто «не предоставляйте привилегии» одной привилегии). Но, тем не менее, это означает размещение чего-то с привилегиями предоставления в режиме онлайн, чтобы каждый мог взломать. Я почти уверен, что мой DBA не понравится мне, если я сделаю это :)
Я знаю, что на одном уровне эта проблема все равно существует, но у вас есть уровни защиты, особенно для удаления данных, если вы не разрешаете веб-приложению управлять пользователями БД.
Кроме того, это предотвратит любое использование подключенных или повторно используемых подключений к БД.
[1] Большинство, я бы сказал, но не цифры, чтобы поддержать это
источник