Как обеспечить единое частное соединение s sh с помощью ssh2 с socket.io в Meteor - PullRequest
0 голосов
/ 08 мая 2020

Я использую ssh2 и socket.io , чтобы включить соединение s sh в реальном времени с удаленным сервером для пользователей моего Meteor 1.8 .1 приложение. Приложение работает на Ubuntu под Nginx и Phusion Passenger. Вот что необходимо приложению:

  • Каждый авторизованный пользователь уже имеет учетную запись на удаленном сервере.
  • Пользователь начнет сеанс, введя свои учетные данные и щелкнув значок " кнопка подключения "в приложении.
  • Пользователь может просматривать списки каталогов в своем домашнем каталоге на удаленном сервере.
  • Ни один пользователь не должен иметь доступа к сеансу sh другого пользователя.
  • Их сеанс s sh должен быть удален с сервера, когда пользователь нажимает кнопку «отключить».

У меня работает s sh соединение, но я не могу понять узнал, как разрушить соединение s sh в конце сеанса пользователя. Каждый раз, когда они нажимают «разъединить», затем «подключиться», запускается другой сеанс s sh, а старый сеанс s sh все еще работает, поэтому каждая отправленная команда s sh выполняется несколько раз и отправляется несколько ответов. в браузер.

Меня также беспокоит, что соединение небезопасно; в процессе разработки я создаю сервер с помощью require ('http'). createServer () ;. В производстве на моем Ubuntu сервер с настроенным SSL, достаточно ли использовать require ('https'). createServer (); или требуется другая конфигурация, например, Nginx? Socket.io возвращается к старым технологиям, когда веб-сокет недоступен; как это защищено?

  • Главный вопрос: почему я вижу дублирующиеся сеансы S SH каждый раз, когда пользователь отключается, а затем подключается?

  • Второй вопрос: где я могу найти актуальные инструкции по защите socket.io? Или мне следует отказаться от socket.io и использовать WebSocket?

Я читал много статья es и сообщения о переполнении стека, но я нахожу это очень запутанным, и большая часть материала устарела. Например, socketio-auth не поддерживается. Я почти ничего не могу найти в документации Socket.io по аутентификации или авторизации - есть запись рукопожатие , но мне не ясно, нужна ли мне эта функция или как используйте его.

Вот мой код.

Сервер

    io.on('connection', (socket) => {
        console.log('socket id', socket.id); // this shows a new id after disconnect / reconnect

        const conn = new SSHClient();

        socket.on('disconnect', () => {
            console.log('disconnect on server');
            conn.end();
        });

        conn.on('ready', () => {
            socket.emit('message', '*** SSH CONNECTION ESTABLISHED ***');
            socket.emit('ready', 'ready');

            conn.shell((err, stream) => {
                stream.write('stty -echo \n'); // don't echo our own command back, or the user's password...

                if (err) {
                    return socket.emit('message', `*** SSH SHELL ERROR: ' ${err.message} ***`);
                }
                socket.on('path', (path) => {
                    // path is a request for a directory listing
                    if (typeof path === 'string') {
                        const bashCommand = `ls -l ${path} --time-style=full-iso`;
                        console.log('*** WRITE'); // if you disconnect and reconnect this runs twice. Disconnect and reconnect again, it runs 3 times.
                        console.log('socket id again', socket.id); // this shows the same new socket id each time
                        stream.write(`${bashCommand} \n`);
                    }
                });
                stream.on('data', (d) => {
                    socket.emit('data', response); // tell the browser!
                }).on('close', () => {
                    conn.end();
                });
            });
        }).on('close', () => {
            socket.emit('message', '*** SSH CONNECTION CLOSED ***');
        }).on('error', (err) => {
            socket.emit('message', `*** SSH CONNECTION ERROR: ${err.message} ***`);
        }).connect({
            'host': hosturl,
            'username': ausername,
            'agent': anagent, // just for dev I'm using public / private key from my local machine but this will be replaced with the user's entered credentials
        });
    }).on('disconnect', () => {
        console.log('user disconnected');
    });

    server.listen(8080);

Клиент:

const io = require('socket.io-client');
const EventEmitter = require('events');

class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();

const PORT = 8080;

let socket;

myEmitter.on('connectClicked', () => {
    if (socket) {
        this.connected.set(socket.connected);
    }

    if (this.connected.get() === false) {
        socket = io(`http://localhost:${PORT}`);

        socket.on('connect', () => {
            this.connected.set(true);

            socket.on('ready', () => {
                console.log('ready');
            });

            // Backend -> Browser
            socket.on('message', (data) => {
                console.log('socket on message', data);
            });

            // Backend -> Browser
            socket.on('data', (data) => {
                console.log('got data', data);
                this.parseResponse(data); // client function to handle data, not shown here
            });

            // Browser -> Backend
            myEmitter.on('selectDirectory', () => {
                console.log('*** SELECT DIRECTORY');
                socket.emit('path', pathArray.join('/')); // path array is set in client code, it is a simple array of directory names
            });

            socket.on('disconnect', () => {
                console.log('\r\n*** Disconnected from backend***\r\n');
                this.connected.set(false);
            });
        });
    }

    myEmitter.on('disconnectClicked', () => {
        socket.disconnect();
    });
});

1 Ответ

0 голосов
/ 11 мая 2020

Ответом на сохранение s sh соединений отдельно является поддержание списка текущих s sh соединений и переработка кода так, чтобы полученные s sh данные отправлялись только в браузер, который соответствует входящему сообщению. .

Я также отказался от socket.io, потому что не могу быть уверен в безопасности. Сейчас я использую встроенную в Meteor систему обмена сообщениями DDP через пакет Meteor Direct Stream Access . Я думаю, это позволит избежать открытия новых точек доступа к моему веб-серверу.

...