Aikido

SQLでSELECT * を避ける方法:データ漏洩の防止

パフォーマンス

ルール
SQL クエリでの SELECT * の使用を 避ける
本番 コードでの SELECT *は、 アプリケーションを
スキーマ 変更に対して 脆弱にし、 データ 依存関係を 不明瞭にします。

対応言語: 45+

はじめに

使用 SELECT * 本番クエリでは、アプリケーションが使用しない列を含む、テーブルからすべての列を取得します。データベーススキーマが進化し、新しい列(パスワードやPIIなどの機密データを含む)が追加されると、使用するクエリは SELECT * コード変更なしで自動的にそれらを取得し始めます。これはセキュリティ脆弱性を生み出し、アプリケーションロジックの前提を崩します。

なぜ重要なのか

パフォーマンスへの影響: 不要なカラムの取得は、クエリ実行時間、ネットワーク転送サイズ、およびメモリ消費量を増加させます。50カラムあるテーブルで5カラムしか必要としない場合、必要以上の10倍のデータを転送していることになり、応答時間を低下させ、インフラコストを増加させます。

セキュリティへの影響: テーブルに追加された新しいカラム(監査フィールド、内部フラグ、機密性の高いユーザーデータ)は、~を通じて自動的に公開されます SELECT * クエリ。APIがパスワードハッシュ、SSN、またはそのエンドポイント向けではなかった内部ビジネスデータを漏洩し始める可能性があります。

コードの保守性: いつ SELECT * スキーマ変更後にクエリが破損し、コンパイル時ではなく実行時に障害が発生します。新しいNULL非許容列や名前変更されたフィールドは、本番環境でエラーを引き起こします。明示的な列リストは依存関係を明確にし、スキーマが非互換に変更された場合にビルドを中断させます。

コード例

❌ 非準拠:

async function getUserProfile(userId) {
    const query = 'SELECT * FROM users WHERE id = ?';
    const [user] = await db.execute(query, [userId]);

    return {
        name: user.name,
        email: user.email,
        createdAt: user.created_at
    };
}

誤っている理由: これは、password_hash、ssn、internal_notes、deleted_atなどの機密性の高い可能性のあるフィールドを含むすべての列を取得します。スキーマが成長するにつれて、このクエリは遅くなり、より多くのデータを公開しますが、アプリケーションは3つのフィールドしか使用していません。

✅ 準拠済み:

async function getUserProfile(userId) {
    const query = `
        SELECT name, email, created_at
        FROM users
        WHERE id = ?
    `;
    const [user] = await db.execute(query, [userId]);

    return {
        name: user.name,
        email: user.email,
        createdAt: user.created_at
    };
}

まとめ

SQLクエリでは、常に明示的なカラムリストを指定してください。これにより、データ漏洩を防ぎ、パフォーマンスを向上させ、コードとスキーマ間の依存関係を明確にします。カラム名を入力するというわずかな初期コストで、セキュリティとパフォーマンスに関するあらゆる種類の問題を未然に防ぐことができます。

よくある質問

ご質問がありますか?

SELECT * はいつ許容されますか?

開発中またはデバッグ中のアドホッククエリでのみ使用し、本番コードでは決して使用しないでください。すべての列が本当に必要なデータ移行スクリプトや単発レポートの場合、SELECT * は妥当です。アプリケーションコードの場合、現在すべての列が必要であっても、スキーマ変更は避けられないため、常に明示的な列リストを使用してください。

SELECT * クエリを生成するORMについてはどうですか?

Configure your ORM to select specific fields. Most ORMs (Sequelize, TypeORM, Prisma, SQLAlchemy) support field selection: User.findOne({ attributes: ['name', 'email'] }) or prisma.user.findUnique({ select: { name: true, email: true } }). Always use these options to control what data is retrieved.

SELECT * はデータベースのパフォーマンスに著しく影響しますか?

はい、特に幅の広いテーブルの場合に影響があります。データベースはディスクからより多くのページを読み取る必要があり、インデックスは効果的に使用できず、クエリ結果セットはデータベースバッファプールでより多くのメモリを消費します。ネットワーク転送時間はデータサイズに比例して増加します。TEXTまたはBLOB列を持つテーブルの場合、その影響は深刻になる可能性があります。

ほとんどの列が必要なクエリをどのように処理しますか?

それらを明示的にリストアップしてください。IDEのオートコンプリートを使用するか、information_schemaをクエリして列リストを生成してください。一部のチームでは、各ユースケースに必要な正確な列を定義するビューオブジェクトやデータベースビューを作成しています。明示的なリストの明確さと安全性は、わずかな不便さを上回ります。

コードベース内のSELECT *を検出するにはどうすればよいですか?

コードベースで「SELECT *」(大文字と小文字を区別しない)パターンを検索します。多くの静的解析ツールやデータベースクエリアナライザーは、これらを検出できます。コードレビュー中に、アプリケーションコードに「SELECT *」を含むPRを拒否します。一部のチームは、プリコミットフックやCIチェックを使用して、これらのパターンを自動的に検出およびブロックしています。

今すぐ、安全な環境へ。

コード、クラウド、ランタイムを1つの中央システムでセキュアに。
脆弱性を迅速に発見し、自動的に修正。

クレジットカードは不要です | スキャン結果は32秒で表示されます。