0

我的 ASP.NET MVC Web 应用程序代表用户创建了一些数据,并将其存储在 SQL 数据库中的一条带有数字主键的记录中。我通过主键访问数据。

我希望经过身份验证的用户能够导航到包含(数字)主键的 URL,但我不想公开实际的键值。所以,在我看来,我想用一个密码加密数字密钥(使用对称加密算法),密码由我的代码中的一个字符串加上登录用户的 UserID 组成。生成的 URL 类似于:https://foo.com/123abc,其中“123abc”是加密的密钥值(从字节转换为字符)。理论上(对于我的初学者来说)这个加密值,即使被恶意方获取,也不会有用,除非该方可以使用用户的凭据登录到我的网站。

问题 1:这是做这类事情的正确方法吗?
问题 2:知道这些东西的人能否指出我可以用于此目的的简单对称加密 API。

4

3 回答 3

2

您可以向 SQL 表添加一列并将其类型设置为 uniqueidentifier 并将其值设置为 NEWID() ,然后将其显示给用户,而不是使用 PK,此解决方案的开销最少,同时仍提供看似随机的系列,您可以稍后将其绑定到该用户。

ALTER TABLE foo ADD foobar uniqueIdentifier default newid();

http://msdn.microsoft.com/en-us/library/ms187942.aspx

于 2013-03-12T17:26:44.450 回答
1

整数的对称加密将非常容易破解,您甚至不必费心。现在,您可以通过 Base64 编码或类似的方式对其进行加盐或混淆,但这仍然毫无意义。数据库主键不是敏感数据。没有访问数据库是没有意义的,如果他们可以访问数据库,那么通过他们的 id 查找特定用户绝对是你最不关心的问题。即使是对称加密也会为您的应用程序增加大量开销,因为这根本不是必需的。

如果您真的不想公开 PK,请使用 URL 中的用户名之类的其他内容,然后通过该名称查找用户。

于 2013-03-12T17:19:07.593 回答
0

你可以这样做,当然。

将盐存储在您的会话中,每次随机生成一个或使用会话 ID 作为盐。

以下是两种可以用盐加密/解密字符串值的方法。您可以使用盐代替初始向量。

public static string Encrypt(string PlainText, string Password, string Salt,
 string HashAlgorithm = "SHA1", int PasswordIterations = 16, string InitialVector = "Initial Vector", int KeySize = 256)
{  
    byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
    byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
    byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
    PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
    byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
    RijndaelManaged SymmetricKey = new RijndaelManaged();
    SymmetricKey.Mode = CipherMode.CBC;

    ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);

    MemoryStream MemStream = new MemoryStream();
    CryptoStream cryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
    cryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
    cryptoStream.FlushFinalBlock();
    byte[] CipherTextBytes = MemStream.ToArray();

    MemStream.Close();
    cryptoStream.Close();
    Encryptor.Dispose();
    Encryptor = null;

    return Convert.ToBase64String(CipherTextBytes);
}


public static string Decrypt(string CipherText, string Password, string Salt,
    string HashAlgorithm = "SHA1", int PasswordIterations = 16, string InitialVector = "Initial Vector", int KeySize = 256)
{ 
    byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
    byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
    byte[] CipherTextBytes = Convert.FromBase64String(CipherText);
    PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
    byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
    RijndaelManaged SymmetricKey = new RijndaelManaged();
    SymmetricKey.Mode = CipherMode.CBC;

    ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes);
    MemoryStream MemStream = new MemoryStream(CipherTextBytes);
    CryptoStream cryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read);
    byte[] PlainTextBytes = new byte[CipherTextBytes.Length];

    int ByteCount = cryptoStream.Read(PlainTextBytes, 0, PlainTextBytes.Length);

    MemStream.Close();
    cryptoStream.Close();
    Decryptor.Dispose();
    Decryptor = null;

    return Encoding.UTF8.GetString(PlainTextBytes, 0, ByteCount);
}
于 2013-03-12T17:16:08.453 回答