我使用的是Flask内置会话机制。
以下是我对会话机制(带烧瓶)的理解:
- 所有会话数据都存储在签名的cookie中(带有app.secret_key)
- 当会话数据被修改时,cookie会被更改
- 会话的数据受到写客户端保护(由于签名),但不受读取保护
想象一下以下场景:
- 在我的会话中,我放置了一个变量
try_number=3
- 每次用户执行操作时,都会减少此数字
- 如果此数字等于0,则禁止操作
用户第一次连接到应用程序,应用程序发送一个Set-Cookie: sesssion=Flask.sign("try_number=3")
,让我们将此cookie称为COOKIE_A
。
用户执行他的第一个操作,他发送COOKIE_A,应用程序用Set-Cookie: sesssion=Flask.sign("try_number=2")
回复,让我们把这个COOKIE称为COOKIE_B
。
现在,如果用户执行了另一个操作,但没有再次使用COOKIE_B
而是使用COOKIE_A
(例如使用curl
),则cookie仍然是签名的,并且将由服务器使用try_number=3
来处理。
因此,只有使用COOKIE_A
进行所有操作,他才能"欺骗"会话机制,并在同一会话中进行无限制的操作。
有什么内在机制可以防止这种情况发生吗?(我说的不是使用sqlite/redis的代码片段,而是内置解决方案)
这不是Flask cookie安全性的失败,而是计数器设计的失败。没有针对重播攻击的内置保护。
您可以缩短会话cookie的过期时间。这并不能真正解决问题,只会使窗口变小。它还使会话不便于正常使用,这会惹恼您的普通用户。
最终,你必须在服务器上存储一些信息并进行检查。你可以在每个请求中发送一个nonce,并保存已发送回的信息,忽略以前看到的信息。您还可以将所有会话信息(除了一些标识密钥)存储在服务器端,这样就无法重新发送。