我的ASP.NET MVC Web应用程序代表用户创建一些数据,并将其存储在具有数字主键的记录中的SQL数据库中。我通过主键访问数据。
我希望经过身份验证的用户能够导航到包含(数字)主键的URL,但我不想公开实际的键值。因此,在我看来,我想要加密数字密钥(使用对称加密算法),密码由我的代码中加入的字符串和登录用户的UserID组成。结果URL看起来像:https://foo.com/123abc
,其中“123abc”是加密的键值(从字节转换为字符)。理论上(对我的初学者大脑)这个加密的值,即使被恶意方获取,也没有用,除非该方可以使用用户的凭据登录我的网站。
问题1:这是做这种事的正确方法,而且 问题2:知道这些内容的人能否指出我可以用于此目的的简单对称加密API。
答案 0 :(得分:2)
您可以在SQL表中添加一个列并将其类型设置为uniqueidentifier,并将其值设置为NEWID()然后将其显示给用户,而不是使用PK,此解决方案将具有最少的开销,而仍然提供一个看似随机的系列,你可以稍后再绑定给那个用户。
ALTER TABLE foo ADD foobar uniqueIdentifier default newid();
答案 1 :(得分:1)
整数的对称加密会非常容易破解你甚至可能都不会打扰。现在,你可以通过Base64编码或者类似的东西对它进行加盐或混淆,但是,这仍然是毫无意义的。数据库主键不是敏感数据。没有访问数据库就没有意义,如果他们可以访问数据库,那么通过他们的id查找特定用户绝对是你的问题。即使是对称加密也会给你的应用程序带来很大的开销,而这些开销根本就没有必要。
如果你真的不想暴露PK,那么在URL中使用其他类似用户名的东西,然后按用户查找用户。
答案 2 :(得分:0)
你可以这样做,当然。
将salt存储在会话中,每次随机生成一个或使用会话ID作为salt。
以下是两种可以使用salt加密/解密字符串值的方法。您可以使用盐代替初始矢量。
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);
}