从ASP解密加密的密码.. NET成员使用RijndaelManaged

本文关键字:成员 RijndaelManaged NET 密码 ASP 解密 加密 | 更新日期: 2023-09-27 18:19:06

底线是创建一个自定义FTP身份验证提供程序。为了做到这一点,必须从IFtpAuthenticationProvider接口继承,然后在GAC中注册该汇编。之后,程序集需要在IIS的FTP设置中注册。

为了实现这一点,我必须使用数据库,该数据库从我们之前开发的自定义会员资格和角色提供程序中保存我的用户信息。所以,这意味着我必须使用本地类库app.config文件并使用ConfigurationManager.OpenMappedExeConfiguration()读取它。我从那里读取连接字符串,我甚至能够动态地将其提供给Linq-To-Sql类。没问题。

接下来,我尝试创建一个继承SqlMembershipProvider的类,这样我就可以使用它自己的系统来解密用户的密码。但是,问题是它必须从配置中读取machineKey值。您可以为SqlMembershipProvider提供自定义配置的唯一方法是通过它的Initialize方法(无论如何,我们不打算在代码中使用它)。但无论如何,我尝试了,但失败了。我已经能够为它提供自定义会员设置,但不能提供machineKey设置。

所以,我决定激进一点。我说:我有machineKeydecryptionKey,所以我将尝试手动解密密码。

到目前为止,我尝试使用RijndaelManaged:
    private string UnEncodePassword(string encodedPassword, string secretKey)
    {
        string password = encodedPassword;
        var keyBytes = new byte[16];
        var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
        Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));
        RijndaelManaged rm = new RijndaelManaged
        {
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
            KeySize = 128,
            BlockSize = 128,
            Key = keyBytes,
            IV = keyBytes
        };
        var encryptedBytes = Convert.FromBase64String(encodedPassword);
        password = Encoding.UTF8.GetString(Decrypt(encryptedBytes, rm));
        return password;
    }

我有点意识到我在这里是空白处,因为我甚至不确定使用了什么样的填充,最重要的是,即使我可以,我也没有击中正确的IV。到目前为止,我所做的最好的是得到一些垃圾响应,如:' 21l ' <' ' (' 't ' '].

我需要一些指针。甚至从另一个角度来解决这个问题的建议也是受欢迎的。

编辑:

让事情更清楚一点。我不是想破解密码什么的。我有密码和解密密钥等等。我只是想找到一种方法来加密/解密它,这样我就可以进行用户验证。
我完全意识到加密/解密密码并不是最好的方法,但是这样做是有原因的。

从ASP解密加密的密码.. NET成员使用RijndaelManaged

您不应该解密密码。你应该比较密码哈希值。

密码不应以可逆加密方式存储。密码应该以哈希的形式存储(不是MD5,它太弱了)。

关于你上面的评论,你不需要解密密码来比较它们。要比较的是哈希值,而不是原始值。系统应该无法获得密码的原始文本。使用内置的ASP。. NET成员资格提供程序正确地将密码存储为散列。这可能就是你无法解密它们的原因,它们本来就是不可能解密的。

Edit:关于您使用passwordFormat="Encrypted"作为SQL成员资格提供程序的事实。有了这个事实,您可以用相同的格式加密密码,使用相同的填充、cipherMode和IV(您需要从SQL数据库中查询),然后只比较加密的密码值。这可能是不必要的工作。实际上,您只需要在代码中使用用户名/密码组合调用Membership的登录函数,并验证它是否成功。您需要确保机器密钥和相关部件在两个系统中都匹配,否则您将无法成功。

你真的想计划转移到散列密码,然而,存储加密密码而不是散列密码几乎是没有意义的。它只比将它们存储为纯文本稍微好一点。

您通常不需要存储加密的密码,除非您想要一种允许用户看到其当前密码的密码恢复形式。这通常是一个坏主意,它确实需要更多的工作。

按照惯例,您应该在数据库中只存储密码的腌制散列。散列是一种单向操作(因此,如果您的数据库被泄露,没有人可以解密信息以找出密码)。

要检测用户的密码是否与您存储的密码匹配,您只需要使用与在数据库中散列值相同的盐来散列他们的密码。如果两个哈希值匹配,则用户提供了正确的密码。

认证算法应该看起来像这样:

  1. 获取用于散列的盐(可以使用每个用户唯一的盐,也可以使用全局盐)
  2. 生成用户密码的哈希值
  3. 将哈希密码与指定用户名存储在数据库中的密码进行比较(如果使用LINQ-to-SQL,一个简单的Any语句可以做到这一点)。
  4. 返回成功或失败的值。

我同意其他人的观点,散列密码通常比加密密码更安全。

但是因为你不能选择为什么你必须使用MembershipProvider中的EncryptionDecription方法(顺便说一句,我甚至认为这是不可能的)。

为什么不创建自己的加密方法,并在web应用程序和类库中使用它们呢?