2016-12-28 32 views
4

問題在年底制訂的問題,我已經測試答案瀏覽器請求與IO ::插座:: SSL

我正在寫一些代碼來展示一些基本的原則,以先詳細說明其他。代碼將永遠不會有生產力,並且打算簡化。

我的目標(從別人開始)是編寫一個簡單的應用程序,使用Web-Certificat加密其網絡流量。

的出發點是一個應用程序,它不加密:

#!/usr/bin/env perl 
use strict; 
use warnings; 
use IO::Socket::INET; 

# auto-flush on socket 
$| = 1; 

# creating a listening socket 
my $socket = new IO::Socket::INET (
    LocalAddr  => '0.0.0.0',  # local server address 
    LocalPort  => '7777',  # local server port 
    Listen  => 5,    # queue size for connections 
    Proto   => 'tcp',   # protocol used 
); 
die "cannot create socket $!\n" unless $socket; 
print "server waiting for client connection on port 7777\n"; 

while(1) 
{ 
    # waiting for a new client connection 
    my $client_socket = $socket->accept() or die "socket accept failed $!"; 

    # get information about a newly connected client 
    my $client_address = $client_socket->peerhost(); 
    my $client_port = $client_socket->peerport(); 
    print "connection from $client_address:$client_port\n"; 

    # read up to 1024 characters from the connected client 
    my $client_data = ''; 
    sysread($client_socket, $client_data, 1024); 
    print "received data: $client_data\n"; 

    # write response data to the connected client 
    print $client_socket "Hey $client_data!"; 

    # notify client that response has been sent 
    shutdown($client_socket, 1); 
} 

END { 
    $socket->close(); 
} 

此服務器的應用程序可以使用此客戶端調用:

#!/usr/bin/env perl 
use IO::Socket::INET; 

# auto-flush on socket 
$| = 1; 

# create a connecting socket 
my $socket = new IO::Socket::INET (
    PeerHost => '127.0.0.1', 
    PeerPort => '7777', 
    Proto  => 'tcp', 
); 
die "cannot connect to the server $!\n" unless $socket; 
print "connected to the server\n"; 

# data to send to a server 
my $req = $ARGV[0] . ''; 
print $socket $req; 

# notify server that request has been sent 
shutdown($socket, 1); 

# receive a response of up to 1024 characters from server 
my $response = ''; 
sysread($socket, $response,1024); 
print "received response: $response\n"; 

$socket->close(); 

客戶端和服務器之間的相互作用可以看看像這樣:

inet$ perl server.pl server waiting for client connection on port 7777 
connection from 127.0.0.1:40028 
received data: Herbert 

inet$ perl client.pl "Herbert" 
connected to the server 
received response: Hey Herbert! 

很酷的事情是:服務器還可以從瀏覽器調用:

Access TCP-Server with Firefox

所以第一個結論:代碼工作,並是很好的展示一個簡單的客戶端 - 服務器交互的基本功能。

現在的程序應該使用SSL通信

服務器和客戶端都這麼寫的,是SSL的能力可以通過只在代碼中添加幾行來實現:

$ diff inet/server.pl ssl/server.pl 
7c7 
< use IO::Socket::INET; 
--- 
> use IO::Socket::SSL 'inet4'; 
13c13 
< my $socket = new IO::Socket::INET (
--- 
> my $socket = IO::Socket::SSL->new (
17a18,19 
>  SSL_cert_file => 'cert.pem', # SSL certificate 
>  SSL_key_file => 'key.pem',  # SSL certificate key 

$ diff inet/client.pl ssl/client.pl 
5c5 
< use IO::Socket::INET; 
--- 
> use IO::Socket::SSL 'inet4'; 
11c11 
< my $socket = new IO::Socket::INET (
--- 
> my $socket = new IO::Socket::SSL (
14a15 
>  SSL_ca_file => 'cert.pem', 

因此,新的啓用了SSL代碼:

#!/usr/bin/env perl 
use strict; 
use warnings; 
use IO::Socket::SSL 'inet4'; 

# auto-flush on socket 
$| = 1; 

# creating a listening socket 
my $socket = IO::Socket::SSL->new (
    LocalAddr  => '0.0.0.0',  # local server address 
    LocalPort  => '7777',  # local server port 
    Listen  => 5,    # queue size for connections 
    Proto   => 'tcp',   # protocol used 
    SSL_cert_file => 'cert.pem', # SSL certificate 
    SSL_key_file => 'key.pem',  # SSL certificate key 
); 
die "cannot create socket $!\n" unless $socket; 
print "server waiting for client connection on port 7777\n"; 

while(1) 
{ 
    # waiting for a new client connection 
    my $client_socket = $socket->accept() or die "socket accept failed $!"; 

    # get information about a newly connected client 
    my $client_address = $client_socket->peerhost(); 
    my $client_port = $client_socket->peerport(); 
    print "connection from $client_address:$client_port\n"; 

    # read up to 1024 characters from the connected client 
    my $client_data = ''; 
    sysread($client_socket, $client_data, 1024); 
    print "received data: $client_data\n"; 

    # write response data to the connected client 
    print $client_socket "Hey $client_data!"; 

    # notify client that response has been sent 
    shutdown($client_socket, 1); 
} 

END { 
    $socket->close(); 
} 

#!/usr/bin/env perl 
use IO::Socket::SSL 'inet4'; 

# auto-flush on socket 
$| = 1; 

# create a connecting socket 
my $socket = new IO::Socket::SSL (
    PeerHost => '127.0.0.1', 
    PeerPort => '7777', 
    Proto  => 'tcp', 
    SSL_ca_file => 'cert.pem', 
); 
die "cannot connect to the server $!\n" unless $socket; 
print "connected to the server\n"; 

# data to send to a server 
my $req = $ARGV[0] . ''; 
print $socket $req; 

# notify server that request has been sent 
shutdown($socket, 1); 

# receive a response of up to 1024 characters from server 
my $response = ''; 
sysread($socket, $response,1024); 
print "received response: $response\n"; 

$socket->close(); 

運行代碼,證書必須首先創建:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 

現在服務器和客戶端可以啓動,並很好地互動:

ssl$ perl server.pl 
Enter PEM pass phrase: 
server waiting for client connection on port 7777 
connection from 127.0.0.1:40041 
received data: Sabine 

ssl$ perl client.pl "Sabine" 
connected to the server 
received response: Hey Sabine! 

但是,什麼行不通的來自類似Firefox或Chrome的瀏覽器的連接,即使我使用以下格式轉換證書:

openssl pkcs12 -export -in cert.pem -inkey key.pem -out webcert.p12 

我還通過導入菜單將新創建的證書導入瀏覽器。

連接剛被拒絕。瀏覽器無法連接,服務器在$socket->accept()失敗,沒有任何有用的消息
UPDATE:有在導出的變量$SSL_ERROR消息:

SSL accept attempt failed error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request 

我做了一些測試用工具analyze ssl

p5-ssl-tools-master$ perl analyze-ssl.pl --show-chain --all-ciphers -v3 127.0.0.1:7777 
+ checking host=127.0.0.1(127.0.0.1) port=7777 
* version SSLv23 no verification, ciphers= -> TLSv1_2,ECDHE-RSA-AES128-GCM-SHA256 
* version SSLv23 no verification, ciphers=HIGH:ALL -> TLSv1_2,ECDHE-RSA-AES128-GCM-SHA256 
* version TLSv1_2 no verification, ciphers= -> TLSv1_2,ECDHE-RSA-AES128-GCM-SHA256 
* version TLSv1_2 no verification, ciphers=HIGH:ALL -> TLSv1_2,ECDHE-RSA-AES128-GCM-SHA256 
* version TLSv1_1 no verification, ciphers= -> TLSv1_1,ECDHE-RSA-AES256-SHA 
* version TLSv1_1 no verification, ciphers=HIGH:ALL -> TLSv1_1,ECDHE-RSA-AES256-SHA 
* version TLSv1 no verification, ciphers= -> TLSv1,ECDHE-RSA-AES256-SHA 
* version TLSv1 no verification, ciphers=HIGH:ALL -> TLSv1,ECDHE-RSA-AES256-SHA 
* version SSLv3, no verification, ciphers= -> FAIL! SSL connect attempt failed because of handshake problems error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure 
+ 127.0.0.1 failed permanently 'tcp connect: Verbindungsaufbau abgelehnt', no more IP to try 
tcp connect: Verbindungsaufbau abgelehnt 

服務器似乎接受了一定的要求,未能在最後,也許與瀏覽器一樣?

ssl$ perl server.pl 
Enter PEM pass phrase: 
server waiting for client connection on port 7777 
connection from 127.0.0.1:40042 
received data: 
connection from 127.0.0.1:40043 
received data: 
connection from 127.0.0.1:40044 
received data: 
connection from 127.0.0.1:40045 
received data: 
connection from 127.0.0.1:40046 
received data: 
connection from 127.0.0.1:40047 
received data: 
connection from 127.0.0.1:40048 
received data: 
connection from 127.0.0.1:40049 
received data: 
socket accept failed at server.pl line 27. 

我的問題

爲什麼用瀏覽器的請求不能正常工作? 代碼應該支持瀏覽器請求,因爲它不使用SSL。 由於SSL-Perl-Client沒有問題,它似乎是瀏覽器特定的SSL設置。 或者是證書導入瀏覽器不按預期工作? 任何人都可以給我提示或解決這個問題?

更新:當我看看$SSL_ERROR錯誤消息「SSL23」,並在客戶端測試錯誤消息「SSL3」似乎有兼容性問題SSL版本?我需要明確指定我想要的版本嗎? (另一方面,「SSL23」的客戶端測試似乎成功運行...)

非常感謝。

UPDATE:輸出與$IO::Socket::SSL::DEBUG = 3;

ssl$ perl server.pl 
Enter PEM pass phrase: 
DEBUG: .../IO/Socket/SSL.pm:2554: new ctx 42708208 
server waiting for client connection on port 7777 
DEBUG: .../IO/Socket/SSL.pm:799: no socket yet 
DEBUG: .../IO/Socket/SSL.pm:801: accept created normal socket IO::Socket::SSL=GLOB(0x28ac158) 
DEBUG: .../IO/Socket/SSL.pm:829: starting sslifying 
DEBUG: .../IO/Socket/SSL.pm:873: Net::SSLeay::accept -> -1 
DEBUG: .../IO/Socket/SSL.pm:1779: SSL accept attempt failed 

DEBUG: .../IO/Socket/SSL.pm:1784: SSL accept attempt failed error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request 
socket accept failed: SSL accept attempt failed error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request at server.pl line 28. 
DEBUG: .../IO/Socket/SSL.pm:2587: free ctx 42708208 open=42708208 
DEBUG: .../IO/Socket/SSL.pm:2599: OK free ctx 42708208 

回答

2

... SSL accept attempt failed error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request

我的猜測是,你仍然使用http:// URL來訪問服務器,即使你需要使用一個https:// URL。這意味着瀏覽器向服務器發送HTTP請求,而不是首先執行TLS握手,並且僅在成功握手後發送HTTP請求。

除此之外,您還要指望瀏覽器瞭解舊的和長期棄用的HTTP 0.9協議,它只包含沒有任何HTTP頭的響應主體。並非所有瀏覽器都能理解這一點

+0

Ullrich你真棒!雖然對我來說有點尷尬......在我身邊的一個簡單的錯誤。非常感謝您的時間。 (我可能沒有看到森林,因爲所有的樹木,就像我們在德語中所說的那樣) –