Я знаю, что есть много других вопросов, подобных этому, но после нескольких дней попыток у меня больше нет идей для решения проблемы.
Я впервые испытываю подключение к Websocket, мне нужно создать простой чат и для этого я пытаюсь PHPWebSocketServer (https://github.com/ghedipunk/PHP-WebSockets), поэтому я проверил этот пример чата (https://github.com/Flynsarmy/PHPWebSocket-Chat) и все работает нормально, пока я не использую соединение ws (это известная история).
Для wss я настроил Stunnel с сертификатом OpenSSL со знаком pem, служба работает, порты (9040 — 9000) открыты, и сервер веб-сокетов правильно прослушивает порт 9000 (php ./server.php), но я не могу понять, почему в stunnel.log всегда есть ошибка «плохой сертификат» при каждом вызове клиента браузера.
Ниже представлены все возможные полезные файлы и журналы.
Начните с файлов PHP-сервера Websocket:
server.php
<?php
// prevent the server from timing out
set_time_limit(0);
// include the web sockets server script (the server is started at the far bottom of this file)
require 'class.PHPWebSocket.php';
// when a client sends data to the server
function wsOnMessage($clientID, $message, $messageLength, $binary) {
global $Server;
$ip = long2ip( $Server->wsClients[$clientID][6] );
// check if message length is 0
if ($messageLength == 0) {
$Server->wsClose($clientID);
return;
}
//The speaker is the only person in the room. Don't let them feel lonely.
if ( sizeof($Server->wsClients) == 1 )
$Server->wsSend($clientID, "There isn't anyone else in the room, but I'll still listen to you. --Your Trusty Server");
else
//Send the message to everyone but the person who said it
foreach ( $Server->wsClients as $id => $client )
if ( $id != $clientID )
$Server->wsSend($id, "Visitor $clientID ($ip) said \"$message\"");
}
// when a client connects
function wsOnOpen($clientID)
{
global $Server;
$ip = long2ip( $Server->wsClients[$clientID][6] );
$Server->log( "$ip ($clientID) has connected." );
//Send a join notice to everyone but the person who joined
foreach ( $Server->wsClients as $id => $client )
if ( $id != $clientID )
$Server->wsSend($id, "Visitor $clientID ($ip) has joined the room.");
}
// when a client closes or lost connection
function wsOnClose($clientID, $status) {
global $Server;
$ip = long2ip( $Server->wsClients[$clientID][6] );
$Server->log( "$ip ($clientID) has disconnected." );
//Send a user left notice to everyone in the room
foreach ( $Server->wsClients as $id => $client )
$Server->wsSend($id, "Visitor $clientID ($ip) has left the room.");
}
// start the server
$Server = new PHPWebSocket();
$Server->bind('message', 'wsOnMessage');
$Server->bind('open', 'wsOnOpen');
$Server->bind('close', 'wsOnClose');
// for other computers to connect, you will probably need to change this to your LAN IP or external IP,
// alternatively use: gethostbyaddr(gethostbyname($_SERVER['SERVER_NAME']))
$Server->wsStartServer('0.0.0.0', 9000);
?>
клиент-chat.php
<html>
<head>
<meta charset='UTF-8' />
<style>
input, textarea {border:1px solid #CCC;margin:0px;padding:0px}
#body {max-width:800px;margin:auto}
#log {width:100%;height:400px}
#message {width:100%;line-height:20px}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="fancywebsocket.js"></script>
<script>
var Server;
function log( text ) {
$log = $('#log');
//Add text to log
$log.append(($log.val()?"\n":'')+text);
//Autoscroll
$log[0].scrollTop = $log[0].scrollHeight - $log[0].clientHeight;
}
function send( text ) {
Server.send( 'message', text );
}
$(document).ready(function() {
log('Connecting...');
Server = new FancyWebSocket('wss://xx.xx.xx.xx:9040');
$('#message').keypress(function(e) {
if ( e.keyCode == 13 && this.value ) {
log( 'You: ' + this.value );
send( this.value );
$(this).val('');
}
});
//Let the user know we're connected
Server.bind('open', function() {
log( "Connected." );
});
//OH NOES! Disconnection occurred.
Server.bind('close', function( data ) {
log( "Disconnected." );
});
//Log any messages sent from server
Server.bind('message', function( payload ) {
log( payload );
});
Server.connect();
});
</script>
</head>
<body>
<div id='body'>
<textarea id='log' name='log' readonly='readonly'></textarea><br/>
<input type='text' id='message' name='message' />
</div>
</body>
</html>
stunnel.conf
cert = /home/myuser/ssl-cert/ssl/stunnel.pem
key = /home/myuser/ssl-cert/mykey.key
chroot = /var/run/stunnel
pid = /stunnel.pid
client = no
fips = no
sslVersion = all
options = NO_SSLv2 ;also commented but same result
options = NO_SSLv3 ;also commented but same result
accept = foobar
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
debug = 7
output = /var/log/stunnel/stunnel.log
[stunnel]
accept = 0.0.0.0:9040
connect = 127.0.0.1:9000
Мой подписанный OpenSSL сертификат получен из ssls (COMODO) CA, как указано в разделе о том, как я использовал имя хоста сервера в качестве общего имени, давайте назовем его (mydomain.com), но у меня также есть другой сертификат OpenSSL с доменное имя моего сайта как общее имя для режима https (www.mydomain.com), я использовал оба, но ошибка все та же.
В любом случае, COMODO отправил мне 4 разных файла: mydomain_com.crt, COMODORSADomainValidationSecureServerCA.crt, COMODORSAAddTrustCA.crt, AddTrustExternalCARoot.crt, и я отсортировал их именно таким образом в файле stunnel.pem.
stunnel.log (при запуске сервиса)
2015.04.24 17:39:30 LOG7[13406:139929686013888]: Snagged 64 random bytes from /dev/urandom
2015.04.24 17:39:30 LOG7[13406:139929686013888]: RAND_status claims sufficient entropy for the PRNG
2015.04.24 17:39:30 LOG7[13406:139929686013888]: PRNG seeded successfully
2015.04.24 17:39:30 LOG7[13406:139929686013888]: Configuration SSL options: 0x03000000
2015.04.24 17:39:30 LOG7[13406:139929686013888]: SSL options set: 0x03000004
2015.04.24 17:39:30 LOG7[13406:139929686013888]: Certificate: /home/myuser/ssl-cert/ssl/stunnel.pem
2015.04.24 17:39:30 LOG7[13406:139929686013888]: Certificate loaded
2015.04.24 17:39:30 LOG7[13406:139929686013888]: Key file: /home/myuser/ssl-cert/mykey.key
2015.04.24 17:39:30 LOG7[13406:139929686013888]: Private key loaded
2015.04.24 17:39:30 LOG7[13406:139929686013888]: SSL context initialized for service stunnel
2015.04.24 17:39:30 LOG7[13406:139929686013888]: FIPS mode disabled
2015.04.24 17:39:31 LOG5[13406:139929686013888]: stunnel 4.29 on x86_64-redhat-linux-gnu with OpenSSL 1.0.1e-fips 11 Feb 2013
2015.04.24 17:39:31 LOG5[13406:139929686013888]: Threading:PTHREAD SSL:ENGINE,FIPS Sockets:POLL,IPv6 Auth:LIBWRAP
2015.04.24 17:39:31 LOG6[13406:139929686013888]: file ulimit = 1024 (can be changed with 'ulimit -n')
2015.04.24 17:39:31 LOG6[13406:139929686013888]: poll() used - no FD_SETSIZE limit for file descriptors
2015.04.24 17:39:31 LOG5[13406:139929686013888]: 500 clients allowed
2015.04.24 17:39:31 LOG7[13406:139929686013888]: FD 10 in non-blocking mode
2015.04.24 17:39:31 LOG7[13406:139929686013888]: FD 11 in non-blocking mode
2015.04.24 17:39:31 LOG7[13406:139929686013888]: FD 12 in non-blocking mode
2015.04.24 17:39:31 LOG7[13406:139929686013888]: SO_REUSEADDR option set on accept socket
2015.04.24 17:39:31 LOG7[13406:139929686013888]: stunnel bound to 0.0.0.0:9040
2015.04.24 17:39:31 LOG7[13412:139929686013888]: Created pid file /stunnel.pid
stunnel.log (клиент wss call)
2015.04.24 17:45:10 LOG7[13412:139929686013888]: stunnel accepted FD=13 from xx.xx.xx.xx:62481
2015.04.24 17:45:10 LOG7[13412:139929686116096]: stunnel started
2015.04.24 17:45:10 LOG7[13412:139929686116096]: FD 13 in non-blocking mode
2015.04.24 17:45:10 LOG7[13412:139929686116096]: TCP_NODELAY option set on local socket
2015.04.24 17:45:10 LOG7[13412:139929686116096]: Waiting for a libwrap process
2015.04.24 17:45:10 LOG7[13412:139929686116096]: Acquired libwrap process #0
2015.04.24 17:45:10 LOG7[13412:139929686116096]: Releasing libwrap process #0
2015.04.24 17:45:10 LOG7[13412:139929686116096]: Released libwrap process #0
2015.04.24 17:45:10 LOG7[13412:139929686116096]: stunnel permitted by libwrap from xx.xx.xx.xx:62481
2015.04.24 17:45:10 LOG5[13412:139929686116096]: stunnel accepted connection from xx.xx.xx.xx:62481
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): before/accept initialization
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 read client hello A
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 write server hello A
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 write certificate A
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 write server done A
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 flush data
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 read client key exchange A
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 read finished A
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 write session ticket A
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 write change cipher spec A
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 write finished A
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL state (accept): SSLv3 flush data
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 0 items in the session cache
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 0 client connects (SSL_connect())
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 0 client connects that finished
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 0 client renegotiations requested
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 1 server connects (SSL_accept())
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 1 server connects that finished
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 0 server renegotiations requested
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 0 session cache hits
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 0 external session cache hits
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 0 session cache misses
2015.04.24 17:45:10 LOG7[13412:139929686116096]: 0 session cache timeouts
2015.04.24 17:45:10 LOG6[13412:139929686116096]: SSL accepted: new session negotiated
2015.04.24 17:45:10 LOG6[13412:139929686116096]: Negotiated ciphers: AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1
2015.04.24 17:45:10 LOG7[13412:139929686116096]: FD 14 in non-blocking mode
2015.04.24 17:45:10 LOG6[13412:139929686116096]: connect_blocking: connecting 127.0.0.1:9000
2015.04.24 17:45:10 LOG7[13412:139929686116096]: connect_blocking: s_poll_wait 127.0.0.1:9000: waiting 10 seconds
2015.04.24 17:45:10 LOG5[13412:139929686116096]: connect_blocking: connected 127.0.0.1:9000
2015.04.24 17:45:10 LOG5[13412:139929686116096]: stunnel connected remote server from 127.0.0.1:50258
2015.04.24 17:45:10 LOG7[13412:139929686116096]: Remote FD=14 initialized
2015.04.24 17:45:10 LOG7[13412:139929686116096]: TCP_NODELAY option set on remote socket
2015.04.24 17:45:10 LOG7[13412:139929686116096]: SSL alert (read): fatal: bad certificate
2015.04.24 17:45:10 LOG3[13412:139929686116096]: SSL_read: 14094412: error:14094412:SSL routines:SSL3_READ_BYTES:sslv3 alert bad certificate
2015.04.24 17:45:10 LOG5[13412:139929686116096]: Connection reset: 0 bytes sent to SSL, 0 bytes sent to socket
2015.04.24 17:45:10 LOG7[13412:139929686116096]: stunnel finished (0 left)
я также попробовал клиентское соединение openssl
openssl s_client -connect xx.xx.xx.xx:9040
и это работает!
Пожалуйста помоги!
я также попробовал клиентское соединение openssl … и оно работает!
Непонятно, что работает: возможно, соединение и рукопожатие SSL работает. И если цепочка доверия работает, вы получаете Verify return code: 0 (ok)
, Но openssl s_client
не делает никаких проверок имени хоста, в то время как браузеры делают.
Сервер = новый FancyWebSocket (‘wss: //xx.xx.xx.xx: 9040’);
Это будет работать, только если ваш сертификат действительно для данного IP. Но я сомневаюсь, что вы купили сертификат для определенного IP, потому что обычно вы покупаете сертификат для имени хоста. Поскольку вы не обращаетесь к серверу по имени, содержащемуся в сертификате, проверка имени хоста завершится неудачно.
Других решений пока нет …