私は PostgreSQL と通信する比較的小さなアプリケーションを開発していますが、SQL インジェクションに対する保護に関しては、どこまで行き過ぎているかについてフィードバックを得たいと考えていました。
アプリケーションは Perl であり、ORM モジュール (DBI のみ) を使用しません。SQL ステートメントは、プレースホルダーを使用して一般的な方法で構築されます。
my $sql = "SELECT * FROM $cfg->{tablename} WHERE foo = ?";
my $sth = $dbh->prepare($sql);
$sth->execute('bar');
テーブル名が補間される理由は、アプリケーションが複数のテーブルに対して同じ操作を実行する必要があるためです。これらのテーブルにはすべて「foo」列があります。
? の使用 placeholder は、ほとんどの単純な SQL インジェクション攻撃から保護します。私の質問は、プレースホルダーを使用できないテーブル名に関するものです。テーブルは構成ファイルから取得されますが、アプリは代替構成ファイルを使用する --configfile スイッチをサポートしています。
データベース資格情報は構成ファイルに保存されます。そのため、攻撃者が $cfg->{tablename} を悪意のあるものに置き換えた構成ファイルを作成する (または既定のファイルを置き換える) ことができる場合、アプリケーションは「だまされて」悪意のあるコードを実行される可能性があります。
攻撃者がこれを行うには、有効なデータベース資格情報を既に持っている必要があります。そうでない場合、アプリケーションは接続できません。資格情報を持っている場合、DBI を使用して独自のコードを作成するか、psql cli を使用して悪意のあることを行うことができます。
これを防ぐには、次の 2 つの方法が考えられます。
- ORM に切り替えます。この場合、$orm->get_class_for_table($cfg->{tablename} の順序で何かを行うことになります。
- SQLステートメントを準備する前に、正規表現を使用してテーブル名をサニタイズします
- $dbh->quote_identifier() を使用
明らかに 2 番目の方法は「安くて楽しい」方法です。しかし、上記の資格情報に関する声明を考えると、これらのアプローチのいずれかが本当に正当化されるのでしょうか? 攻撃者に別の攻撃ベクトルを使用するように強制することになると、どのくらいの労力がかかりすぎますか (実際に攻撃を防ぐ努力とは対照的に?)