【问题标题】:Socket.IO socket protection without authenticationSocket.IO 套接字保护无需认证
【发布时间】:2019-01-02 01:49:47
【问题描述】:

我使用 Express.js 和 socket.io(here)创建了一个简单的 Node.js 应用程序,用户单击一个按钮,它会在页面上增加一个数字。在连接到该页面的所有客户端中,此数字也会实时递增。我正在使用 web sockets 和 socket.io 来获取客户端-服务器通信和实时号码更新系统。

我正在使用flood-protection 模块将套接字发射限制为每秒 5 次,但这并没有让游戏变得非常有趣,因为每秒的点击量很少,黑客可以使用setInterval 并且仍然自动取得相当大的进步,即使速度如此之低。

我的问题:

  1. 我不希望用户必须进行身份验证 - 任何人都应该可以玩!

  2. 如果可能,我希望将点击率保持在每秒 15 次左右。

  3. 我不希望人们能够发送套接字消息并从浏览器控制台自动单击按钮。

Here's the program:

index.js

var express = require("express");
var http = require("http");
var socketIO = require("socket.io");
var path = require("path");
var fs = require("fs");
var FloodProtection = require("flood-protection").default;
__dirname = path.resolve();

function btoa(str) {
  return new Buffer(str, 'latin1').toString('base64');
};

function atob(b64Encoded) {
  return new Buffer(b64Encoded, 'base64').toString('latin1');
};

var app = express();
app.get("/", function(req, res){
  res.sendFile(__dirname + "/index.html");
});

var temp;
num = temp | parseInt(atob(fs.readFileSync("num.txt"))) | 0

var server = http.createServer(app);
var io = socketIO.listen(server, {log: true});
io.sockets.on("connection", (socket) => {
  protector = new FloodProtection({rate: 5, per: 1})
  io.sockets.emit("update", num);
  socket.on("push", (value) => {
    if (protector.check()) {
      num++;
      temp = num
      io.sockets.emit("update", temp);
    } else {
      io.sockets.emit("update", "You can only click the button five times per second.")
      socket.disconnect(2)
      setTimeout(()=>{}, 3000)
    }
  });
  socket.on("disconnect", () => {
    fs.writeFile("num.txt", btoa(String(temp)), (err) => {
      if (err) throw err;
      console.log("saved | new num: " + temp);
    })
  })
});

server.listen(5000);

index.html

<html>
  <head>
    <title>A Button</title>
  </head>
  <body>
    <button onclick='push();'>Click me!</button>
    <p id="out"></p>
  </body>
  <script type="text/javascript" src="/socket.io/socket.io.js"></script>
  <script type="text/javascript">
    var variableFromFrontEnd = 2;
    var socket = io.connect("/");
    socket.on("connect", function() {
      socket.on("update", function(val) {
        document.getElementById("out").innerHTML = val
      });
    });
    socket.on("disconnect", function() {
      setTimeout(()=>{socket.connect();}, 1000);
    });
    function push() {
      if (socket.connected) {
        socket.emit("push");
      }
    }
  </script>
</html>

num.txt 是一个 base-64 编码的数字。

那么,有没有一种方法可以在没有明显的速率限制或身份验证的情况下做到这一点?还是我只需要使用速率限制?

【问题讨论】:

  • 我想知道赞成票的人是不是我现在正在看的玩我的游戏的人;)
  • 是的,是我。我达到了 420,这是我的目标 B)好的,所以我尝试了不同的客户端的东西。我可以按照你说的设置超时并玩循环。我进行了一项小型研究,发现了一些事情。 Facebook 安全工程师执行一条消息只是为了阻止其他人 (stackoverflow.com/questions/21692646/…)。不幸的是,JavaScript 是完整的客户端,我认为您不能完全禁用。 davidwalsh.name/disable-console 阅读此内容。我也想看看其他答案,所以我给你的好问题加了星
  • @Cristian 好的,只是确认一下。该数字可能重置为 346 左右;那是我的错,我不小心刷新了页面或失去了连接或其他东西。我应该尝试在那个 Facebook 问题上的尝试吗?
  • @Cristian 我想我想出了一个解决方案。它要求您通过socket.emit 传入new Error(),并且服务器会检查堆栈跟踪以确保它不包含任何指示浏览器控制台的默认值。

标签: node.js sockets socket.io


【解决方案1】:

用户作弊的方法有很多种,防止作弊的方法也有很多。一般规则是你只能“让事情变得更难”(如果你幸运的话,足够努力,让潜在的作弊者在成功之前就失去兴趣)。

对于基于浏览器的游戏,我会确保您至少确保您的游戏完全缩小/精简(因此您的 javascript 代码尽可能不可读,并且更难只需直接调用“click”函数),并在您的消息中构建校验和(因此用户不能直接对服务器进行套接字调用)。

完成此操作后,您仍然需要处理直接使用代码或插件在元素上生成点击事件的用户,或者使用浏览器外部程序生成点击的用户重复按钮上方的事件。您最好的防御措施不是阻止它,而是检测它——可能在服务器端,通过观察具有持续点击率的用户不可能,然后炸毁他们的游戏/暂时禁止他们的IP/等等。

有关更多相关想法,请参阅相关问题Ways to prevent or reduce cheating(此问题是关于一般客户端-服务器游戏,而不是浏览器游戏,但其中一些讨论仍然有用)。

【讨论】:

  • 您好,关于您对校验和的评论,我该怎么做?您可以参考我的资源吗?
  • 通常,校验和是您附加到消息的内容,可以在另一端进行检查,范围从加密(如 MD5 哈希)或简单的东西(添加所有字节模 32 位)。 gafferongames.com/categories/building-a-game-network-protocol 可能是从此类概念开始的好地方 - 他涵盖了各种有趣的技巧和策略。
猜你喜欢
  • 1970-01-01
  • 2013-01-14
  • 2013-12-01
  • 2014-08-05
  • 1970-01-01
  • 1970-01-01
  • 2011-09-19
  • 1970-01-01
相关资源
最近更新 更多