我正在使用 Perl 通过 TLS 连接到一些(非常)低功耗的硬件设备。第一次握手大约需要 10-15 秒才能完成!重用 session (来自同一个 Perl 进程)要快得多,但是当下一个作业连接到同一个设备时,新进程必须以相同的延迟建立一个新 session 。我想在我的进程之间共享一个 session 缓存,但我遇到了问题(和段错误!)。
我有一个测试脚本(连接到 openssl s_server -www
)和一个使用 Sereal 写缓存的 IO::Socket::SSL::Session_Cache
包装器对象输出到磁盘。尽管在缓存中找到了现有的 session ,它不会重用它们,并且在尝试向缓存中添加其他条目时有时会出现段错误。
use 5.20.1; use warnings;
use LWP::UserAgent;
use IO::Socket::SSL;
# $IO::Socket::SSL::DEBUG = 2;
request_with_new_ua();
request_with_new_ua();
request_with_new_ua();
sub request_with_new_ua {
say "make request";
my $ua = LWP::UserAgent->new;
$ua->ssl_opts(
verify_hostname => 0,
SSL_session_cache => Inline::SessionStore->new,
);
process_response($ua->get('https://localhost:4433'));
}
sub process_response {
my $res = shift;
say "> $_" for grep /Session|Master/, split /\n/, $res->as_string;
}
BEGIN {
package Inline::SessionStore;
use 5.20.1; use warnings;
use Moo;
use experimental qw(signatures);
use Sereal::Encoder;
use Sereal::Decoder;
use Try::Tiny;
use Path::Tiny;
has session_cache => ( is => 'rw' );
my $encoder = Sereal::Encoder->new;
my $decoder = Sereal::Decoder->new;
my $file = path('/tmp/ssl-session-cache');
sub get_session ($self, $key) {
say "get session $key";
my $cache;
try {
$cache = $decoder->decode($file->slurp_raw);
say "got cache from file, ".ref $cache;
} catch {
say $_ unless /No such file/;
$cache = IO::Socket::SSL::Session_Cache->new(128);
say "made new cache";
};
$self->session_cache($cache);
my $ret = $cache->get_session($key);
say "found session $ret" if $ret;
return $ret;
}
sub add_session {
my $self = shift;
say"add session " . join ' - ', @_;
my $session = $self->session_cache->add_session(@_);
$file->spew_raw($encoder->encode($self->session_cache));
return $session;
}
sub del_session {
my $self = shift;
say "del session " . join ' - ', @_;
$self->session_cache->del_session(@_);
$file->spew_raw($encoder->encode($self->session_cache));
}
1;
}
并输出:
rm -f /tmp/ssl-session-cache && perl wes.swp/workbench.pl make request get session localhost:4433 made new cache add session localhost:4433 - 23864624 > SSL-Session: > Session-ID: > Session-ID-ctx: 01000000 > Master-Key: DDF335492BFE2A7BA7674A656E72005865859D89249D597302F338D01C5776E2C94B61E6BCBED6114DFDA5AAEECD22EA make request get session localhost:4433 got cache from file, IO::Socket::SSL::Session_Cache found session 23864624 add session localhost:4433 - 23864624 # trying to re-add the session?? > SSL-Session: > Session-ID: > Session-ID-ctx: 01000000 > Master-Key: 4FE17B7FE9B4DE0A711C659FC333F686AD41840740B9D10E67A972D5A27D1720F0470329DA63DE65C1B023A1E2F0CC89 make request get session localhost:4433 got cache from file, IO::Socket::SSL::Session_Cache found session 23864624 add session localhost:4433 - 23864624 > SSL-Session: > Session-ID: > Session-ID-ctx: 01000000 > Master-Key: C76C52E5ECC13B0BB4FA887B381779B6F686A73DDFBEA06B33336537EC6AE39290370C07505BCD8B552CA874CD6E4089
我觉得我快要让它工作了,但我错过了一些东西。
最佳答案
我认为没有办法在进程之间使用 IO::Socket::SSL/Net::SSLeay 或 Crypt::SSLeay(它们是 LWP 的新旧 SSL 后端)。
您尝试在代码中使用的 session 缓存引用了 OpenSSL 库内部的 SESSION 对象。在 Perl 级别序列化缓存不会序列化 OpenSSL 库内部的部分,而只会包括指向内部结构的指针。由于这些指针仅对进程的当前状态有效,因此在不同的进程或进程状态中再次反序列化将导致悬空指针在最好的情况下指向任何地方或在最坏的情况下指向某些其他数据,从而导致段错误或内部数据损坏。
在 Net::SSLeay 中有 i2d_SSL_SESSION 和 d2i_SSL_SESSION 函数,理论上可以用来正确序列化 SESSION 对象。但我怀疑在当前的实现中是否可用。
关于perl - 如何在 Perl 进程之间共享 OpenSSL session ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47340354/