我应该掩盖主键值吗?

时间:2009-12-13 05:57:17

标签: language-agnostic web-applications primary-key

我正在构建一个前端是高度专业化的搜索引擎的Web应用程序。搜索在主URL处理,当用户单击搜索结果以进行更详细的显示时,用户将被传递到子目录。这个切换是作为GET请求完成的,主键在查询字符串中传递。我似乎记得曾经读到某个地方,向用户公开主键并不是一个好主意,所以我决定实施可逆加密。

我开始怀疑自己是不是只是偏执狂。可逆加密(base64)可能很容易被任何关心尝试的人破坏,使URL变得非常丑陋,并且也比其他人更长。我应该放弃加密并以明文形式发送主键吗?

10 个答案:

答案 0 :(得分:22)

你所做的基本上是混淆。可逆加密(并且base64实际上不算作加密)主键仍然是主键。

您所阅读的内容归结为:您通常不希望主键在系统外具有任何意义。这称为技术主键,而不是自然主键。这就是为什么您可以使用患者ID的自动编号字段而不是SSN(称为自然主键)。

技术主键通常优于自然主键,因为看起来不变的东西会发生变化,这可能会导致问题。甚至国家也可以存在并且不复存在。

如果您确实拥有技术主键,那么您不希望通过赋予它们本来没有的含义来使它们成为事实上的自然主键。我认为将主键放在URL中是好的,但安全性是一个单独的主题。如果有人可以更改该URL并访问他们无法访问的内容,那么这是一个安全问题,需要通过身份验证和授权来处理。

有些人会争辩说,用户永远不应该看到它们。我认为你不需要那么远。

答案 1 :(得分:7)

关于暴露主键的危险,你需要阅读“autoincrement considered harmful”,作者:Joshua Schachter。

  

包含标识符的网址   让你失望有三个原因。

     

首先是给定的URL   一些对象,你可以搞清楚   已创建对象的URL   周围。这暴露了数量   数据库中的对象可能   竞争对手或其他人   不想拥有这些信息(如   盟军着名的证明   猜测德国坦克生产水平   通过查看序列号。)

     

其次,在某些时候会有一些混蛋   得到写一个shell脚本的想法   使用for循环并尝试获取每个   系统中的单个对象;这个   绝对没有乐趣。

     

最后,在用户的情况下,它   允许人们得到某种形式   社会等级。经常见证   劫持和/或黑客攻击   高声望的低位数ICQ ID。

答案 2 :(得分:4)

如果您担心某人更改URL以尝试查看其他值,那么您可能需要查看令牌生成。

例如,不是给用户一个'SearchID'值,而是给它们一个SearchToken,它是一个很长的唯一伪随机值(读取:GUID),然后你可以在内部映射到SearchID。

当然,您还需要应用会话安全性并保持柔和 - 因为即使是具有非顺序ID的唯一URL也不会受到服务器与用户之间的任何嗅探。

答案 3 :(得分:2)

只需发送主键即可。只要您的数据库操作与用户界面密封在一起,就没问题了。

答案 4 :(得分:2)

如果出于安全原因而隐藏主键,请不要这样做。这通过默默无闻而被称为安全性,并且有更好的方法。话虽如此,至少有一个合理的理由来掩盖主键,这是为了防止有人通过简单地检查URL中的查询字符串并确定他们可以简单地增加id值并下拉每条记录来抓取所有内容。一个坚定的刮刀仍然可以发现你的阻力,尽管你尽了最大的努力,但至少你没有做到这一点。

答案 5 :(得分:1)

出于您的目的(构建搜索引擎),加密数据库主键的安全权衡优势可以忽略不计。 Base64编码不是加密 - 它通过默默无闻的安全性,甚至不会成为攻击者的速度爆炸。

答案 6 :(得分:1)

如果您正在尝试保护数据库查询输入,请使用参数化查询。如果主键被公众操纵,根本没有理由隐藏主键。

当您在URL中看到base64时,您几乎可以确保该网站的开发人员不知道他们在做什么,并且该网站容易受到攻击。

答案 7 :(得分:1)

  

包含标识符的网址   让你失望有三个原因。

错误,错误,错误。

首先 - 每个请求都必须经过验证,无论它是以带有id,POST或Web服务调用的HTTP GET形式出现的。

第二 - 正确制作的网站需要针对依赖IP地址跟踪和请求频率分析的机器人进行保护;隐藏ID可能会阻止某些人编写shell脚本来获取一系列对象,但还有其他方法可以通过某种类型的暴力攻击来利用网站。

第三 - ICQ ID很有价值,但仅仅因为它们与用户有关并且是用户的主要识别手段;它是一种独一无二的用户身份验证方法,不被任何其他服务,程序或网站使用。

所以,总结一下..是的,你需要担心刮刀和DDOS攻击和数据保护以及其他一些东西,但隐藏ID不能正确解决任何这些问题。

答案 8 :(得分:1)

PostgreSQL为此问题提供了多种解决方案,并且可以适用于其他RDBM:

  • hashidshttps://hashids.org/postgresql/

      

    Hashids是一个小型的开放源代码库,可从数字生成短的,唯一的,非顺序的ID。   它将347之类的数字转换为“ yr8”之类的字符串,或将[27,986]之类的数字数组转换为“ 3kTMd”。   您还可以将这些ID解码回来。这对于将多个参数捆绑为一个或仅将它们用作短UID很有用。

  • optimushashids类似,但仅提供整数作为输出:https://github.com/jenssegers/optimus

  • skip32,位于https://wiki.postgresql.org/wiki/Skip32_(crypt_32_bits)

      

    它可以用于生成一系列看起来随机的唯一值,或混淆SERIAL主键而不失去其唯一性。

  • pseudo_encrypt(),位于https://wiki.postgresql.org/wiki/Pseudo_encrypt

      

    pseudo_encrypt(int)可以用作唯一值的伪随机生成器。它产生一个整数输出,该整数输出唯一地与其整数输入相关联(通过数学排列),但同时看起来是随机的,且碰撞为零。

  • 本文详细介绍了如何在Instagram:https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c上完成此操作,归结为:

      

    我们已使用PL / PGSQL,Postgres的内部编程语言和Postgres的现有自动递增功能将ID创建委托给每个分片中的每个表。   我们的每个ID均包含:      41位的时间(以毫秒为单位)(使用自定义历元为我们提供了41年的ID)      代表逻辑碎片ID的13位   10位代表一个自动递增序列,模数1024。这意味着我们可以每碎片,每毫秒生成1024个ID

答案 9 :(得分:0)

当我需要查询字符串参数以便能够识别列中的单个行时,我通常会向该表添加GUID列,然后在连接字符串中传递GUID而不是行的主键值。 / p>