【実務・中級編】 Linuxにおけるファイルシステム権限の最小化とImmutable属性の付与 – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

サーバーの「心臓部」を守る:chattrとスティッキービットで実現する鉄壁のハーデニング

現場でインシデント対応をしていると、決まって遭遇する光景がある。攻撃者がウェブサーバーの脆弱性を突き、まず最初に行うのは「バックドアの設置」と「特権昇格の足掛かり作り」だ。

彼らは、OSが本来持っている権限管理の隙間を縫うようにして、設定ファイルを書き換え、ルート権限を奪取しようと試みる。今日のテーマは、こうした攻撃を「物理的」かつ「OSレベル」で封じ込めるための、泥臭いが極めて強力な防御手法だ。教科書的な知識ではなく、実戦で生き残るための設定を共有しよう。

—

1. 攻撃者が狙う「書き換え可能な設定ファイル」

攻撃者がLinuxサーバーへ侵入した際、真っ先に狙うのは /etc/ 配下の設定ファイルや、ウェブアプリケーションのコンフィグファイル(config.php や .env)だ。

攻撃者の思考プロセス(PoCの断片)

もしウェブアプリにファイルアップロードやディレクトリトラバーサルの脆弱性があれば、攻撃者は www-data 権限で以下の操作を試みる。

# 攻撃者の視点:設定ファイルを上書きして悪意あるコードを注入
echo "<?php system($_GET['cmd']); ?>" > /var/www/html/config.php

この攻撃を許す最大の原因は、「Webサーバーの実行ユーザーが、自分自身の設定ファイルを書き換えられる状態にある」ことだ。これを物理的に遮断するのが chattr コマンドである。

—

2. chattr +i によるImmutable(不変)属性の付与

chattr +i(Immutable属性)を付与されたファイルは、たとえ root ユーザーであっても、そのままでは削除もリネームも、内容の変更もできない。

実装:設定ファイルを「聖域化」する

デプロイ完了後、重要な設定ファイルに対して以下のコマンドを適用する。

# 1. ファイルをroot権限に変更
chown root:root /var/www/html/config.php

# 2. 書き込み権限を剥奪(644 -> 444)
chmod 444 /var/www/html/config.php

# 3. Immutable属性を付与(最強の防御)
chattr +i /var/www/html/config.php

これ以降、たとえ攻撃者が root 権限の一部を奪取したとしても、chattr -i を実行して属性を解除しない限り、そのファイルを改ざんすることは不可能になる。インシデント発生時の「踏み台化」や「永続化」を防ぐための強力な防波堤だ。

—

3. スティッキービットで「書き込み」の暴走を止める

次に重要なのが /tmp や /var/tmp といった「誰でも書き込めるディレクトリ」の扱いだ。ここを放置すると、攻撃者はスクリプトを設置し、権限昇格のためのエクスプロイトを実行する。

ここで活躍するのが「スティッキービット(Sticky Bit)」だ。

スティッキービットの効果

ディレクトリにスティッキービット(パーミッションの最後に t が付く)が設定されていると、「そのファイルの所有者」または「root」以外は、ファイルを削除・リネームできなくなる。

# 実装例:共有ディレクトリの保護
chmod 1777 /tmp
# 実行結果:drwxrwxrwt となり、末尾の t がスティッキービットを意味する

これを適切に設定することで、攻撃者が他人のファイルを上書きしたり、システム全体に影響を与えるような一時ファイルを生成することを困難にする。

—

4. セキュアな運用に向けた実装サンプル(Pythonによる自動化)

運用現場では、サーバー構築後に手動でコマンドを打つのはリスクが高い(設定漏れが起きるからだ)。デプロイパイプラインに、以下の「要塞化スクリプト」を組み込むことを強く推奨する。

import os
import subprocess

def harden_file(file_path):
    """ファイルにImmutable属性を付与し、改ざんを防止する"""
    try:
        # root権限が必要な操作
        subprocess.run(["chattr", "+i", file_path], check=True)
        print(f"[SUCCESS] Immutable applied: {file_path}")
    except subprocess.CalledProcessError as e:
        print(f"[ERROR] Failed to harden {file_path}: {e}")

# 対象ファイルリスト
targets = ["/var/www/html/config.php", "/etc/nginx/nginx.conf"]

for target in targets:
    if os.path.exists(target):
        harden_file(target)
    else:
        print(f"[WARN] File not found: {target}")

—

まとめ:防御の深層心理

セキュリティにおいて、ソフトウェアのバグをゼロにすることは不可能に近い。だからこそ、「バグを突かれたとしても、システム本体を破壊させない」という多層防御が重要になる。

  • Immutable属性 (chattr +i): 攻撃者の永続化(バックドア設置)を物理的に封じる。
  • スティッキービット: ディレクトリ内での不正なファイル操作を抑制する。

これらは派手な技術ではないが、私が数々のインシデントを見てきた中で、最も「攻撃者の足を止める」効果が高かった手法だ。今日から、君の担当するサーバーの設定ファイルを、もう一度見直してみてほしい。その「小さな一手間」が、数百万件の顧客データを守る結果に繋がるのだから。

コメント

タイトルとURLをコピーしました