簡體   English   中英

我的REST API密碼/身份驗證策略是否正確?

[英]Is my password/authentication strategy for a REST API good?

好的,好的是主觀的,但標題更合適。 我真正想知道的是,此密碼管理/身份驗證策略中是否存在任何明顯的缺陷。 我也對性能感到好奇。 我正在嘗試使用PBKDF2進行身份驗證,但我不確定這是否是RESTful Web服務的好主意。 我可以在這里到那里找到該問題的某些部分,但是我從未找到一個完整的自上而下的答案。 這就是我的整個策略。

背景:

  • 服務是C#中的ASP.NET Web Api項目
  • 后端是MS SQL Server
  • 使用基本身份驗證通過HTTPS發送憑據,即“授權:基本用戶名:密碼”
  • API將由Andriod應用程序,iOS應用程序和網站使用

首先,后端:

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消息處理程序,該處理程序設置Principal(角色尚未實現):

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);
}

高度自以為是的答案。

當有很多現成的實現(如完全免費且經過良好測試的實現)時,為什么要自己做呢?

一定要把它當作練習(這是一個令人着迷的區域imo),但定時攻擊只是冰山一角。

安全性的第一條規則是,如果您自己進行涉及加密的任何事情,您可能正在冒險進入一個應該確保很少進行加密的區域。例如,使用owin或開放式身份驗證提供程序或活動目錄。 但是要遠離武器。

不要成為自己動手泄漏大量數據的下一個木偶。

看一下聯合安全,saml令牌和sts提供程序

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM