過剰なファイル読み取り・書き込み権限

他のユーザーが変更できるファイルを信頼して読む危険

説明

複数のユーザーが利用する環境で、すべてのユーザーに書き込みを許可したファイルは、他のユーザーに内容を変更される可能性があります。アプリケーションがそのファイルを信頼して読むと、設定やデータの改ざんによって動作を変えられるおそれがあります。設定ファイル、トークンや鍵のファイル、許可リストなどが変更されると、制御の無効化、意図しないパスの読み込み、外部への接続につながる場合があります。

想定される影響

  • 不正な設定や入力によるアプリケーション動作の変更
  • 設定や許可リストの改ざんによる機能の無効化、検査の回避、危険なオプションの有効化
  • 重要なファイルを空の内容や無効なデータで上書きされることによるサービス拒否
  • 認証やアクセス制御の回避、または権限昇格

対処方法

  • 全ユーザーへの書き込みを許可せず、POSIX権限やACLを必要な権限に設定してください。File.setWritable(true, true) を呼ぶだけでは、既存のグループや他のユーザーの書き込み権限は除去されません。
  • POSIXファイルシステムでは、Files.createFile や createTempFile に rw------- などの属性を渡し、作成時点から権限を制限してください。
  • 読み込む前に、所有者、実際の権限、内容の信頼性を確認してください。権限を減らしても、改ざん済みの内容は元に戻りません。権限変更の失敗を処理し、信頼できない既存ファイルは検証または置換してください。
  • 複数ユーザーの書き込みが必要な場合は、特定のグループやACLに限定してください。
  • 機密ファイルは所有者だけが変更できる信頼されたディレクトリに置き、シンボリックリンクを追跡しないオプションも検討してください。

例

変更前

java
import java.io.*;
import java.nio.file.*;

public class InsecureConfigReader {
    // 취약: 월드 쓰기 후 같은 파일을 신뢰하고 읽음
    public static String loadApiToken() throws Exception {
        File f = new File("/var/app/config/token.txt");
        if (!f.exists()) {
            f.getParentFile().mkdirs();
            f.createNewFile();
        }
        // 잘못된 권한: 모든 사용자에게 쓰기 허용
        f.setWritable(true, false); // world-writable

        try (BufferedReader br = new BufferedReader(new FileReader(f))) {
            return br.readLine(); // 공격자가 바꾼 내용을 그대로 신뢰
        }
    }
}

変更後

java
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.Set;

public class SecureConfigReader {
    public static String loadApiToken() throws Exception {
        Path path = Paths.get("/var/app/config/token.txt");
        Files.createDirectories(path.getParent());

        // 1) POSIX 권한을 소유자 전용으로 강제 (rw-------)
        Set<PosixFilePermission> ownerOnly = PosixFilePermissions.fromString("rw-------");
        if (Files.notExists(path)) {
            Files.createFile(path, PosixFilePermissions.asFileAttribute(ownerOnly));
        } else {
            // 기존 파일이라면 Others/Group 쓰기 제거
            Files.setPosixFilePermissions(path, ownerOnly);
        }

        // 2) 추가 방어: JVM File API로도 world write 제거 후, 소유자 쓰기만 허용
        File f = path.toFile();
        f.setWritable(false, false); // group/others 쓰기 제거
        f.setWritable(true, true);   // owner만 쓰기 허용

        try (BufferedReader br = Files.newBufferedReader(path)) {
            return br.readLine();
        }
    }
}

解説:

  • 変更前: 全ユーザーへの書き込みを許可したファイルを、そのまま信頼して読み込んでいます。他のユーザーによる上書きが、設定の変更やサービス障害につながるおそれがあります。
  • 変更後: POSIX権限を rw------- に設定し、グループや他のユーザーの読み取りと書き込みを制限します。信頼できる所有者と親ディレクトリが前提です。パスを置換されないように保護し、既存ファイルは権限を変更しただけで内容まで信頼しないでください。

参考資料