伝送暗号化 - ssl/tls

質問:

Workermanとの通信をどのように安全に保つことができますか?

回答:

比較的便利な方法は、通信プロトコルの上に一層のSSL暗号化層を追加することです。例えば、wssやhttpsプロトコルはすべてSSLに基づいて暗号化されており、とても安全です。Workermanは自らSSL(Workerman >= 3.3.7が必要)をサポートしており、属性を設定するだけでSSLを有効にできます。

もちろん、開発者は特定の暗号化および復号化アルゴリズムに基づいて独自の暗号化メカニズムを実装することもできます。

Workermanでsslを有効にする方法は以下の通りです:

準備作業:

  1. Workermanのバージョンは3.3.7以上であること

  2. PHPにopenssl拡張がインストールされていること

  3. 証明書(pem/crtファイルおよびkeyファイル)を申請し、/etc/nginx/conf.d/sslに配置していること

コード:

<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

// 証明書は申請した証明書が望ましい
$context = array(
    'ssl' => array(
        'local_cert'        => '/etc/nginx/conf.d/ssl/server.pem', // crtファイルも使用可能
        'local_pk'          => '/etc/nginx/conf.d/ssl/server.key',
        'verify_peer'       => false,
        'allow_self_signed' => true, // 自己署名証明書の場合はこのオプションを有効にする
    )
);
// ここではwebsocketプロトコルを設定していますが、httpプロトコルや他のプロトコルも可能です
$worker = new Worker('websocket://0.0.0.0:443', $context);
// transportをsslに設定
$worker->transport = 'ssl';
$worker->onMessage = function(TcpConnection $con, $msg) {
    $con->send('ok');
};

Worker::runAll();

Workermanでサーバー名表示SNI(Server Name Indication)を有効にすると、同一IPおよびポートで複数の証明書をバインドできます。

証明書を.pemと.keyファイルを結合する:

各証明書の.pemと対応する.keyファイルの内容を結合し、.keyファイルの内容を.pemファイルの末尾に追加します。(もし.pemファイル内に既に秘密鍵が含まれている場合は、無視可能です。)

注意点は、単一の証明書であり、すべての証明書を1つのファイルにコピーすることではありません。

例えばhost1.com.pemの結合後のpemファイルの内容はおおよそ以下のようになります:

-----BEGIN CERTIFICATE-----
MIIGXTCBA...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFBzCCA...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAA....
-----END RSA PRIVATE KEY-----

コード:

<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

$context = array(
    'ssl' => array(
        'SNI_enabled' => true, // SNIを有効にする
        'SNI_server_certs' => [ // 複数の証明書を設定
            'host1.com' => '/path/host1.com.pem', // 証明書1
            'host2.com' => '/path/host2.com.pem', // 証明書2
        ],
        'local_cert' => '/path/default.com.pem', // デフォルトの証明書
        'local_pk'   => '/path/default.com.key',
    )
);
$worker = new Worker('websocket://0.0.0.0:443', $context);
$worker->transport = 'ssl';
$worker->onMessage = function(TcpConnection $con, $msg) {
    $con->send('ok');
};

Worker::runAll();