【问题标题】:Open up terminal/shell on remote server via tcp request通过 tcp 请求打开远程服务器上的终端/shell
【发布时间】:2019-05-31 15:35:21
【问题描述】:

我有这个:

const http = require('http');
const cp = require('child_process');

const server = http.createServer((req,res) => {

  const bash = cp.spawn('bash');
  req.pipe(bash.stdin, {end:false);
  bash.stdout.pipe(res);
  bash.stderr.pipe(res);

});

server.listen('4004');

当我点击服务器时:

curl localhost:4004

然后我输入 bash 命令,没有任何东西输出到我的控制台,有人知道为什么吗?

注意:为了解决安全问题,我计划在 docker 容器中运行它,使用 https/ssl,并实施身份验证(有关身份验证方案 lmk 的任何建议)。

更重要的是,我正在寻找 shell 提示 出现...显然 bash 本身不会打开 shell/提示?

【问题讨论】:

  • 获得终端体验的一种方法是使用 ssh,但我正试图弄清楚如何在没有 ssh 的情况下使用其他终端程序或其他东西来实现这一点

标签: node.js bash http


【解决方案1】:

可以这么说,“通过网络”执行此操作。但是,您的方法行不通,因为您正在混合范式(批处理与交互式),并且您缺少运行终端应用程序所需的大量设置。

通常我会向您展示如何对此进行编程,但是,这确实涉及。看看:

https://github.com/chjj/tty.js

和,

https://github.com/xtermjs/xterm.js

作为创建解决方案的起点。

两者都可以直接从 node.js 用于通过 HTTP 提供终端应用程序。

【讨论】:

    【解决方案2】:

    这是一个部分答案,但我开始了赏金,因为我正在寻找更好的东西。我能够像这样使用 TCP 创建一些基本的东西:

    const net = require('net');   // !use net package not http
    const cp = require('child_process');
    
    const server = net.createServer(s => {
    
      const bash = cp.spawn('bash');
      s.pipe(bash.stdin, {end:false});
      bash.stdout.pipe(s);
      bash.stderr.pipe(s);
    
    
    });
    
    server.listen('4004');
    

    不知道为什么它不适用于 HTTP。我使用 netcat 连接到它:

    nc localhost 4004
    

    但这不是打开终端,只是一个 bash 进程。体验并不理想,如下所述: https://unix.stackexchange.com/questions/519364/bash-shell-modes-how-to-pipe-request-to-shell-on-remote-server

    但是我希望复制您在执行以下操作时的 shell 体验:

    docker exec -ti <container> /bin/bash
    

    当我运行 my 脚本时,它“工作”,但我没有得到任何 shell 提示 或类似的东西。 (解决这个问题的一种方法可能是使用 ssh,但我正在尝试另一种方法)。

    【讨论】:

      【解决方案3】:

      您可以使用 telnet 连接到 http 服务器。这取决于您如何启动 http 服务器。这是一个例子

      使用 npm 包 http-server 启动一个 http 服务器

      npm install -g http-server 
      cd ~/ <Any directory>
      http-server
      

      现在单独启动一个 telnet 会话

      telnet localhost 8080
      

      nc localhost 8080
      

      然后输入类似 GET /

      使用 telnet 客户端而不是 nc

      检查这个:https://www.the-art-of-web.com/system/telnet-http11/ 更新:在 nodejs 上运行 ssh 服务器。它允许您运行 ssh 服务器 我在https://github.com/mscdex/ssh2

      找到了这个
      var fs = require('fs');
      var crypto = require('crypto');
      var inspect = require('util').inspect;
      
      var ssh2 = require('ssh2');
      var utils = ssh2.utils;
      
      var allowedUser = Buffer.from('foo');
      var allowedPassword = Buffer.from('bar');
      var allowedPubKey = utils.parseKey(fs.readFileSync('foo.pub'));
      
      new ssh2.Server({
        hostKeys: [fs.readFileSync('host.key')]
      }, function(client) {
        console.log('Client connected!');
      
        client.on('authentication', function(ctx) {
          var user = Buffer.from(ctx.username);
          if (user.length !== allowedUser.length
              || !crypto.timingSafeEqual(user, allowedUser)) {
            return ctx.reject();
          }
      
          switch (ctx.method) {
            case 'password':
              var password = Buffer.from(ctx.password);
              if (password.length !== allowedPassword.length
                  || !crypto.timingSafeEqual(password, allowedPassword)) {
                return ctx.reject();
              }
              break;
            case 'publickey':
              var allowedPubSSHKey = allowedPubKey.getPublicSSH();
              if (ctx.key.algo !== allowedPubKey.type
                  || ctx.key.data.length !== allowedPubSSHKey.length
                  || !crypto.timingSafeEqual(ctx.key.data, allowedPubSSHKey)
                  || (ctx.signature && !allowedPubKey.verify(ctx.blob, ctx.signature))) {
                return ctx.reject();
              }
              break;
            default:
              return ctx.reject();
          }
      
          ctx.accept();
        }).on('ready', function() {
          console.log('Client authenticated!');
      
          client.on('session', function(accept, reject) {
            var session = accept();
            session.once('exec', function(accept, reject, info) {
              console.log('Client wants to execute: ' + inspect(info.command));
              var stream = accept();
              stream.stderr.write('Oh no, the dreaded errors!\n');
              stream.write('Just kidding about the errors!\n');
              stream.exit(0);
              stream.end();
            });
          });
        }).on('end', function() {
          console.log('Client disconnected');
        });
      }).listen(0, '127.0.0.1', function() {
        console.log('Listening on port ' + this.address().port);
      });
      

      【讨论】:

      • 我想在远程机器上打开一个终端,比如ssh,这不会那样tmk...我会让问题更清楚一点。
      • 您无法打开终端 (ssh),因为 ssh 需要持续的双向连接。 HTTP 只会接受一个请求并发送一个响应。这就是 http 服务器的工作原理。
      • 是的,这就是为什么我的部分答案是 tcp 而不是 http,你是对的
      • 如果你启动一个 tcp 服务器,你可以让它对你发送的任何命令做出反应。 HTTP 不会接受这一点。一个请求,一个响应。除非你使用 keep-alive
      • 如果您想自己构建一个,您必须实现一个在每次击键时传输数据的客户端。服务器将以其他格式(可能是 json)发送数据,客户端将解释这一点并显示类似于 shell 的工作方式。它的工作量很大,但可以完成
      【解决方案4】:

      尽管如此,您的方法很复杂,当您最终连接到远程服务器时,不要使用“bash”作为启动连接的方法,BASH 只是重生的外壳,其中包含其他命令和内容,

      宁可使用以下一些程序、命令行名称:即:

       ~ $ 'gnome-terminal'     
      
       ~ $ 'xterm'
      

      您现在将在系统中引用一个真正的程序,即使内核级 C 代码也可以自己识别这些程序,如果不更改的话。

      【讨论】:

        猜你喜欢
        • 2011-12-10
        • 1970-01-01
        • 1970-01-01
        • 2019-11-05
        • 2016-02-27
        • 2019-01-30
        • 2011-06-22
        • 2011-04-21
        • 1970-01-01
        相关资源
        最近更新 更多