除了我对重新发明轮子的评论之外;我看到这个理论的主要问题是它完全受到重放攻击。
例如,给定一个 ID 为 99 且会话 ID/cookie 为“MONKEY-1”的用户——如果用户想要发送一个请求,他必须以某种方式使用“from, 99, MONKEY-1”对其进行签名。让我们假设它是这样的:
{ FROM: 99, TO: SERVER, COMMAND: GET-NEW-MAIL, SESSION: MONKEY-1 }
太好了,如果 MONKEY-1 是秘密的话。(无论你喜欢什么格式;它也可能是一个 4KiB 的二进制线路噪声块。)
然而,现在我们有一个窃听者,他看到了那个数据包经过……她现在发送了她自己的数据包。也许她很聪明,并且欺骗了真实用户 99 正在使用的源 IP 地址——即使窃听者听不到您的回复,她仍然可以向您发送数据包。也许那个看起来像这样:
{ FROM: 99, TO: SERVER, COMMAND: DELETE-ALL-MAIL, SESSION: MONKEY-1 }
有很多方法可以防止这种事情,它们的效果各不相同。在 SSL 中包装连接有助于使这变得极其困难(但绝不是不可能);这是很多网站都依赖的解决方案。一种更好的方法是使用双向通信以一种入侵者无法获取秘密数据的方式对事物进行签名,使用散列或公钥/私钥加密。例如,假设我们有这样的交换:
{ FROM: SERVER, TO: ??, COMMAND: PLEASE-LOGIN, NONCE: PIGEON }
{ FROM: BILL, TO: SERVER, COMMAND: LOGIN, AUTH: hash ( hash ( password ) . "PIGEON" ) }
......其中hash()
表示,比如说,一个 SHA-256 总和,并且. "PIGEON"
是指连接;
{ FROM: SERVER, TO: BILL, COMMAND: LOGIN-OK, SESSION: hash ( password ) ^ "MONKEY-1" }
… where^
指的是一些操作,比如按位异或,也许。然后,随后,Bill 发送如下请求:
{ FROM: BILL, TO: SERVER, COMMAND: GET-NEW-MAIL, NONCE: "ARMADILLO",
AUTH: hash ( "GET-NEW-MAIL" . #\Newline . "ARMADILLO" . #\Newline . "MONKEY-1" ) }
现在,MONKEY-1 从未在任何时候畅通无阻;并且,在每个请求上给出的 AUTH 密钥与所使用的动词或命令以及一个随机数相关联,该随机数应该随每个请求而变化,服务器可以轻松验证其完整性,但窃听者无法再次重播相同的消息,或更改动词和做一些不同的事情。
解释密码问题:
我有一个数据库表,它包含
User: BILL, Password: hash(DOLPHIN)
如果,在网上,我收到
{ FROM: BILL, PASSWORD: hash(DOLPHIN), COMMAND: GET-ALL-MAIL }
......那么窃听者不太可能(但相当合理)知道密码是 DOLPHIN,但是,她不需要知道或关心:
{ FROM: BILL, PASSWORD: hash(DOLPHIN), COMMAND: DELETE-ALL-MAIL }
你提到加盐密码......你会怎么做?
User: BILL, PASSWORD: hash( SALT . DOLPHIN )
除非您将 SALT 和 DOLPHIN 分开存放,否则您很难从
hash ( SALT . DOLPHIN )
到hash (DOLPHIN)
. 因此,要么用户必须向hash ( SALT . DOLPHIN )
您提交(在客户端放置一个静态 SALT),要么您必须再次存储明文密码。
解决方法可能是做类似的事情
Database: ( BILL => hash ( SALT . DOLPHIN ) )
Server sends: ( NONCE )
Client sends: ( BILL => hash ( NONCE . hash ( SALT . DOLPHIN ) ) )