AWS Lambda を使ってサーバーサイド JavaScript (Node.js) で maxVersion: ‘TLSv1.2’ を指定している場合に ALB のセキュリティポリシーを変えたときの挙動を確認してみた

2024.04.16

いわさです。

最近、サーバーサイドで TLS 1.3 のみを許可した際にどれくらい影響出るものなのかなと考えることが多いです。
先日は Android ネイティブアプリケーションにおけるレガシークライアントのサポート状況を確認しました。

その延長で Web フロントエンドフレームワークの対応状況はどうなのかなと調べていました。
ALB のセキュリティポリシーは TLS 1.3 のみを許可しています。

クライアントサイド JavaScript の場合はブラウザエンジンバージョンに依存する

ブラウザ上で実行されるフロントエンドアプリケーションについては、そのままブラウザエンジンがサポートする TLS バージョンや暗号スイートにに依存しており、ネイティブアプリケーションのようにアプリケーションコード側 HTTP クライアントのオプションとして最大 TLS バージョンを指定したり、独自のセキュリティプロバイダーを使うなどは難しいということがわかりました。
フロントエンドアプリケーションの場合はXMLHttpRequestFetch APIが使用されますが、オプション指定は提供されていません。

つまり、フロントエンドアプリケーションについてはブラウザが TLS 1.3 をサポートするブラウザバージョンかどうかが重要になります(TLS バージョンだけでなく暗号スイートを意識する必要があるが)

サーバーサイド JavaScript の場合は独自指定している場合があるので注意

一方で、JavaScipt であれば TLS 1.3 が勝手に使われるのかというとそうではなく、例えば Lambda + Node.js ランタイムのようなサーバーサイド JavaScript の場合は最大 TLS バージョンを指定してしまっていないか気をつける必要があることがわかりました。

Node.js 10.x 以下ではデフォルトでは TLS 1.3 がサポートされていませんが、本日時点で AWS Lambda で新規関数の作成時に 10.x ランタイムバージョンは選択出来ません。
ただし、AWS Lambda でサポート期限切れのランタイムを実行し続けていたり、あるいは Lambda 以外の環境では古い Node.js バージョンを使用している可能性もあります。

また、Node.js の場合はクライアントのオプションとしていくつか最大 TLS バージョンを指定するオプションがあります。
最低 TLS バージョンの指定はたまに見ますよね。実際のケースとしてこの最大 TLS バージョンを意図的に使われているところを私は見たことがないのですが、明示的に最大バージョンが指定されている可能性はゼロではないので気にしておく必要があります。

次のコードは特に最大 TLS バージョンは指定せずに TLS 1.3 のエンドポイントへリクエストを送信するコードです。
ツギハギで実装したのでだいぶ適当です。

index.mjs

import https from 'node:https';

export const handler = async (event) => {
    const url = 'https://hoge0415.fuga.tak1wa.com/';

    return new Promise((resolve, reject) => {
        https.get(url, (res) => {
            let data = '';

            res.on('data', (chunk) => {
                data += chunk;
            });

            res.on('end', () => {
                console.log('Response:', data);
                resolve(`Successfully processed ${event.key}`);
            });
        }).on('error', (err) => {
            console.error('Error:', err);
            reject(err);
        });
    });
};

こちらは問題なくエンドポイントへ接続しレスポンスを受信出来ています。

一方で、次のように最大 TLS バージョン(ここではmaxVersion: TLSv1.2)を指定することが出来ます。

index.mjs

import https from 'node:https';

export const handler = async (event) => {
    const url = 'https://hoge0415.fuga.tak1wa.com/';

    return new Promise((resolve, reject) => {
        const options = {
            hostname: 'hoge0415.fuga.tak1wa.com',
            port: 443,
            path: '/',
            method: 'GET',
            maxVersion: 'TLSv1.2'
        };

        const req = https.request(options, (res) => {
            let data = '';

            res.on('data', (chunk) => {
                data += chunk;
            });

            res.on('end', () => {
                resolve(data);
            });
        });

        req.on('error', (err) => {
            console.error('Error:', err);
            reject(err);
        });

        req.end();
    });
};

この場合は同じエンドポイントに対するリクエストが失敗します。

さいごに

本日は Node.js で maxVersion: 'TLSv1.2' を指定した AWS Lambda 関数の挙動を確認してみました。

まとめると、インフラ管理者が TLS 1.3 のみを許可するようなセキュリティポリシーを適用する場合、フロントエンド JavaScript においてはブラウザバージョンを気にしておくこと、サーバーサイド JavaScirpt においては Node.js ランタイムバージョンと HTTP クライアントのオプションについて確認しておくと良いことがわかりました。
あまり多いケースではないのですが、リスクゼロではないという点を知っておくことはまぁ大事かなと。

今回調べていて、WebSocket クライアントはどうなのか?気にしなくていいのか?というのが気になり始めましたのでこのあたりも次回以降調べてみますね。