mysql - MySQL & Socket.IO – 泛滥数据库 > 重复事务
问题描述
我不知道我应该在哪里发布我的问题及其背后的问题,但我会在这里试一试。
前段时间我有一个小项目,用户可以在想法上花费硬币。这些硬币作为余额存储在我的 MySQL 数据库中的用户帐户中。前端使用常规模块连接到后端socket.io
,节点应用程序使用常规mysql
模块与数据库通信。
问题: 不幸的是,过了一段时间我发现有可能使用socket.io连接(或多次打开网站以获得相同的结果)淹没/垃圾邮件节点应用程序以减慢 mysql 查询. 这就是为什么可以花费用户两次或更多的硬币的原因。
正常的工作流程是这样的:
Request to DB
check balance
if balance > 0
spend coins
reduce coins in DB
else
reject
请求结束
如何花两次硬币:(问题)
Request to DB
Request to DB
check balance
check balance
if balance > 0
if balance > 0
spend coins
spend coins
reduce coins in DB
reduce coins in DB
else
reject
Request end
Request end
这样就可以在余额更新之前获得花费硬币的代码。
问题: 如何防止用户做这样的事情?使用请求限制器仅适用于使用相同 IP 的人,因此 scriptkiddys 应该无法访问我上面提到的内容。使用具有不同 ip 的小型僵尸网络的人呢?
如果我能找到解决这个问题的方法,我可以重新开始这个项目。
解决方案
一种解决方案是select for update ... where user = XXX
使用check balance
.
另一种解决方案是添加一version
列。然后get balance and version
, (假设 verison 为 n), spend
, reduce coins and set version= n+1 where version == n
, 则后面的填充失败。在此解决方案中,您应该spend coins
在reduce succeeded.
.
这些只是一般的解决方案,仅供参考,因为我不熟悉 socket.io。
推荐阅读
- reactjs - 使用 redux-thunk 中间件在 redux 中正确的异步操作类型
- python - 如何允许某个类只能在 python 脚本中访问一次?
- c# - C# WebSockets 监听 UNIX 域套接字?
- apache-spark - PySpark 上的 regexp_replace 用于两列
- javascript - 如何安全地深入物体
- typescript - 如何在 Cypress 6.0 之前恢复 cy.wait() 类型以返回 XMLHttpRequest
- javascript - react js中带参数调用回调的最佳实践
- installation - 在 wix 安装程序上应用转换时出错
- gcc - googletest 在使用 cmake / gcc 10.2 重新编译时失败
- html - 为什么当我使用状态代码 200 渲染我的页面时会显示原始 Html 代码?