0 Comments

昨今、巷ではPHPの不具合やらサーバーがハックされ情報の流失があった等の情報で賑わっています。
個人サーバーならPHPのセキュリティパッチの適用が最も早くて簡単です。早めにアップデートしましょう。
さて、AIさんが教えてくれたPHPの実際の危険な記述例と安全な書き方の例をご紹介しましょう。

PHPの実際の危険な記述例と安全な書き方の例

1. SQLインジェクション対策(データベース操作)

外部から受け取った入力値(GET/POSTなど)を、そのままSQL文に埋め込むような記述をしていると、データベースの全権限を奪われたり、データが書き換え・削除されたりします。

❌危険な記述例:

// ユーザーからの入力を直接SQL文に埋め込んでいる(非常に危険)
$user_id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = " . $user_id;
$result = $db->query($sql);

⭕安全な記述例(プリペアドステートメントの利用):

// プレースホルダー(? または :id)を使い、値とSQL構造を完全に分離する
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
$result = $stmt->fetchAll();

2. リモートファイルインクルード(RFI) / ローカルファイルインクルード(LFI)対策

画面の切り替えなどで、URLパラメータの文字列をそのまま include や require 関数に渡していると、外部の悪意あるスクリプトやサーバー内の機密ファイル(/etc/passwd など)を勝手に読み込まれて実行されてしまいます。

❌危険な記述例:

// GETパラメータをそのまま読み込んでいる
$page = $_GET['page'];
include($page . '.php');

⭕安全な記述例(ホワイトリスト方式の採用):

// 許可するファイル名(ホワイトリスト)をあらかじめ定義し、それ以外は弾く
$allowed_pages = [
    'home' => 'home.php',
    'about' => 'about.php',
    'contact' => 'contact.php'
];

$page = $_GET['page'] ?? 'home';

if (array_key_exists($page, $allowed_pages)) {
    include($allowed_pages[$page]);
} else {
    include('404.php');
}

3. クロスサイトスクリプティング(XSS)対策

ユーザーが入力した内容を、そのまま画面に出力していると、悪意あるJavaScriptコード(Cookieを盗むスクリプトなど)をブラウザ上で実行されてしまいます。これ結構やらかしやすいです。過去に私もやってます。

❌危険な記述例:

// ユーザーの入力をそのまま出力している
echo "ようこそ、" . $_POST['username'] . "さん";

⭕ 安全な記述例(出力時のエスケープ処理):

// htmlspecialchars() を用いてHTMLタグとして機能しないように無害化する
echo "ようこそ、" . htmlspecialchars($_POST['username'], ENT_QUOTES, 'UTF-8') . "さん";

  ※ポイントは「入力時ではなく出力時にエスケープすること」です。

4. ファイルアップロード機能の厳格化

画像やファイルのアップロード機能を自作している場合、拡張子のチェックが甘いと、拡張子を偽ったPHPファイルをアップロードされ、それをサーバー上で直接実行されて完全に乗っ取られるケースがあります

❌ 危険な記述例:

// ユーザーが送信したファイル名をそのまま保存し、実行権限のある場所に置いている
move_uploaded_file($_FILES['upfile']['tmp_name'], './uploads/' . $_FILES['upfile']['name']);

⭕ 安全な対策のポイント:

  1. ファイル名をハッシュ値(ランダムな文字列)に変更する(元ファイル名で保存しない)。
  2. 拡張子とMIMEタイプを厳格にチェックする(画像であっても中身がPHPコードになっていないか確認する)。
  3. アップロード先ディレクトリの実行権限(PHPなどのスクリプト実行)を無効化する(Apacheなら .htaccess で php_flag engine off や、Nginxであれば該当ディレクトリでのスクリプト実行を禁止する設定を入れる)。

5. その他の基本設定(php.ini やエラー出力)

  • エラーを画面に直接表示させない:
    開発中のデバッグ画面で、サーバーの内部パスやデータベース構造が露出するのを防ぐため、本番環境ではエラーを画面に出さず、ログファイルに出力するように設定します。
    display_errors = Off
    log_errors = On
  • 危険な設定の無効化:
    allow_url_fopen = Off
    allow_url_include = Off (外部URL経由でのファイル読み込みやインクルードを完全に遮断します)

個人サーバーの運営においては、最新バージョンへのこまめな追従(アップデート)を大前提としつつ、こうした「外部からの入力を一切信用しない(プリペアドステートメント、エスケープ、ホワイトリスト制御)」という実装の徹底が最大の自衛策となります。