5

在我的网络应用程序的一个表单中,出于安全原因,我需要保护一个隐藏字段以防止被篡改。我正在尝试提出一个解决方案,通过该解决方案我可以检测隐藏字段的值是否已更改,并做出适当的反应(即使用通用的“出现问题,请重试”错误消息)。该解决方案应该足够安全,以至于暴力攻击是不可行的。我有一个我认为可行的基本解决方案,但我不是安全专家,我可能在这里完全遗漏了一些东西。

我的想法是渲染两个隐藏的输入:一个名为“important_value”,包含我需要保护的值,另一个名为“important_value_hash”,其中包含与恒定长随机字符串连接的重要值的 SHA 哈希(即相同的字符串将每次都使用)。提交表单时,服务器会重新计算 SHA 哈希,并与提交的重要值哈希值进行比较。如果它们不一样,那么important_value 已经被篡改了。

我还可以将附加值与 SHA 的输入字符串(可能是用户的 IP 地址?)连接起来,但我不知道这是否真的让我受益匪浅。

这会安全吗?任何人都知道它是如何被破坏的,以及可以/应该做些什么来改进它?

谢谢!

4

6 回答 6

4

最好将哈希存储在服务器端。可以想象,攻击者可以更改值并生成他/她自己的 SHA-1 哈希并添加随机字符串(他们可以通过重复访问页面很容易地弄清楚这一点)。如果散列在服务器端(可能在某种缓存中),您可以重新计算散列并检查它以确保该值没有以任何方式被篡改。

编辑

我读错了关于随机字符串(常量盐)的问题。但我想原来的观点仍然存在。攻击者可以建立一个与隐藏值相对应的哈希值列表。

于 2010-04-13T19:39:50.420 回答
1

电子签名

这可能有点矫枉过正,但这听起来与您对外发电子邮件进行数字签名以使收件人可以验证其来源和内容是否真实时没有什么不同。只要您保护私钥并在返回时使用公钥验证数据和签名,就可以将篡改敏感字段的签名与您的篡改敏感字段一起发布到野外,而无需担心无法检测到篡改。

该方案甚至有一个漂亮的属性,您可以将“签名”限制为可以访问私钥的非常受保护的服务器/进程集,但使用公钥提供的更大的服务器/进程集来处理表单提交。

如果您有一个非常敏感的“请勿篡改”字段并且无法在服务器上维护它的哈希签名,那么这就是我会考虑的方法。

尽管我怀疑大多数人都熟悉数字签名,但这里有一些 Wikipedia 供任何外行使用:

公钥密码学 - 安全

... 公钥密码学中的另一种应用类型是数字签名方案。数字签名方案可用于发件人身份验证和不可否认性。在这种方案中,想要发送消息的用户计算该消息的数字签名,然后将该数字签名与消息一起发送给预期的接收者。数字签名方案具有只能在知道私钥的情况下才能计算签名的特性。为了验证消息已经被用户签名并且没有被修改,接收者只需要知道相应的公钥。在某些情况下(例如 RSA),存在与加密方案有许多相似之处的数字签名方案。在其他情况下(例如 DSA)该算法与任何加密方案都不相似。...

于 2010-04-13T20:38:39.377 回答
1

If you can't handle the session on the server, consider encrypting the data with your private key and generating an HMAC for it, send the results as the hidden field(s). You can then verify that what is returned matches what was sent because, since no-one else knows your private key, no-one else can generate the valid information. But it would be much better to handle the 'must not be changed' data on the server side.

You have to recognize that anyone sufficiently determined can send an HTTP request to you (your form) that contains the information they want, which may or may not bear any relation to what you last sent them.

于 2010-04-13T20:40:50.103 回答
0

如果您不能/不会存储哈希服务器端,则需要能够在服务器端重新生成它以验证它。

为了它的价值,你还应该给你的哈希加盐。你说的可能是这个意思:

与一个恒定的长随机字符串连接(即每次都会使用相同的字符串)

知道如果每个用户/登录/会话的值没有不同,它实际上不是一个盐值。

于 2010-04-13T19:44:25.000 回答
0

只要你用生命守护“恒长随机字符串”,那么你的方法就比较强大。

更进一步,您可以生成一次/唯一的“恒定长随机字符串”。

于 2010-04-13T19:47:11.303 回答
0

您所描述的内容类似于所谓的金丝雀所需的部分实现,用于缓解跨站点请求伪造攻击。

一般而言,HTML 表单内的隐藏输入包含一个加密值,该值通过 HTTP 请求回传。会话中保存的浏览器 cookie 或字符串包含相同的加密值,因此当隐藏的输入值被解密并且 cookie/会话值被解密时,未加密的值会相互比较 - 如果它们不相同,则 HTTP 请求不能被信任。

加密值可能是包含属性的对象。例如,在 ASP.NET MVC 中,金丝雀实现使用一个类,该类包含经过身份验证的用户名的属性、使用RNGCryptoServiceProvider该类生成的加密伪随机值、创建对象的日期时间(UTC 格式)和可选的盐字符串. 然后使用 256 位密钥的 AES 加密算法对该对象进行加密,并在请求进入时使用相同的密钥解密。

于 2010-04-13T19:52:49.120 回答