我已经看了所有的地方,我似乎无法得到一个完整的答案.因此,如果答案已经存在于stackoverflow上,那么我提前道歉.
我想要一个独特的随机ID,以便我网站中的用户无法猜出下一个号码,只是跳到其他人的信息.我打算坚持使用主键的递增ID,但也要在DB中为该行存储随机且唯一的ID(一种哈希)并在其上放置一个索引.
从我的搜索中我意识到我想避免碰撞,我已经读过一些关于SHA1的提及.
我的基本要求是
小于GUID的东西.(在URL中看起来很可怕)
必须是独特的
避免碰撞
不是很长的不可读的奇怪字符列表.
我正在寻找的一个例子是www.somesite.com/page.aspx?id=AF78FEB
我不确定我是应该在数据库中实现这个(我使用的是SQL Server 2005)还是在代码中(我使用的是C#ASP.Net)
编辑:
从我所做的所有阅读中,我意识到这是通过默默无闻的安全.我打算对访问页面进行适当的授权和身份验证.我将使用.Net的身份验证和授权框架.但是,一旦合法用户登录并正在访问一个充满属于他的项目的链接(但动态创建的页面).例如,链接可能是www.site.com/page.aspx?item_id=123.什么阻止他点击该链接,然后更改上面的URL以访问不属于他的www.site.com/page.aspx?item_id=456?我知道一些像Struts这样的Java技术(我有待纠正)会在会话中存储所有内容并以某种方式解决这个问题,但我不知道如何做到这一点.
Raymond Chen有一篇很好的文章说明为什么你不应该使用"半指导",并提供一个合适的解决方案,在这里产生你自己的"不完全但不够好"的类型值:
GUID是全局唯一的,但GUID的子字符串不是
他的策略(没有具体的实施)是基于:
用于编码计算机编号的四位,
时间戳为56位,和
四位作为无统一者.
由于集群中的计算机数量有限,我们可以减少使计算机唯一的位数,并且我们可以通过假设程序将在200年后不再使用来减少时间戳中的位数.
假设时钟不会偏离歪斜超过一个小时(比如说)并且时钟每小时不会复位超过16次,那么你就可以摆脱四位统一.
更新(2017年2月4日):
Walter Stabosz在原始代码中发现了一个错误.经过调查发现了更多的错误,然而,我自己对代码进行了大量的测试和重新编写,原作者(CraigTP)现在已经修复了所有这些问题.我已使用正确的工作版本更新了此处的代码,您还可以在此处下载Visual Studio 2015解决方案,其中包含"短代码"生成代码和相当全面的测试套件以证明其正确性.
我过去使用的一个有趣的机制是内部只使用递增的整数/长,但要将整数"映射"为字母数字"代码".
Console.WriteLine($"1371 as a shortcode is: {ShortCodes.LongToShortCode(1371)}"); Console.WriteLine($"12345 as a shortcode is: {ShortCodes.LongToShortCode(12345)}"); Console.WriteLine($"7422822196733609484 as a shortcode is: {ShortCodes.LongToShortCode(7422822196733609484)}"); Console.WriteLine($"abc as a long is: {ShortCodes.ShortCodeToLong("abc")}"); Console.WriteLine($"ir6 as a long is: {ShortCodes.ShortCodeToLong("ir6")}"); Console.WriteLine($"atnhb4evqqcyx as a long is: {ShortCodes.ShortCodeToLong("atnhb4evqqcyx")}"); // PLh7lX5fsEKqLgMrI9zCIA Console.WriteLine(GuidToShortGuid( Guid.Parse("957bb83c-5f7e-42b0-aa2e-032b23dcc220") ) );码
下面的代码显示了一个简单的类,它将long更改为"代码"(并再次返回!):
public static class ShortCodes { // You may change the "shortcode_Keyspace" variable to contain as many or as few characters as you // please. The more characters that are included in the "shortcode_Keyspace" constant, the shorter // the codes you can produce for a given long. private static string shortcodeKeyspace = "abcdefghijklmnopqrstuvwxyz0123456789"; public static string LongToShortCode(long number) { // Guard clause. If passed 0 as input // we always return empty string. if (number == 0) { return string.Empty; } var keyspaceLength = shortcodeKeyspace.Length; var shortcodeResult = ""; var numberToEncode = number; var i = 0; do { i++; var characterValue = numberToEncode % keyspaceLength == 0 ? keyspaceLength : numberToEncode % keyspaceLength; var indexer = (int) characterValue - 1; shortcodeResult = shortcodeKeyspace[indexer] + shortcodeResult; numberToEncode = ((numberToEncode - characterValue) / keyspaceLength); } while (numberToEncode != 0); return shortcodeResult; } public static long ShortCodeToLong(string shortcode) { var keyspaceLength = shortcodeKeyspace.Length; long shortcodeResult = 0; var shortcodeLength = shortcode.Length; var codeToDecode = shortcode; foreach (var character in codeToDecode) { shortcodeLength--; var codeChar = character; var codeCharIndex = shortcodeKeyspace.IndexOf(codeChar); if (codeCharIndex < 0) { // The character is not part of the keyspace and so entire shortcode is invalid. return 0; } try { checked { shortcodeResult += (codeCharIndex + 1) * (long) (Math.Pow(keyspaceLength, shortcodeLength)); } } catch(OverflowException) { // We've overflowed the maximum size for a long (possibly the shortcode is invalid or too long). return 0; } } return shortcodeResult; } }
}
这基本上是您自己的baseX编号系统(其中X是shortCode_Keyspace常量中唯一字符的数量).
为了使事情变得不可预测,在1或0以外的其他内容(即从184723开始)开始内部递增编号,并且还改变shortCode_Keyspace常量中字符的顺序(即使用字母AZ和数字0-9,但是scamble它们在常量字符串中的顺序.这将有助于使每个代码有些不可预测.
如果您使用它来"保护"任何东西,这仍然是默默无闻的安全性,并且如果给定用户可以观察到足够的这些生成的代码,他们可以预测给定长度的相关代码.这种"安全性"(如果你可以称之为)就是shortCode_Keyspace常量被扰乱,并保持秘密.
编辑:如果你只想生成一个GUID,并将其转换为仍然是唯一的,但包含少量字符的东西,这个小函数将起到作用:
public static string GuidToShortGuid(Guid gooid) { string encoded = Convert.ToBase64String(gooid.ToByteArray()); encoded = encoded.Replace("/", "_").Replace("+", "-"); return encoded.Substring(0, 22); }
如果您不希望其他用户查看人员信息,为什么不保护您使用该ID的页面?
如果你这样做,那么使用递增Id就没关系.
[响应编辑]
您应该将查询字符串视为"恶意输入".您需要以编程方式检查是否允许经过身份验证的用户查看所请求的项目.
if( !item456.BelongsTo(user123) ) { // Either show them one of their items or a show an error message. }