0

さて、良いというのは主観的なものですが、タイトルにぴったりです。私が本当に知りたいのは、このパスワード管理/認証戦略に明らかな欠陥があるかどうかです. パフォーマンスも気になります。認証に PBKDF2 を使用しようとしていますが、それが RESTful Web サービスに適しているかどうかはよくわかりません。この質問のいくつかの部分があちこちで答えられているのを見つけることができますが、上から下までの包括的な答えを見つけたことはありません。これが私の戦略のすべてです。

バックグラウンド:

  • Service は C# の ASP.NET Web Api プロジェクトです
  • バックエンドは MS SQL サーバー
  • 資格情報は、基本認証を使用して HTTPS 経由で送信されます。つまり、「承認: 基本ユーザー名:パスワード」です。
  • API は Andriod アプリ、iOS アプリ、Web サイトで使用されます

まず、バックエンド:

create table [dbo].[User] (
    [Name] varchar(50) collate SQL_Latin1_General_CP1_CI_AI not NULL primary key clustered,
    [Password] varchar(28) collate SQL_Latin1_General_CP1_CS_AS not NULL,
    [Salt] varchar(28) not NULL)

ユーザーを作成するためのストアド プロシージャ:

create procedure [dbo].[User_Create] 
    @Name varchar(50),
    @Salt varchar(50),
    @Password varchar(50)
as 
    insert into [dbo].[User]([Name], [Salt], [Password])
    values(@Name, @Salt, @Password)

ユーザーを取得するためのストアド プロシージャ:

create procedure [dbo].[User_Get] 
    @Name varchar(50)
as 
    select *
    from [dbo].[User]
    where [Name] = @Name

バックエンドでは、名前、パスワード、およびソルトに選択されたデータ型が適切かどうかに興味があります。

これは、新しいユーザーを作成してバックエンドに永続化するコードです。これはおそらく、セキュリティとパフォーマンスの両方の観点から、私が最も懸念していることです。

public void CreateUser(string username, string password)
{
    int hashLength = 20;
    int saltLength = 20;
    int hashIterations = 1000;
    using(SqlConnection connection = new SqlConnection(this._ConnectionString))
    using (SqlCommand command = new SqlCommand("[dbo].[User_Create]"))
    {
        Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, saltLength, hashIterations);
        string salt = Convert.ToBase64String(pbkdf2.Salt);
        string hashPassword = Convert.ToBase64String(pbkdf2.GetBytes(hashLength));

        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.AddWithValue("@Name", username);
        command.Parameters.AddWithValue("@Salt", salt);
        command.Parameters.AddWithValue("@Password", hashPassword);
        connection.Open();
        command.ExecuteNonQuery();
    }
}

そして、ここにユーザーを認証するためのコードがあります。これは基本的に、ストアド プロシージャValidatePasswordを実行し、PBKDF2 を実行するための呼び出しを行い、Userプリンシパルを設定する Web API メッセージ ハンドラーにオブジェクトを返します (ロールはまだ実装されていません)。

public User AuthenticateUser(string username, string password)
{
    using (SqlConnection connection = new SqlConnection(this._ConnectionString))
    using (SqlCommand command = new SqlCommand("[dbo].[User_Get]"))
    {
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.AddWithValue("@Name", username);
        command.Connection = connection;

        connection.Open();
        using (SqlDataReader reader = command.ExecuteReader())
        {
            if (reader.Read() && this.ValidatePassword(password, reader["Salt"].ToString(), reader["Password"].ToString()))
            {
                return new User()
                    {
                        Name = username,
                        CustomerId = reader["CustomerId"].ToString()
                    };
            }
            else
            {
                return null;
            }
        }
    }
}

ValidatePassword上記のコードがパスワードを検証するために依存している は次のとおりです (明らかでない場合に備えて) 。また、これが正しいことを確認したいと思います。

private bool ValidatePassword(string password, string salt, string hashedPassword)
{
    int hashLength = 20;
    int hashIterations = 1000;
    byte[] saltBytes = Convert.FromBase64String(salt);
    Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, saltBytes, hashIterations);

    byte[] hashBytes = pbkdf2.GetBytes(hashLength);
    string hash = Convert.ToBase64String(hashBytes);

    // Security Decisions For String Comparisons
    //
    // If you are making a security decision (such as whether to allow access to a system resource) based on the 
    // result of a string comparison or a case change, you should not use the invariant culture. Instead, you 
    // should perform a case-sensitive or case-insensitive ordinal comparison by calling a method that includes 
    // a StringComparison parameter and supplying either StringComparison.Ordinal or 
    // StringComparison.OrdinalIgnoreCase as an argument. Code that performs culture-sensitive string operations 
    // can cause security vulnerabilities if the current culture is changed or if the culture on the computer 
    // that is running the code differs from the culture that is used to test the code. In contrast, an ordinal 
    // comparison depends solely on the binary value of the compared characters.
    //
    // Source: http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.invariantculture.aspx

    return hash.Equals(hashedPassword, StringComparison.Ordinal);
}
4

1 に答える 1

0

非常に独断的な答え。

(完全に無料で十分にテストされた) 既製の実装がたくさんあるのに、なぜ自分でこれを行うのでしょうか?

必ず練習としてこれを行ってください(これは魅力的な分野です)が、タイミング攻撃は氷山の一角にすぎません.

セキュリティの第 1 のルールは、暗号化に関連することを自分で行っている場合、ほとんど何もしないようにする必要がある領域に足を踏み入れている可能性があるということです。たとえば、owin またはオープン認証プロバイダーまたは Active Directory を使用します。しかし、武器から離れてください。

自分でやって大量のデータを漏らす次のマペットにならないでください。

フェデレーション セキュリティ、saml トークン、および sts プロバイダーをご覧ください

于 2016-06-14T16:38:45.830 に答える