2026年7月9日

2026年7月9日

WordPressでファイルアップロードの種類を制限する方法・セキュリティ強化

はじめに

「悪意あるPHPファイルがアップロードされてサイトを乗っ取られた」「不審なファイルがメディアライブラリにアップロードされている」——WordPressのファイルアップロード機能は適切に制限しないと、攻撃者がWebシェル(バックドア)を設置するために悪用される危険があります。

症状・原因

WordPressはデフォルトで画像・PDF・動画など多くのファイル形式のアップロードを許可しています。しかし、ファイル拡張子の偽装や二重拡張子攻撃により、PHPスクリプトが実行可能な場所にアップロードされるリスクがあります。拡張子とMIMEタイプの両方を検証することが重要です。

解決手順

ステップ1:現在のアップロード設定を確認する

# 許可されているファイルタイプを確認
wp eval '
$types = get_allowed_mime_types();
foreach ($types as $ext => $mime) {
    echo $ext . " => " . $mime . "\n";
}
'

# アップロードディレクトリのPHPファイルを検索(不審なファイル確認)
find wp-content/uploads -name "*.php" -o -name "*.phtml" \
  -o -name "*.php5" -o -name "*.phar" 2>/dev/null

# アップロードディレクトリのパーミッションを確認
ls -la wp-content/uploads/

ステップ2:許可するファイルタイプを明示的に制限する

// functions.php:許可するMIMEタイプをホワイトリスト方式で制限
add_filter( 'upload_mimes', function( $mimes ) {
    // 許可するファイルタイプのみを残す(ホワイトリスト)
    $allowed = [
        'jpg|jpeg|jpe' => 'image/jpeg',
        'gif'          => 'image/gif',
        'png'          => 'image/png',
        'webp'         => 'image/webp',
        'svg'          => 'image/svg+xml',
        'pdf'          => 'application/pdf',
        'mp4|m4v'      => 'video/mp4',
        'mp3|m4a'      => 'audio/mpeg',
        'zip'          => 'application/zip',
        'doc'          => 'application/msword',
        'docx'         => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'xls'          => 'application/vnd.ms-excel',
        'xlsx'         => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    ];
    return $allowed;
} );

// 管理者のみSVGアップロードを許可する例
add_filter( 'upload_mimes', function( $mimes ) {
    if ( ! current_user_can( 'administrator' ) ) {
        unset( $mimes['svg'] ); // 管理者以外はSVG不可
    }
    return $mimes;
} );

ステップ3:MIMEタイプの実際の内容を検証する

// ファイルの実際のMIMEタイプを検証(拡張子偽装を防止)
add_filter( 'wp_check_filetype_and_ext', function( $data, $file, $filename, $mimes ) {
    if ( ! empty( $data['ext'] ) ) {
        return $data; // 既にWPが検証済み
    }

    // finfo_fileで実際のMIMEタイプを取得
    $finfo    = new finfo( FILEINFO_MIME_TYPE );
    $real_mime = $finfo->file( $file );
    $allowed  = get_allowed_mime_types();

    if ( in_array( $real_mime, $allowed, true ) ) {
        $ext = array_search( $real_mime, $allowed, true );
        $ext = explode( '|', $ext )[0];
        $data['ext']  = $ext;
        $data['type'] = $real_mime;
    }

    return $data;
}, 10, 4 );

// PHPファイルを偽装したアップロードをブロック
add_filter( 'wp_handle_upload_prefilter', function( $file ) {
    $dangerous_exts = [ 'php', 'php3', 'php4', 'php5', 'php7', 'phtml', 'phar', 'exe', 'sh', 'cgi' ];
    $ext = strtolower( pathinfo( $file['name'], PATHINFO_EXTENSION ) );

    if ( in_array( $ext, $dangerous_exts, true ) ) {
        $file['error'] = 'このファイル形式はアップロードできません。';
    }
    return $file;
} );

ステップ4:アップロードディレクトリでPHP実行を禁止する

# Nginxでuploadsディレクトリのスクリプト実行を禁止
location ~* /wp-content/uploads/.*\.(php|phtml|php5|phar|cgi|sh)$ {
    deny all;
    return 403;
}
# .htaccess(Apacheの場合)
<FilesMatch "\.(php|phtml|php5|phar|cgi|sh)$">
    Order Allow,Deny
    Deny from all
</FilesMatch>
# uploadsディレクトリに.htaccessを設置(Apache)
cat > wp-content/uploads/.htaccess << 'EOF'
<FilesMatch "\.(php|phtml|php5|phar|cgi|sh|py|rb|pl)$">
    Order Allow,Deny
    Deny from all
</FilesMatch>
EOF

# ディレクトリのパーミッションを適切に設定
chmod 755 wp-content/uploads/
find wp-content/uploads -type f -exec chmod 644 {} \;

ステップ5:アップロードサイズを制限する

// 最大アップロードサイズをロールごとに制限
add_filter( 'upload_size_limit', function( $size ) {
    if ( current_user_can( 'administrator' ) ) {
        return 50 * MB_IN_BYTES; // 管理者: 50MB
    }
    if ( current_user_can( 'editor' ) ) {
        return 10 * MB_IN_BYTES; // 編集者: 10MB
    }
    return 2 * MB_IN_BYTES; // その他: 2MB
} );
# php.ini でアップロードサイズを設定
# upload_max_filesize = 10M
# post_max_size = 12M
wp eval 'echo ini_get("upload_max_filesize");'

注意事項

  • SVGファイルはXSSを含む可能性があるため、信頼できるユーザーのみに許可し、アップロード後にDOMPurifyなどでサニタイズしてください。
  • upload_mimesフィルターはWordPressの管理画面のみに影響します。APIやWP-CLI経由のアップロードには別途検証が必要です。
  • ファイルアップロード制限を変更した後は、既存のプラグインがファイルをアップロードできるかテストしてください。

まとめ

ファイルアップロード制限は「許可タイプのホワイトリスト化→MIMEタイプ検証→Nginx/Apacheでスクリプト実行禁止→パーミッション設定」の多層防御で実装します。特にuploadsディレクトリのPHP実行禁止は必須設定です。関連記事:WordPressのXMLRPCを無効化する方法WordPressにセキュリティヘッダーを追加する方法

お気軽にご相談ください

お見積りへ お問い合わせへ