SV.DATA.FILE

潜在的に有害なファイルがアップロードされ、自動的に処理される可能性があります

リリース 2023.2 の時点で、このチェッカーは Jakarta EE をサポートしています。

脆弱性とリスク

特定の拡張子が付いたファイルは、特定の環境で自動的に処理される可能性があり、それらのファイルがチェックされていない場合、攻撃者は悪意のあるファイルを挿入できます。

軽減と防止

次のようなプラクティスを実装します。
  • 可能であれば、アップロードしたファイルを Web ルートディレクトリの外部に保存します。
  • アップロードされたファイルにはランダムに生成されたファイル名を使用します。
  • ファイル名に拡張子が 1 つだけ使用されていることを確認してください。htm ファイルのアップロードを許可する場合は、クロスサイトスクリプティングの可能性を検討してください。
  • 大文字と小文字を区別しないシステムでは、ファイル拡張子が大文字と小文字を区別せずに評価されることを確認してください。
  • ファイルをアップロードする前に、ファイルの MIME タイプが正しいことを確認してください。ただし、MIME タイプだけを当てにしないでください。
  • 可能であれば、アップロードディレクトリから直接アクセスできるのは、許可された拡張子が付いたファイルだけであることを確認してください。たとえば、ディレクトリにイメージのみを含める必要がある場合は、ディレクトリ内の PHP/ASP ファイルへのアクセスを制限します。

脆弱コード例 1

コピー
import javax.servlet.http.*;
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
    String pLine = br.readLine();
    String filename = pLine.substring(pLine.lastIndexOf("\\"), pLine.lastIndexOf("\""));
    BufferedWriter bw = new BufferedWriter(new FileWriter(UPLOAD_DIRECTORY_STRING + filename, true));  // <- Defect detected here because of a new file been created with tainted name
   
    for (String line; (line=br.readLine())!=null; ) {
      if (line.indexOf(boundary) == -1) {
        bw.write(line);
        bw.newLine();
        bw.flush();
      }
   }
    bw.close();
  }

この例では、Klocwork は 6 行目で SV.DATA.FILE の欠陥を報告し、「潜在的に有害なファイルがアップロードされ、自動的に処理される可能性があります」を示します。ファイルの内容と名前の両方をリクエストから受け入れるので、攻撃者はファイル拡張子を指定でき、それに応じて自動的に処理される可能性があります。危険なファイル拡張子には、.exe、.py、.php などがあります。

修正コード例 1

コピー
import javax.servlet.http.*;
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
    String pLine = br.readLine();
    String filename = UUID.randomUUID().toString();
    BufferedWriter bw = new BufferedWriter(new FileWriter(UPLOAD_DIRECTORY_STRING + filename, true));
     
    for (String line; (line=br.readLine())!=null; ) {
        if (line.indexOf(boundary) == -1) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
    }
    bw.close();
 }

SV.DATA.FILE の欠陥を克服する簡単な方法は、拡張子を付けないでファイル名を割り当てることです。ファイル名はランダムに生成された UUID に設定されるので、Klocwork は欠陥をもはや報告していません。

脆弱コード例 2

コピー
import jakarta.servlet.http.*;
 public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
   //get the file chosen by the user
   Part filePart = request.getPart("fileToUpload");
  
   //get the InputStream to store the file somewhere
   InputStream fileInputStream = filePart.getInputStream();
  
   //for example, you can copy the uploaded file to the server
   File fileToSave = new File("fileName.exe");
   Files.copy(fileInputStream, fileToSave.toPath(), StandardCopyOption.REPLACE_EXISTING); // Detect defect here because: filename is dangerous and content is from user request
 }

この例では、Klocwork は 11 行目で SV.DATA.FILE の欠陥を報告し、「潜在的に有害なファイルがアップロードされ、自動的に処理される可能性があります」を示します。コードは、ファイルの内容をリクエストから実行可能ファイルに直接コピーしています。このリクエストは自動的に処理されるか、後で意図的に実行される可能性があり、ファイルの拡張子が変更または削除される可能性があります。

修正コード例 2

コピー
import jakarta.servlet.http.*;
 public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
     //get   the file chosen by the user
     Part filePart = request.getPart("fileToUpload");
  
     //get the InputStream to store the file somewhere
     InputStream fileInputStream = filePart.getInputStream();
  
     //for example, you can copy the uploaded file to the server
     File fileToSave = new File(UUID.randomUUID().toString());
     Files.copy(fileInputStream, fileToSave.toPath(), StandardCopyOption.REPLACE_EXISTING);
 }

この場合でも、最も簡単な解決策は拡張子なしで生成された名前をファイルに付けることであるため、Klocwork は欠陥をまはや報告していません。

関連チェッカー

拡張機能

このチェッカーは、Klocwork knowledge base (ナレッジベース) を利用して拡張できます。詳細については、Java 解析のチューニングを参照してください。