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にセキュリティヘッダーを追加する方法。