node.js,带SSL的socket.io

Bey*_*ond 152 ssl https websocket node.js socket.io

我正在尝试使用我的SSL证书运行socket.io但是,它将无法连接.

我将我的代码基于聊天示例:

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});
...
Run Code Online (Sandbox Code Playgroud)

如果我删除SSL代码它运行正常,但是有了它我收到了http://domain.com/socket.io/1/?t=1309967919512的请求

请注意,它不会尝试https,这会导致失败.

我正在测试chrome,因为它是此应用程序的目标浏览器.

如果这是一个简单的问题,我很抱歉,我是node/socket.io新手.

谢谢!

kan*_*aka 181

使用安全URL进行初始连接,即使用"https://"代替"http://".如果选择了WebSocket传输,那么Socket.IO也应该自动使用"wss://"(SSL)进行WebSocket连接.

更新:

您还可以尝试使用'secure'选项创建连接:

var socket = io.connect('https://localhost', {secure: true});
Run Code Online (Sandbox Code Playgroud)

  • 如果在网址中指定"https",则不需要`{secure:true}`.以下是socket.io客户端源代码`secure:'https'== uri.protocol`(版本0.9.16)的摘录,如果在URL中检测到https,则将安全选项设置为true. (12认同)
  • 我相信通过使用secure:true和向客户端发出https url来确保连接是安全的是谨慎的.这种方式无论你知道什么,它都将是一个安全的连接. (4认同)
  • 我使用https URL尝试过此操作,实际上并不需要`{secure:true}`才能正常运行。 (3认同)

emo*_*nik 42

这就是我设法用express来设置的方法:

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){
    ...
})
Run Code Online (Sandbox Code Playgroud)


我希望这能节省一些人的时间.

更新:对于使用let加密的人使用此

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

  • “`rejectUnauthorized: false` 警告:它会让您容易受到 MITM 攻击!” (3认同)
  • 这是唯一对我有用的解决方案。谢谢你节省了我的时间。 (2认同)
  • 谢谢,这个解决方案对我来说是完美的。如果您使用letsencrypt.org提供的免费证书,则可以使用以下代码。`var server = https.createServer({key:fs.readFileSync('/ etc / letsencrypt / live / domain.name / privkey。 pem'),证书: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);` (2认同)
  • 非常感谢这个答案。它对我有很大的帮助。 (2认同)
  • 谢谢,与 letencrypt 和 .pem 文件一起工作非常顺利 (2认同)

Kuf*_*Kuf 31

同样,如果您的服务器支持两者http,https您可以使用以下方式连接:

var socket = io.connect('//localhost');
Run Code Online (Sandbox Code Playgroud)

自动检测浏览器方案,并使用HTTP/HTTPS连接相应.在https中,默认情况下传输将受到保护,如使用连接

var socket = io.connect('https://localhost');
Run Code Online (Sandbox Code Playgroud)

将使用安全的Web套接字 - wss://(这 {secure: true}是多余的).

有关如何使用同一节点服务器轻松提供http和https的详细信息,请查看此答案.


cle*_*ion 9

如果您的服务器认证文件不受信任(例如,您可以使用java中的keytool命令自行生成密钥库),则应添加额外选项rejectUnauthorized

var socket = io.connect('https://localhost', {rejectUnauthorized: false});
Run Code Online (Sandbox Code Playgroud)


Gab*_*ocq 5

根据您的需要,您可以允许安全和不安全的连接,并且仍然只使用一个 Socket.io 实例。

您只需实例化两台服务器,一台用于 HTTP,另一台用于 HTTPS,然后将这些服务器附加到 Socket.io 实例。

服务器端 :

// 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

});
Run Code Online (Sandbox Code Playgroud)

客户端 :

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 );
});
Run Code Online (Sandbox Code Playgroud)

如果您的 NodeJS 服务器与您的 Web 服务器不同,您可能需要设置一些 CORS 标头。所以在服务器端,替换:

const httpServer  = http.createServer();
const httpsServer = https.createServer({
    "key" : fs.readFileSync( "yourcert.key" ),
    "cert": fs.readFileSync( "yourcert.crt" ),
    "ca"  : fs.readFileSync( "yourca.crt"   )
});
Run Code Online (Sandbox Code Playgroud)

和:

const CORS_fn = (req, res) => {
    res.setHeader( "Access-Control-Allow-Origin"     , "*"    );
    res.setHeader( "Access-Control-Allow-Credentials", "true" );
    res.setHeader( "Access-Control-Allow-Methods"    , "*"    );
    res.setHeader( "Access-Control-Allow-Headers"    , "*"    );
    if ( req.method === "OPTIONS" ) {
        res.writeHead(200);
        res.end();
        return;
    }
};
const httpServer  = http.createServer( CORS_fn );
const httpsServer = https.createServer({
        "key" : fs.readFileSync( "yourcert.key" ),
        "cert": fs.readFileSync( "yourcert.crt" ),
        "ca"  : fs.readFileSync( "yourca.crt"   )
}, CORS_fn );
Run Code Online (Sandbox Code Playgroud)

当然,添加/删除标题并根据您的需要设置标题的值。