Хранение, получение и проверка пароля (SecureString) в SQL Server

У меня есть окно входа в систему, которое получает имя пользователя и пароль от пользователя, и я хотел бы узнать, как лучше всего обработать пароль. Имя пользователя - это обычное текстовое поле, а пароль - PasswordBox. Я передаю имя пользователя непосредственно в ViewModel, но устанавливаю свойство SecureString в ViewModel только после того, как нажата кнопка входа в систему с использованием скрытого кода. После установки пароля SecureString я хочу проверить.

Сейчас я пишу LoginBox, но у меня еще нет полностью проработанной модели. Как мне сохранить пароль в SQL Server? Могу ли я просто записать содержимое SecureString в SQL, а затем попытаться сравнить его, когда пользователь пытается войти в систему?


person John the Ripper    schedule 05.09.2011    source источник
comment
Что-то вроде этого? stackoverflow.com/ questions / 1191112 /   -  person CodeCaster    schedule 05.09.2011
comment
Это помогает с хешированием пароля, но в каком типе данных я его храню и как мне работать с SecureStrings, чтобы потом проводить сравнение?   -  person John the Ripper    schedule 05.09.2011
comment
Datatype, вероятно, должен быть просто varchar, а SecureString - это не волшебное решение для сохранения пароля, это просто строка, в некоторой степени защищенная от атак, вы не можете прочитать ее содержимое из памяти извне вашей программы, но это все.   -  person CodeCaster    schedule 05.09.2011
comment
Спасибо, думаю, у меня это сработает.   -  person John the Ripper    schedule 05.09.2011


Ответы (2)


НИКОГДА не храните пароль - даже не зашифрованный ...

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

Для этого существуют стандарты:

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

Вы можете сохранить результат либо как VARBINARY напрямую, либо как VARCHAR после Base64- или HEX-кодирования байтов ... вам нужно будет сохранить соль вместе с ней (что не представляет опасности для безопасности, если каждый пароль имеет свой собственный криптографический безопасная сгенерированная случайная соль).

person Yahia    schedule 05.09.2011
comment
Вот что я имел в виду. Мне просто было интересно, как это сделать. Я думаю, что то, что CodeCaster поставил в комментариях, сработает. - person John the Ripper; 05.09.2011
comment
Как хранить соль? Какой тип данных? - person John the Ripper; 05.09.2011
comment
соль - это просто byte[] и может быть сохранена как VARBINARY или как VARCHAR после Base64- или HEX-кодирования ... - person Yahia; 05.09.2011
comment
Спасибо, это вместе с информацией от CodeCaster поможет. - person John the Ripper; 05.09.2011
comment
@Yahia Во многих случаях это просто невозможно. Например, когда вы подключаетесь к общему файловому ресурсу с помощью WNetUseConnection, вы не можете указать хэш вместо пароля, вы должны передать его как обычный текст. Как же тогда мне сохранить пароль к файловому ресурсу в базе данных? - person Alex Zhukovskiy; 26.08.2016
comment
@AlexZhukovskiy Всегда есть некоторые исключения, но даже тогда вам нужно применить максимально возможную безопасность, у соответствующего пользователя должно быть как можно меньше прав ... пароль должен быть сгенерирован безопасным способом и т. Д. - person Yahia; 01.09.2016

На моем предыдущем концерте мы сохранили пароль в виде хешированного / зашифрованного / соленого значения (в то время с использованием MD5) как VARBINARY(32). Чтобы позже сравнить пароль, вместо того, чтобы пытаться его расшифровать, мы сравнили бы зашифрованное + солёное значение, которое мы сохранили, с зашифрованным + солёным значением пытаемого пароля. Если они совпали, они вошли, если они не совпали, они не вошли.

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

CREATE TABLE dbo.Users
(
    UserID INT IDENTITY(1,1) PRIMARY KEY,
    Username NVARCHAR(255) NOT NULL UNIQUE,
    PasswordHash VARBINARY(32) NOT NULL
);

Процедура создания пользователя (без обработки ошибок или предотвращения дублирования, только псевдо).

CREATE PROCEDURE dbo.User_Create
    @Username NVARCHAR(255),
    @Password NVARCHAR(16)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @salt NVARCHAR(16) = '$w0rdf1$h';

    INSERT dbo.Users(Username, Password)
        SELECT @Username, 
          CONVERT(VARBINARY(32), HASHBYTES('MD5', @Password + @Salt));
END
GO

Теперь процедура аутентификации пользователя.

CREATE PROCEDURE dbo.User_Authenticate
    @Username NVARCHAR(255),
    @Password NVARCHAR(16)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @salt NVARCHAR(16) = '$w0rdf1$h';

    IF EXISTS 
    (
      SELECT 1 FROM dbo.Users
        WHERE Username = @Username AND 
        PasswordHash = CONVERT(VARBINARY(32), HASHBYTES('MD5', @Password + @salt))
    )
    BEGIN
        PRINT 'Please, come on in!';
    END
    ELSE
    BEGIN
        PRINT 'You can keep knocking but you cannot come in.';
    END
END
GO

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

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

person Aaron Bertrand    schedule 05.09.2011
comment
это работает, но я бы действительно рекомендовал использовать более продвинутый хэш с несколькими раундами и т. д., например PBKDF2 или bcrypt ... - person Yahia; 05.09.2011
comment
Да, в своем ответе я указал, что в то время мы использовали MD5 - я имел в виду, что это означает, что есть определенно более безопасные способы сделать это. Обратите внимание, что мы, скорее всего, говорим о хранении паролей для сайта форума или базы данных рецептов или чего-то еще, а не о ЦРУ. - person Aaron Bertrand; 05.09.2011
comment
Я понимаю это, но даже скромно известный сайт может иметь некоторый ущерб репутации, если база данных user / pw взломана, особенно. поскольку многие пользователи используют один и тот же PW для разных сайтов :-( - person Yahia; 05.09.2011
comment
СНОВА, это был просто тривиальный пример, демонстрирующий основную методологию, не предназначенный как директиву это наиболее безопасный способ. - person Aaron Bertrand; 05.09.2011