MariaDB Connector/Node.js: SET句の展開におけるオブジェクトキーからのSQLインジェクションの脆弱性 (permitSetMultiParamEntries)
### 説明
デフォルト以外のpermitSetMultiParamEntriesオプションが有効になっている場合、クエリパラメータとして渡されたオブジェクトがSET句に展開され、各キーがカラム名になります。その展開を実装する3つのコードパスでは、バッククォートで囲まれた識別子を手動で構築し、キーをエスケープせずに書き込んでいましたが、値のみがエスケープされていました。
したがって、バッククォートを含むキーは識別子を閉じ、残りのキーはSQLとして解析されていました。コネクタ自体の識別子エスケープ関数 (escapeId、これは正しくバッククォートを2倍にする) は存在しましたが、3つのいずれの箇所からも呼び出されていませんでした。これは、GitHub issue #252に対する不完全な修正であり、2023年にescapeId自体は修正されましたが、手動で構築された呼び出し箇所は変更されていませんでした。
### 影響
permitSetMultiParamEntriesを有効にし、攻撃者が操作したキーを持つオブジェクトを、例えばconn.query('UPDATE users SET ? WHERE id = ?', [body, id])のようなステートメントに渡すと、アプリケーションが意図していないカラム(ロール、残高、またはパスワードカラムなど)を書き込むことができ、また、任意のSQLをステートメントに追加することができます。これは、注入されたテキストが代入に限定されないためです。
この脆弱性が顕在化するには、オプションを有効にする必要があります。デフォルトでは無効になっており、無効になっている場合はオブジェクトが単一の文字列リテラルとしてシリアライズおよびエスケープされるため、キーはSQLの構文に到達しません。ただし、リクエストボディをこのAPIに渡すことが、このオプションを有効にする一般的な理由です。permitSetMultiParamEntriesを有効にすることは、キーをカラム名として使用することを意図しており、キーを任意のSQLとして使用することを意図しているわけではありません。
### 修正
3つの展開箇所すべてで、キーが識別子エスケープ関数を経由し、カラム名を書き込む前にバッククォートが2倍になるように修正されました。この変更により、予約語を含む正当なキーについては、機能は変更されません。
### 対策
permitSetMultiParamEntries機能を無効にする(デフォルト設定)、または、query()関数に渡す前に、オブジェクトのキーをカラム名の許可リストと照合して検証する。ただし、これはアップグレードするまでの間の一時的な対応です。
### 報告者
fg0x0氏
影響を受けるパッケージ:
- npm (JavaScript) mariadb: 影響を受けるバージョンは3.2.0以上、3.2.5未満。3.2.5で修正済み。
- npm (JavaScript) mariadb: 影響を受けるバージョンは3.3.0以上、3.3.4未満。3.3.4で修正済み。
- npm (JavaScript) mariadb: 影響を受けるバージョンは3.4.0以上、3.4.7未満。3.4.7で修正済み。
- npm (JavaScript) mariadb: 影響を受けるバージョンは3.5.0-rc.0以上、3.5.4未満。3.5.4で修正済み。