flawopen.com/path-traversal/Rust

● CWE-918 · 高
セキュリティ研究 · FlawOpen

脆弱性の解説:Path Traversal in Rust

How PathBuf::join allows directory escapes in Rust, and how to enforce containment using std::fs::canonicalize and starts_with.

💡 わかりやすい解説 (ELI5)

ホテルの客室カードリーダーが2階の部屋のみを開けるよう制限されている場面を例えに考えてみてください。もし宿泊客がドアのキーパッドに「../../master-safe」と入力すると、不備のある鍵が廊下を抜け出して支配人の金庫を直接解錠してしまいます。

主要な概念と専門用語

Web Application Security
主要概念 (Web Application Security):Core architecture component affected by CWE-918.
CWE-918
主要概念 (CWE-918):Standard Common Weakness Enumeration classification for path-traversal-rust.
Defense-in-Depth
主要概念 (Defense-in-Depth):Multi-layered engineering verification and runtime boundary isolation.

ステップ・バイ・ステップの攻撃フロー

Step 1

ファイルパス入力の受信

エンドポイントがHTTPリクエストパラメータからユーザー指定のファイル名やパスを受け取ります。

Step 2

ディレクトリトラバーサル記号の挿入

攻撃者が '../' や '..%2f' などの相対パス記号や絶対パス指定を挿入します。

Step 3

ベースディレクトリ境界の突破

バックエンドが正規化パスの検証を行わずに文字列を連結し、公開フォルダ外へのアクセスを許容します。

Step 4

機密ファイルの漏洩または上書き

OSが /etc/passwd や設定ファイルなどの重要ファイルを読み取り、攻撃者へ返却します。

ソースコード比較:脆弱 vs 堅牢化

✕ 脆弱な実装
// VULNERABLE: PathBuf::join allows directory traversal
use std::fs;
use std::path::PathBuf;

fn read_user_file(filename: &str) -> Result<Vec<u8>, std::io::Error> {
    let base_dir = PathBuf::from("/var/app/public/files");
    // Attacker input: "../../etc/passwd"
    let target = base_dir.join(filename);
    
    // Reads arbitrary system files!
    fs::read(target)
}
✓ 堅牢化されたセキュアパッチ
// HARDENED: Canonicalize path and assert directory prefix
use std::fs;
use std::path::{Path, PathBuf};
use std::io::{Error, ErrorKind};

fn read_user_file(filename: &str) -> Result<Vec<u8>, Error> {
    let base_dir = Path::new("/var/app/public/files").canonicalize()?;
    
    // 1. Join and canonicalize target path (resolves .. and symlinks)
    let target = base_dir.join(filename);
    let resolved = target.canonicalize()?;
    
    // 2. Strict boundary check: resolved must start with base_dir
    if !resolved.starts_with(&base_dir) {
        return Err(Error::new(ErrorKind::PermissionDenied, "Path traversal attempt detected"));
    }
    
    if !resolved.is_file() {
        return Err(Error::new(ErrorKind::NotFound, "File not found"));
    }
    
    fs::read(resolved)
}

エンジニアリング&システム堅牢化チェックリスト

References