node.js, SSL ile socket.io


163

Ama benim SSL sertifikası ile çalışan socket.io almaya çalışıyorum, bağlanmaz.

Kod örneğimi sohbet örneğine dayandım:

var https = require('https');
var fs = require('fs');
/**
 * Bootstrap app.
 */
var sys = require('sys')
require.paths.unshift(__dirname + '/../../lib/');

/**
* Module dependencies.
*/

var express = require('express')
  , stylus = require('stylus')
  , nib = require('nib')
  , sio = require('socket.io');

/**
 * App.
 */
var privateKey = fs.readFileSync('../key').toString();
var certificate = fs.readFileSync('../crt').toString();
var ca = fs.readFileSync('../intermediate.crt').toString();

var app = express.createServer({key:privateKey,cert:certificate,ca:ca });


/**
 * App configuration.
 */

...

/**
 * App routes.
 */

app.get('/', function (req, res) {
  res.render('index', { layout: false });
});

/**
 * App listen.
 */

app.listen(443, function () {
  var addr = app.address();
  console.log('   app listening on http://' + addr.address + ':' + addr.port);
});

/**
 * Socket.IO server (single process only)
 */

var io = sio.listen(app,{key:privateKey,cert:certificate,ca:ca});
...

SSL kodunu kaldırırsam iyi çalışır, ancak bununla birlikte http://domain.com/socket.io/1/?t=1309967919512 adresine bir istek alırım

Https'yi denemediğini unutmayın, bu da başarısız olmasına neden olur.

Bu uygulama için hedef tarayıcı olduğu için krom üzerinde test yapıyorum.

Bu basit bir soru ise özür dilerim, ben bir node / socket.io acemi.

Teşekkürler!


İstemciniz, 'wss: //' ön ekli URI'ye bağlanmaya çalışıyor mu?
kanaka

Hayır, oraya ulaşmaz , domain.com/socket.io/1/?t=1309967919512 adresine istekte bulunur .
ötesinde

Bağlanılacak adresi nasıl belirtiyorsunuz? "domain.com", socket.io istemci tarafı kitaplığında yer tutucu gibi görünür. Bağlanmak için kullandığınız istemcinin Javascript kodunu gönderebilir misiniz?
kanaka


temelde node.js socket.io istemci tarafı şeyler sihirli işlemek, çünkü tek yapmanız gereken socket.connect çalıştırmak
ötesinde

Yanıtlar:


186

İlk bağlantınız için güvenli bir URL kullanın, yani "http: //" yerine "https: //" kullanın. WebSocket aktarımı seçilirse Socket.IO, WebSocket bağlantısı için de otomatik olarak "wss: //" (SSL) kullanmalıdır.

Güncelleme :

Bağlantıyı 'güvenli' seçeneğini kullanarak da deneyebilirsiniz:

var socket = io.connect('https://localhost', {secure: true});

Biz bunu yaparız. https: // www.thebitcoinwheel.com adresine gittik ve hala otomatik olarak http için bir istekte bulunuyor, bu socket.io kodu ile ilgili bir şey ve sorunun konusu.
ötesinde

1
Siz hayatımı kurtardınız! Bu seçenekleri belgelerde bulamadım.
Paulo Cesar

14
{secure: true}url'de 'https' belirtirseniz gerekli olmamalıdır. Burada socket.io istemci kaynağından bir alıntı secure: 'https' == uri.protocol(sürüm 0.9.16), url'de https algılanırsa güvenli seçeneği true olarak ayarlar.
XiaoChuan Yu

4
Ben bir https URL ile denedim ve gerçekten {secure: true}düzgün çalışması için gerekli değildi.
D Coetzee

4
Ben hem secure: true hem de istemci tarafında bir https url'si kullanarak bağlantının güvenli olduğundan emin olmanın ihtiyatlı olacağına inanıyorum. Bildiğiniz ne olursa olsun güvenli bir bağlantı olacaktır.
gabeio

53

Ben nasıl express ile kurmak başardı:

var fs = require( 'fs' );
var app = require('express')();
var https        = require('https');
var server = https.createServer({
    key: fs.readFileSync('./test_key.key'),
    cert: fs.readFileSync('./test_cert.crt'),
    ca: fs.readFileSync('./test_ca.crt'),
    requestCert: false,
    rejectUnauthorized: false
},app);
server.listen(8080);

var io = require('socket.io').listen(server);

io.sockets.on('connection',function (socket) {
    ...
});

app.get("/", function(request, response){
    ...
})


Umarım bu birinin zamanından tasarruf etmesini sağlar.

Güncelleme: şifrelemek için kullananlar bunu kullanın

var server = https.createServer({ 
                key: fs.readFileSync('privkey.pem'),
                cert: fs.readFileSync('fullchain.pem') 
             },app);

2
Benim için işe yarayan tek çözüm bu. Zamanımı kurtardığın için teşekkürler.
Francisco Hodge

certs ile biraz deneme ve hatadan sonra benim için iyi çalıştı
RozzA

3
Bu çözüm benim için mükemmel çalıştı, teşekkürler. Letsencrypt.org sitesinden ücretsiz sertifikalar kullanıyorsanız, aşağıdaki kodu kullanabilirsiniz .. var server = https.createServer({ key: fs.readFileSync('/etc/letsencrypt/live/domain.name/privkey.pem'), cert: fs.readFileSync('/etc/letsencrypt/live/domain.name/cert.pem'), ca: fs.readFileSync('/etc/letsencrypt/live/domain.name/chain.pem'), requestCert: false, rejectUnauthorized: false },app); server.listen(3000);
Hugo Rune

2
Bu cevap için çok teşekkürler. Bana çok yardımcı oldu.
Harsha Jasti

2
Teşekkürler, letsencrypt ve .pem dosyaları ile bir cazibe gibi çalıştı
Eric

33

Aynı notta, sunucunuz her ikisini de destekliyorsa httpve httpsaşağıdakileri kullanarak bağlanabilirsiniz:

var socket = io.connect('//localhost');

için oto tarayıcı düzenini tespit ve buna göre http / https kullanarak bağlayın. https durumundayken, aktarım varsayılan olarak,

var socket = io.connect('https://localhost');

güvenli web soketleri kullanacaktır - wss://( {secure: true}gereksizdir).

aynı düğüm sunucusunu kullanarak hem http hem de https'nin nasıl kolayca sunulacağı hakkında daha fazla bilgi için bu cevaba göz atın .


10

Sunucu sertifikalı dosyanız güvenilir değilse (örneğin, java'da keytool komutu ile anahtar deposunu kendiniz oluşturabilirsiniz ), ek reddetme seçeneğini eklemelisiniz.

var socket = io.connect('https://localhost', {rejectUnauthorized: false});

düğüm için o anahtarı oluşturmak için tuş takımını nasıl kullandığınızı açıklayan bir örnek eklerseniz takdir edersiniz. Çünkü anahtarlar çok karmaşık ve bu konuda yeterli öğretici yok.
bvdb

keytool, Java Geliştirme Kiti'nin (JDK) içindeki bir araçtır. bu docs.oracle.com/javase/10/tools/…
clevertension

4

Bunu kontrol et.yapılandırma ..

app = module.exports = express();
var httpsOptions = { key: fs.readFileSync('certificates/server.key'), cert: fs.readFileSync('certificates/final.crt') };        
var secureServer = require('https').createServer(httpsOptions, app);
io = module.exports = require('socket.io').listen(secureServer,{pingTimeout: 7000, pingInterval: 10000});
io.set("transports", ["xhr-polling","websocket","polling", "htmlfile"]);
secureServer.listen(3000);

2

Sunucu tarafı:

import http from 'http';
import https from 'https';
import SocketIO, { Socket } from 'socket.io';
import fs from 'fs';
import path from 'path';

import { logger } from '../../utils';

const port: number = 3001;

const server: https.Server = https.createServer(
  {
    cert: fs.readFileSync(path.resolve(__dirname, '../../../ssl/cert.pem')),
    key: fs.readFileSync(path.resolve(__dirname, '../../../ssl/key.pem'))
  },
  (req: http.IncomingMessage, res: http.ServerResponse) => {
    logger.info(`request.url: ${req.url}`);

    let filePath = '.' + req.url;
    if (filePath === './') {
      filePath = path.resolve(__dirname, './index.html');
    }

    const extname = String(path.extname(filePath)).toLowerCase();
    const mimeTypes = {
      '.html': 'text/html',
      '.js': 'text/javascript',
      '.json': 'application/json'
    };

    const contentType = mimeTypes[extname] || 'application/octet-stream';

    fs.readFile(filePath, (error: NodeJS.ErrnoException, content: Buffer) => {
      if (error) {
        res.writeHead(500);
        return res.end(error.message);
      }
      res.writeHead(200, { 'Content-Type': contentType });
      res.end(content, 'utf-8');
    });
  }
);

const io: SocketIO.Server = SocketIO(server);

io.on('connection', (socket: Socket) => {
  socket.emit('news', { hello: 'world' });
  socket.on('updateTemplate', data => {
    logger.info(data);
    socket.emit('updateTemplate', { random: data });
  });
});

server.listen(port, () => {
  logger.info(`Https server is listening on https://localhost:${port}`);
});

İstemci tarafı:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Websocket Secure Connection</title>
</head>

<body>
  <div>
    <button id='btn'>Send Message</button>
    <ul id='messages'></ul>
  </div>
  <script src='../../../node_modules/socket.io-client/dist/socket.io.js'></script>
  <script>
    window.onload = function onload() {
      const socket = io('https://localhost:3001');
      socket.on('news', function (data) {
        console.log(data);
      });

      socket.on('updateTemplate', function onUpdateTemplate(data) {
        console.log(data)
        createMessage(JSON.stringify(data));
      });
      const $btn = document.getElementById('btn');
      const $messages = document.getElementById('messages');

      function sendMessage() {
        socket.emit('updateTemplate', Math.random());
      }

      function createMessage(msg) {
        const $li = document.createElement('li');
        $li.textContent = msg;
        $messages.appendChild($li);
      }

      $btn.addEventListener('click', sendMessage);
    }
  </script>
</body>

</html>

2

Gereksinimlerinize bağlı olarak, hem güvenli hem de güvenli olmayan bağlantılara izin verebilir ve yine de yalnızca bir Socket.io örneği kullanabilirsiniz.

Biri HTTP ve diğeri HTTPS için olmak üzere iki sunucuyu başlatmanız ve ardından bu sunucuları Socket.io örneğine eklemeniz yeterlidir.

Sunucu tarafı:

// needed to read certificates from disk
const fs          = require( "fs"    );

// Servers with and without SSL
const http        = require( "http"  )
const https       = require( "https" );
const httpPort    = 3333;
const httpsPort   = 3334;
const httpServer  = http.createServer();
const httpsServer = https.createServer({
    "key" : fs.readFileSync( "yourcert.key" ),
    "cert": fs.readFileSync( "yourcert.crt" ),
    "ca"  : fs.readFileSync( "yourca.crt"   )
});
httpServer.listen( httpPort, function() {
    console.log(  `Listening HTTP on ${httpPort}` );
});
httpsServer.listen( httpsPort, function() {
    console.log(  `Listening HTTPS on ${httpsPort}` );
});

// Socket.io
const ioServer = require( "socket.io" );
const io       = new ioServer();
io.attach( httpServer );
io.attach( httpsServer );

io.on( "connection", function( socket ) {

    console.log( "user connected" );
    // ... your code

});

Müşteri tarafı:

var url    = "//example.com:" + ( window.location.protocol == "https:" ? "3334" : "3333" );
var socket = io( url, {
    // set to false only if you use self-signed certificate !
    "rejectUnauthorized": true
});
socket.on( "connect", function( e ) {
    console.log( "connect", e );
});

NodeJS sunucunuz Web sunucunuzdan farklıysa, bazı CORS başlıklarını ayarlamanız gerekebilir. Yani sunucu tarafında değiştirin:

httpServer.listen( httpPort, function() {
    console.log(  `Listening HTTP on ${httpPort}` );
});
httpsServer.listen( httpsPort, function() {
    console.log(  `Listening HTTPS on ${httpsPort}` );
});

İle:

const httpServer  = http.createServer( (req, res) => {
    res.setHeader( "Access-Control-Allow-Origin"  , "*" );
    res.setHeader( "Access-Control-Request-Method", "*" );
    res.setHeader( "Access-Control-Allow-Methods" , "*" );
    res.setHeader( "Access-Control-Allow-Headers" , "*" );
    if ( req.method === "OPTIONS" ) {
        res.writeHead(200);
        res.end();
        return;
    }
});
const httpsServer = https.createServer({
        "key" : fs.readFileSync( "yourcert.key" ),
        "cert": fs.readFileSync( "yourcert.crt" )
    }, (req, res) => {
    res.setHeader( "Access-Control-Allow-Origin"  , "*" );
    res.setHeader( "Access-Control-Request-Method", "*" );
    res.setHeader( "Access-Control-Allow-Methods" , "*" );
    res.setHeader( "Access-Control-Allow-Headers" , "*" );
    if ( req.method === "OPTIONS" ) {
        res.writeHead(200);
        res.end();
        return;
    }
});

Ve elbette başlıkların değerlerini ihtiyaçlarınıza göre ayarlayın.


1

Kurumsal uygulamalar için, kodunuzda https kullanmamanız gerektiği unutulmamalıdır. IIS veya nginx aracılığıyla otomatik olarak yükseltilmelidir. Uygulama hangi protokollerin kullanıldığını bilmemelidir.


0

Bu benim nginx yapılandırma dosyam ve iosocket kodum. Sunucu (ekspres) 9191 numaralı bağlantı noktasını dinliyor. İyi çalışıyor: nginx config file:

server {
    listen       443 ssl;
    server_name  localhost;
    root   /usr/share/nginx/html/rdist;

    location /user/ {
        proxy_pass   http://localhost:9191;
    }
    location /api/ {
        proxy_pass   http://localhost:9191;
    }
    location /auth/ {
        proxy_pass   http://localhost:9191;
    }

    location / {
        index  index.html index.htm;
        if (!-e $request_filename){
          rewrite ^(.*)$ /index.html break;
        }
    }
    location /socket.io/ {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass   http://localhost:9191/socket.io/;
    }


    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    ssl_certificate /etc/nginx/conf.d/sslcert/xxx.pem;
    ssl_certificate_key /etc/nginx/conf.d/sslcert/xxx.key;

}

Sunucu:

const server = require('http').Server(app)
const io = require('socket.io')(server)
io.on('connection', (socket) => {
    handleUserConnect(socket)

  socket.on("disconnect", () => {
   handleUserDisConnect(socket)
  });
})

server.listen(9191, function () {
  console.log('Server listening on port 9191')
})

İstemci (reaksiyona):

    const socket = io.connect('', { secure: true, query: `userId=${this.props.user._id}` })

        socket.on('notifications', data => {
            console.log('Get messages from back end:', data)
            this.props.mergeNotifications(data)
        })
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.