Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我的RESTAPI密码/身份验证策略好吗?_C#_Sql_Security_Rest_Asp.net Web Api - Fatal编程技术网

C# 我的RESTAPI密码/身份验证策略好吗?

C# 我的RESTAPI密码/身份验证策略好吗?,c#,sql,security,rest,asp.net-web-api,C#,Sql,Security,Rest,Asp.net Web Api,好吧,好是主观的,但它更适合标题。我真正想知道的是,这种密码管理/身份验证策略是否存在明显的缺陷。我对表演也很好奇。我试图使用PBKDF2进行身份验证,但我不确定这对于RESTful web服务是否是一个好主意。我可以在这里和那里找到这个问题的答案,但我从来没有找到一个全面的自上而下的答案。这就是我的全部策略 背景: 服务是C语言中的ASP.NETWebAPI项目# 后端是MS SQL server 凭据使用基本身份验证通过HTTPS发送,即“授权:基本用户名:密码” API将由Andriod

好吧,好是主观的,但它更适合标题。我真正想知道的是,这种密码管理/身份验证策略是否存在明显的缺陷。我对表演也很好奇。我试图使用PBKDF2进行身份验证,但我不确定这对于RESTful web服务是否是一个好主意。我可以在这里和那里找到这个问题的答案,但我从来没有找到一个全面的自上而下的答案。这就是我的全部策略

背景:

  • 服务是C语言中的ASP.NETWebAPI项目#
  • 后端是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
以及获取用户的存储过程:

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
对于后端,我很好奇为名称、密码和salt选择的数据类型是否合适

这是创建新用户并将其持久化到后端的代码。这可能是我最关心的,无论是从安全角度还是从性能角度

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消息处理程序(角色尚未实现):

下面是
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);
}

非常固执己见的回答

当有很多现成的(如完全免费和经过良好测试的)实现时,为什么要自己这么做

无论如何,这只是一个练习(在我看来,这是一个迷人的领域),但定时攻击只是冰山一角

安全的第一条规则是,如果您自己在做任何涉及加密的事情,那么您可能会冒险进入一个您应该确保很少做的领域。例如,使用owin或开放身份验证提供程序或active directory。但是离武器远点

不要成为下一个自己泄露大量数据的傀儡


查看联邦安全性、saml令牌和sts提供程序

您可能还希望使用恒定时间字符串比较来防止定时攻击。我假设您知道asp.net有自己的成员结构?(虽然我认为你并不在乎,但你有自己的系统)不要假设任何事情,我对安全非常陌生。话虽如此,我的研究中确实出现了会员提供商。有些人似乎很喜欢他们,但似乎还有不少人对他们印象不深。最后,我想,如果我自己花时间去理解这个主题,而不是使用将它抽象出来的技术,那会更好。@Blender:恒定时间字符串比较很有趣。那么多信息真的可以从字符串比较中收集吗?我认为API调用中延迟的可变性质加上PBKDF2函数的时间拉伸会使准确测量字符串比较的时间变得困难。无论如何,这将如何在C#中实现?将每个字符串转换为字节数组,然后对每个字符串中的字节进行“异或”运算,并将其相加以确保它们为0。
Rfc2898DeriveBytes
实现
IDisposable
接口(通过
DeriveBytes
祖先)因此,应该使用语句将其包装在
中,以便正确地进行确定性处理。