Friction River Software

  • お問い合わせ

CakePHP5入門【CakePHP5実用編⑧】WebSocketの暗号化

A子

開発環境のWebサーバが「SSL/TLS」に対応したのは良いんだけどさ

「http」ではうまく動いてたのに、「https」では(WebSocket関連が)動かなくなっちゃったよ

B美

実は「http」環境では「ws」、「https」環境では「wss」がWebSocketのプロトコルになるのよ

要するに、「https」環境下ではWebSocket側も暗号化通信に対応させなきゃダメ…ってこと

C菜

修正作業って、結構難しいでしょうか~?

B美

そうでもないわよ

だってWebSocketライブラリである「Ratchetラチェット」には、暗号化(wss)対応のクラスがきちんと用意されてるもの

A子

だったら安心だね

んじゃ、まずは「src/Command」の中にある「WebSocketServerCommand.php」の変更から?

B美

そうね

まずは、先頭のuseするところなんだけど…
ここには、三行追加してね

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
use React\EventLoop\Factory as LoopFactory;
use React\Socket\Server as ReactServer;

use Ratchet\Server\SecureServer;
use React\Socket\SecureServer as ReactSecureServer;
use React\Socket\SocketServer;
赤字が追加箇所)

次に「execute」メソッドだけど、$contextという連想配列を用意して、それを引数に「SecureServer」のオブジェクトを生成
あとは、それを「IoServer」の引数に渡すだけ…

public function execute(Arguments $args, ConsoleIo $io): void
{
    $loop = LoopFactory::create();

    $context = [
        'local_cert' => '/home/bimi/ssl/server.crt', //サーバ証明書
        'local_pk' => '/home/bimi/ssl/server.key', //秘密鍵
        'allow_self_signed' => true,
        'verify_peer' => false
    ];


    $socket = new SocketServer(WEBSOCKET_IP.':'.WEBSOCKET_PORT);
    $secureServer = new ReactSecureServer($socket, $loop, $context);


    $server = new IoServer(new HttpServer(new WsServer($this)), $secureServer, $loop);

    $io->out('WebSocketサーバを起動しました。');
    $server->run();
}
赤字が追加・変更箇所)

あ、「server.crt」や「server.key」のパスを間違えないように!
(WebサーバであるApache2が参照しているのは「/etc/apache/ssl/」ディレクトリだけど、一般ユーザ権限ではそのディレクトリにアクセスできないからね)


C菜

B美部長のユーザホームに「ssl」というディレクトリを作って、その中に「サーバ証明書(server.crt)」や「秘密鍵(server.key)」をコピーしたということでしょうか~?

B美

そういうこと

A子

ちょっと待って!

軽く流さずに、詳しい手順を教えてよ(苦笑)

B美

仕方ないわねぇ
MATE端末」を開いたら

mkdir ssl[Enter]
cd ssl[Enter]
su[Enter]
cp /etc/apache2/ssl/server.crt .[Enter]
cp /etc/apache2/ssl/server.key .[Enter]
chown bimi:bimi *[Enter]
exit[Enter]

…って感じかしら
(当然だけど「bimi:bimi」の箇所は適宜変更してね)

あ、コピーコマンド(cp)の末尾の「.ドット」を忘れないように!

C菜

chownチェンジオーナー」って、ファイルの所有者を変更するコマンドでしたよね~

あ、あとViewビュー側も修正が必要なんでしょうか~?

B美

一ヶ所だけね
「templates/Chat」の中にある「index.php」のJavaScript部分なんだけど…

const ws = new WebSocket("wss://<?= WEBSOCKET_IP ?>:<?= WEBSOCKET_PORT ?>");
赤字が変更箇所)

つまり、プロトコルである「ws」の箇所を「wss」に変えるだけでOKよ

A子

ふむ
そこまで難しくはなかったね

C菜

いえ、「サーバ証明書」や「秘密鍵」のパスとして、(間違って)「/etc/apache2/ssl」ディレクトリを指定しちゃいそうです~

その場合、絶対に動きませんよね~?

B美

その通りよ

Linuxサーバにおいて、ファイルやディレクトリのパーミッション(の知識)がいかに重要か…ってことね

A子

な、なるほど
たしかに、気付けなかった場合、ドツボにハマるかもしれない…(苦笑)

あ、ちなみにそのパスを含んだファイル名の記述だけど、定数化しといたほうが良いと思うんだけど…
(本番環境への設置デプロイのためにも)

C菜

ですね~

「src/Command」の中にある「WebSocketServerCommand.php」、その「execute」メソッドを書き換えましょう~

public function execute(Arguments $args, ConsoleIo $io): void
{
    $loop = LoopFactory::create();

    $context = [
        'local_cert' => CERT_FILE,
        'local_pk' => PK_FILE,
        'allow_self_signed' => true,
        'verify_peer' => false
    ];

    $socket = new SocketServer(WEBSOCKET_IP.':'.WEBSOCKET_PORT);
    $secureServer = new ReactSecureServer($socket, $loop, $context);

    $server = new IoServer(new HttpServer(new WsServer($this)), $secureServer, $loop);

    $io->out('WebSocketサーバを起動しました。');
    $server->run();
}
赤字が変更箇所)

もちろん、「config/const.php」のほうにも以下の二行を追加するです~

define("CERT_FILE", "/home/bimi/ssl/server.crt");    //サーバ証明書
define("PK_FILE", "/home/bimi/ssl/server.key");    //秘密鍵



A子

うん
完璧じゃん