Bard、ChatGPT、Bing Chat などの人工知能ツールは、現在増加傾向にある大規模言語モデル (LLM)カテゴリの主要なツールです。
LLM は、日常の人間の言語をチャット プロンプトとして使用してコミュニケーションできるように、膨大なデータ セットでトレーニングされています。 LLM の柔軟性と可能性を考慮して、企業は私たちの生活をより良く、より簡単にするために、テクノロジー業界内の多くのワークフローに LLM を統合しています。 AI とワークフローの主な統合の 1 つは、オートコンプリート コード プラグインであり、より迅速かつ効率的にコードを作成するために、一致するコード パターンを予測して生成する機能を提供します。
AI コード生成ツールの現在の市場には、 GitHub Copilot 、 Amazon CodeWhisperer 、 Google Cloud Code (Duet AI) 、 Blackbox AI Code Generationなど、多くのプレーヤーが存在します。このブログ投稿では、開発者がこのようなツールを使用する際に直面する一般的なセキュリティ上の落とし穴の例を概説します。
この記事の目的は、自動生成されたコードは盲目的に信頼することはできず、ソフトウェアの脆弱性の導入を避けるためにセキュリティ レビューが必要であるという認識を高め、強調することです。
注: 一部のベンダーは、オートコンプリート ツールに安全でないコード スニペットが含まれている可能性があると示唆しています。
オートコンプリート ツールがIDOR 、SQL インジェクション、XSS などの既知の脆弱性を生成することは、多くの記事ですでに強調されています。この投稿では、AI オートコンプリートによってコードにバグが紛れ込む可能性が高い、コードのコンテキストに依存する他の脆弱性タイプに焦点を当てます。
セキュリティおよび AI コード生成ツールコード用にトレーニングされた AI モデルは、通常、機能するコードを生成するという主な使命を持った大規模なコード ベースでトレーニングされます。
多くのセキュリティ問題には、パフォーマンス面を損なうことなく軽減する既知の定義された方法があります (たとえば、ユーザー入力/パラメータを直接クエリに連結しないことで SQL インジェクションを回避できます)。したがって、安全でない方法でコードを記述します。
ただし、多くのセキュリティ問題はコンテキストに依存しており、内部機能として実装されている場合は完全に安全ですが、クライアントからの外部入力に直面すると脆弱性になるため、AI の学習データセットを通じて区別するのは困難です。
このような脆弱性では、コードの具体的な使用法は通常、コードの他の部分とアプリケーションの全体的な目的に依存します。
以下に、私たちがテストした一般的な使用例と例を示し、これらのタイプの脆弱性のいくつかを示します。
AI コード生成ツールが上記のケースをどのように処理するかを確認した後、適切なセキュリティ フィルターやその他の緩和メカニズムを作成する機能をテストしようとしました。
以下に、安全なコードを意図的にリクエストしてテストした一般的な使用例と例をいくつか示します。
多くのアプリケーションには、ファイル名に基づいてファイルを取得してユーザーに返すコードが含まれています。サーバー上の任意のファイルを読み取るためにディレクトリ トラバーサルを使用することは、悪意のある者が不正な情報を入手するために使用する一般的な方法です。
ファイルを取得して戻す前に、ユーザーからのファイル名/ファイル パス入力をサニタイズするのは明白に思えるかもしれませんが、汎用コードベースでトレーニングされた AI モデルにとっては難しい作業であると想定しています。これは、一部のデータセットではサニタイズする必要がないためです。サニタイズされたパスを機能の一部として使用するか (パフォーマンスが低下したり、機能に悪影響を与える可能性もあります)、または内部使用のみを目的としているため、サニタイズされていないパスによって悪影響を受けることはありません。
AI ツールの提案 (Google Cloud Code - Duet AI): Google Cloud Code - Duet AI オートコンプリートを使用して、ユーザー入力から基本的なファイル取得関数を生成してみましょう。 Duet AI に関数とルート名に基づいてコードを自動補完させます -
灰色で見られるように、オートコンプリートの提案は、Flask の基本的なファイル処理関数である Flask の「 send_file 」関数を使用することです。
しかし、Flask のドキュメントにも「ユーザーが提供したファイル パスを決して渡さない」と記載されています。これは、ユーザー入力を「send_file」関数に直接挿入している間、ユーザーは、たとえばディレクトリ トラバーサル文字を使用することによって、ファイル システム上の任意のファイルを読み取ることができることを意味します。ファイル名の「../」など。
適切な実装:
「send_file」関数を Flask の安全な「send_from_directory」関数に置き換えることで、ディレクトリ トラバーサルのリスクが軽減されます。特定のハードコーディングされたディレクトリ (この場合は「エクスポート」) からのファイルのフェッチのみが許可されます。
PHP や NodeJS などの一部のプログラミング言語では、2 つの異なる型の変数を比較することができ、プログラムはバックグラウンドで型変換を実行してアクションを完了します。
疎比較では変数の型がバックグラウンドでチェックされないため、型ジャグリング攻撃を受けやすくなります。ただし、緩い比較の使用自体は安全でないコーディング手法とはみなされません。それはコードのコンテキストによって異なります。また、AI モデルがケースを区別することは困難です。
AI ツールの提案 (Amazon CodeWhisperer): PHP 型ジャグリングの最も一般的な例は、JSON リクエスト (入力の型の制御を可能にする) 経由で読み取られたユーザー入力が緩い比較 (「 」)に達する、シークレット トークン/ハッシュの緩い比較です。 ) 厳密なもの (「=」) の代わりに。
ご覧のとおり、CodeWhisperer はオートコンプリート候補で緩やかな比較条件を生成します。
Secret_token の緩やかな比較により、敵対者は $data[“secret_token”] == “secret_token” の比較を回避できます。 「secret_token」の値が True (ブール値) の JSON オブジェクトを送信すると、(新しい PHP バージョンであっても)緩やかな比較結果も True になります。
チェックを「安全に」書くようにツールに(コメントを使用して)「ヒント」を与えた場合でも、厳密な比較を含むコード スニペットは生成されませんでした。
適切な実装:
厳密な比較 (「===」) を指定した場合にのみ、型ジャグリング攻撃から保護されます。
「パスワードを忘れた場合」メカニズムの脆弱性は SaaS アプリケーションで非常に一般的であり、次のような CVE の背後にある根本原因でした。
具体的には、Unicode Case Mapping Collision の脆弱性は、ユーザー入力が比較式で大文字または小文字のいずれかであり、その元の値もコード内で使用されている場合に発生します。一部の異なる文字は、変換すると同じ文字コードになります。たとえば、「ß」と「SS」は両方とも大文字にすると「0x00DF」に変換されます。
このようなケースは通常、比較チェックを騙し、後で予想とは異なる元の値を使用することで、一部のセキュリティ チェックをバイパスしたり誤解を招くために使用されます。このようなケースは、特に多数の実装が可能な場合には、把握するのが非常に困難です。
AI ツールの提案 (GitHub Copilot):このタイプの脆弱性の影響を特に受けやすいメカニズムは、パスワードを忘れた場合のメカニズムです。望ましくない不一致を避けるために、チェックを実行するときに、ユーザーの入力 (電子メール アドレスまたはドメイン名) を大文字または小文字に正規化するのが一般的です。
例として、パスワードを忘れた場合の Copilot 生成コード (以下) を見ると、この問題に対して脆弱であることがわかります。
Copilot のコードは、まず小文字の電子メール アドレスを検索します。
その後、残りのプロセスを実行すると、次のことが提案されます。
ご覧のとおり、オートコンプリートの提案はランダムなパスワードを生成し、ユーザーの電子メール アドレスに送信します。ただし、最初はユーザー アカウントを取得するためにユーザーの電子メールの小文字バージョンが使用され、その後、元のユーザーの電子メールが「そのまま」 (小文字変換なしで) 回復電子メールのターゲットとして使用され続けます。
たとえば、攻撃者が「[email protected]」(「K」はケルビン記号のUnicode 文字)の受信トレイを所有しており、この電子メールを「パスワードを忘れた場合」メカニズムに使用しているとします。電子メール「[email protected]」と「[email protected]」は「そのままでは」同等ではありませんが、小文字に変換すると -
電子メール アドレス「[email protected]」を使用すると、「[email protected]」のアカウント情報が取得されますが、リセットされたパスワードが攻撃者の受信箱 (「[email protected]」) に送信され、「」の乗っ取りが可能になります。 [email protected]」アカウント。
適切な実装:ユーザー アカウントの取得に使用される電子メール アドレスは、回復用電子メール アドレスと正確に一致する必要があります (つまり、send_email パラメーターも email. lower() を使用します)。
また、予防措置として、ユーザーが指定した値ではなく、サーバーにすでに保存されている値を使用することをお勧めします。
オートコンプリート ツールを混乱させる可能性のあるもう 1 つのトピックは、特に複雑なクラウド インフラストラクチャ向けの構成ファイルの作成です。
主な理由は、確かにセキュリティのベスト プラクティス ガイドラインは存在しますが、誰もがそれに従うわけではなく、場合によってはそれに反する必要があるためです。このようなコード サンプルは、AI トレーニング データセットに組み込まれる可能性があります。その結果、一部のオートコンプリート出力は、推奨されるセキュリティ ガイドラインに違反します。
次の例では、Kubernetes の最小の実行単位であるKubernetes Podの構成ファイルを作成します。
AI ツールの提案 (ブラックボックス AI コード生成):この例では、ポッド構成ファイルの作成を開始します。
この提案では、機能セクションを作成し、Linux カーネル機能 (SYS_ADMIN) をコンテナーに追加します。これは、root ユーザーとしてポッドを実行するのと本質的に同等です。
適切な実装: securityContext を単に省略した方がよいでしょうか?いいえ、他の多くの機能がデフォルトで追加されるため、最小特権の原則に違反します。
Docker セキュリティのベスト プラクティスによると、最も安全な設定は、最初にすべての Linux カーネル機能を削除し、その後でコンテナに必要な機能を追加することです。
上記の問題を修正するために、機能セクションではすべての機能を削除することから始めて、コンテナに必要な機能を徐々に追加していきます。
ユースケース: 構成オブジェクト - 安全でない逆シリアル化につながる不整合
多くの脆弱性では、アプリケーションが必要なコンポーネントを処理する方法を決定する構成オブジェクトを定義する必要があります。
私たちが選択した例は、C# のNewtonsoft の JSON逆シリアル化ライブラリです。これは、 JsonSerializerSettings オブジェクトの構成、特にTypeNameHandlingに応じて、安全に使用することも、安全に使用しないこともできます。
逆シリアル化コードをテストしているときに、構成オブジェクトの定義が非常にランダムであり、微妙な変更により異なる構成セットが生成される可能性があることに気付きました。
AI ツールの提案 (Amazon CodeWhisperer):次の例は、開発者が使用したメソッド名のみに基づいた一貫性のない動作を示しています。
2 つの異なる構成があり、どちらも TypeNameHandling プロパティが「Auto」と「ALL」であるため、安全でない JSON 逆シリアル化が発生することがわかります。これらのプロパティにより、JSON ドキュメントで逆シリアル化されたクラスを定義できるようになり、攻撃者が任意のクラスを逆シリアル化できるようになります。これは、たとえばクラス「System.Diagnostics.Process」を逆シリアル化することによって、リモート コード実行に簡単に利用できます。開発者の元のコードとの唯一の違いはメソッド名です。
適切な実装:
デフォルトでは、JsonSerializerSettings オブジェクトは「TypeNameHandling = TypeNameHandling.None」でインスタンス化され、安全であるとみなされます。したがって、安全な TypeNameHandling 値を生成する JsonSerializerSettings のデフォルト コンストラクターを使用します。
AI ツールの提案 (GitHub Copilot):
セキュリティ チェックは非常に単純で、ディレクトリ トラバーサルの試行に必要なドット、ドット、スラッシュのシーケンスを回避するだけであることがわかります。 path パラメータには、システム上の任意のパス (/etc/passwd など) を指す絶対パスを指定できますが、これではセキュリティ チェックの目的が無効になります。
適切な実装:
ここで、 secure_file_read 関数は、ファイル名が存在する (エスケープすべきではない) ディレクトリ (safe_dir) とともに (相対) ファイル名パラメータを取得します。これは、safe_dir と filename を結合することによって絶対パスを作成し、realpath を呼び出して正規化された形式を取得します。次に、safe_dir フォルダーの正規化された形式を取得します。その後、正規化されたパスが正規化されたsafe_dirで始まる場合にのみ、ファイルの内容が返されます。
AI ツールの提案 (ブラックボックス AI コード生成):次の例では、AI オートコンプリーターに、危険なファイル拡張子のフィルター処理を行う関数を生成するように依頼しました。
推奨される Python コードは、ファイル名を取得し、拡張子を分離し、それを危険な拡張子のリストと比較します。
一見すると、このコード スニペットは安全であるように見えます。ただし、 Windows のファイル名の規則では、ドットで終わるファイル名は禁止されており、ファイル作成時にドット (「.」) で終わるファイル名を指定すると、ドットは破棄されます。つまり、悪意のある拡張子の後にドットが付いているファイル (例: 「example.exe.」) を送信すると、生成されたフィルターが Windows 上でバイパスされる可能性があります。
適切な実装:通常、より良いアプローチは、許可された拡張子に対してのみファイル拡張子をチェックするホワイトリストを使用することです。ただし、このツールはブラックリスト アプローチ (場合によっては必要) を採用しているため、より安全なブラックリストの実装について概説します。
次のスニペットでは、英数字以外のすべての文字から拡張子を取り除き、それを新しく生成されたファイル名に連結することで、ユーザーが入力に対して持っていた制御をできるだけ取り除きます。
結論 - 使用には注意が必要です 自動コプログラマーは、アイデアの提案、コードの自動完成、ソフトウェア開発プロセスのスピードアップに最適です。これらのツールは時間の経過とともに進化し続けると予想されますが、現時点では、この投稿の使用例で示されているように、オートコンプリート AI ソリューションには、私たちが心を落ち着かせてその出力を再確認せずに信頼できるようになるまで、克服しなければならない多くの課題があります。バグ。
脆弱性が発生する可能性を減らすために考えられる方法は、AI コード生成ツールに安全なコードの生成を意図的に要求することです。これは一部のユースケースでは便利ですが、確実ではありません。「一見安全な」出力も、ソフトウェア セキュリティに精通した人が手動でレビューする必要があります。
JFrog Security Research Team の推奨事項ソフトウェアを保護するには、AI 生成ツールによって生成されたコードを手動でレビューすることと、脆弱性を確実に発見できる静的アプリケーション セキュリティ テスト (SAST) などのセキュリティ ソリューションを組み込むことの両方をお勧めします。上記の例に見られるように、SAST ツールは、使用例 #3 で説明した Unicode ケース マッピングの衝突を警告して捕捉できます。このプロアクティブなアプローチは、ソフトウェアのセキュリティを確保するために不可欠です。
JFrog Security Research の最新情報を入手するセキュリティ研究チームの発見と研究は、JFrog プラットフォームのアプリケーション ソフトウェアのセキュリティ機能を向上させる上で重要な役割を果たしています。
JFrog Security Research チームからの最新の発見と技術アップデートについては、当社の研究 Web サイトおよび X @JFrogSecurityでフォローしてください。