【问题标题】:ASP.net authenticationASP.net 身份验证
【发布时间】:2012-06-24 12:00:00
【问题描述】:

我是一名 CS 专业的,我刚刚完成了 ASP.net 网站的设计,对于该网站,我需要一个登录身份验证系统...我不想使用 SQLMembershipProvider,因为我真的很想学习如何制作一个靠我自己...无论如何,这就是我想出的,我想知道是否有人可以给我一些反馈、提示或建议。

提前致谢

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Security.Cryptography;

/// <summary>
/// Summary description for PwEncrypt
/// </summary>
public class PwEncrypt
{
    public const int DefaultSaltSize = 5;

    private static string CreateSalt()
    {
        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
        byte[] buffer = new byte[DefaultSaltSize];
        rng.GetBytes(buffer);
        return Convert.ToBase64String(buffer);
    }

    public static string CreateHash(string password, out string salt)
    {
        salt = CreateSalt();
        string saltAndPassword = String.Concat(password, salt);
        string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword, "SHA1");
        hashedPassword = string.Concat(hashedPassword, salt);
        return hashedPassword;
    }
       public static string CreateHashAndGetSalt(string password, string salt)
    {

        string saltAndPassword = String.Concat(password, salt);
        string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword, "SHA1");
        hashedPassword = string.Concat(hashedPassword, salt);
        return hashedPassword;
    }

    public static bool comparePassword(string insertedPassword, string incUserName, out string newEncryptedPassword, out string originalPassword)
    {
        databaseInteraction DBI = new databaseInteraction();
        string actualPassword ="";
        string salt = "";


        DBI.getSaltandPassword(incUserName, out salt, out actualPassword);
        string hashedIncPassword = PwEncrypt.CreateHashAndGetSalt(insertedPassword, salt);
       // hashedIncPassword = string.Concat(hashedIncPassword, salt);     
        newEncryptedPassword = hashedIncPassword;
        originalPassword = actualPassword;
        if (newEncryptedPassword == originalPassword)
        {

            return true;
        }

        else { return false; }

    }

【问题讨论】:

  • 如果要创建自定义会员提供者,首先必须从 MemberShipProvider 继承。如果你谷歌一下,这是相当有据可查的。
  • 除非您真的别无选择,否则不要尝试推出自己的自定义身份验证和会话管理方案或构建自己的控件。我只是想做,没有资格。有趣的阅​​读:troyhunt.com/2010/07/…
  • @ChristopheGeers 没错...自己做很麻烦,内置的 MembershipProviders 工作得很好,他们只是必须配置才能这样做。
  • 我知道对于生产站点来说确实是这样,但是出于教育目的,您是否真的相信只知道如何通过预先构建的系统来实现身份验证系统是一件好事?因为我清楚地提到了 MembershipProviders,所以我清楚地知道它是什么,并且使用起来很舒服,但并不是每种语言都有它......我只是在寻求有关实施自定义系统的建议或技巧,以实现 OUTSIDE asp.net 之外的教育.至于自己动手做起来很麻烦,只要以后可能有一些好处,这不是一个真正的问题。
  • @user1474120 - 除了你的实现安全是一场噩梦。您的密码哈希不确定。

标签: c# asp.net .net salt


【解决方案1】:

假设我们有一个这样的帐户表

然后您可以创建一些返回帐户对象的帮助程序类

private static Account GetByName(string accountName, bool activatedOnly = false)
{
    using (var context = new DBEntities())
    {
        return context.Accounts.FirstOrDefault(s => 
            s.AccountName == accountName &&
            s.IsApproved == activatedOnly);
    }
}

public static Account Get(string accountName, string password)
{
    var account = GetByName(accountName, true);
    if (account != null)
        if (!Cryptographer.IsValidPassword(password, 
                                           account.PasswordSalt, 
                                           account.PasswordKey))
            return null;
    return account;
}

我正在使用EntityFramework,但这并不重要。主要思想是表明您不需要获取整个帐户列表(特别是如果您有大量用户列表)。
我的Cryptographer 类看起来像

public class Cryptographer
{
    private const int keyByteLength = 20;
    public static void Encrypt(string password, 
                               out byte[] salt,
                               out byte[] key)
    {
        using (var deriveBytes = new Rfc2898DeriveBytes(password, 
                                                        keyByteLength))
        {
            salt = deriveBytes.Salt;
            key = deriveBytes.GetBytes(keyByteLength);  
        }
    }
    public static bool IsValidPassword(string password, 
                                       byte[] salt, 
                                       byte[] key)
    {
        using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
        {
            byte[] newKey = deriveBytes.GetBytes(keyByteLength);  
            return newKey.SequenceEqual(key);
        }
    }
}

当然,您可以实现自己的算法。

【讨论】:

  • 谢谢,这正是我正在寻找的反馈类型...关于使用 Rfc2898DeriveBytes 与 RNGCryptoServiceProvider 和 FormsAuthentication.HashPasswordForStoringInConfigFile...哪个具有更强的哈希算法?至于获取完整的用户列表,其他方法实际上处理让特定用户检查密码,incUserID 将密码检查限制为只有那个,所以我的意思是它确实选择了整个数据库,只有 1 个返回但是EntityFramework 会做同样的事情,不是吗?
  • @user1474120 - 您将遇到的主要问题是编写安全的 SQL 查询。根据您自己的代码,您不使用安全密码架构是一个问题,但以安全方式获取用户和密码是一个更大的问题。
  • @user1474120,看看this
  • “只有 1 个回报”。确切地。您只需要从数据库中获取一条记录(从 Accounts 中选择前 1 *,其中 AccountName = @accountName)。
  • 如果我错了,请纠正我,但如果您对用户名有唯一约束,您是否不需要 select top 1?或者它是我不知道的安全问题的一部分? (这完全有可能)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 2010-09-24
  • 2011-06-16
  • 2011-08-19
  • 1970-01-01
相关资源
最近更新 更多