自分が管理しているサイトの画面を開いて、見た目は普段どおりなのに中身が変わっていないだろうかと静かに考えている一人運用の保守担当者

サイト改ざんに気づく仕組み|一人運用で始める改ざん検知の作り方

「サイトは毎日見ています。おかしくなっていたら、さすがに気づくと思います」

——保守を任されている人なら、たぶん一度はそう思ったことがあるはずです。私もそう思っていました。

けれど、サイトの改ざんは見た目が変わらないまま起きることが少なくありません。トップページは今日も普通に開く。管理画面も普通に入れる。でも公開ディレクトリのどこかに、見覚えのないファイルが1つ増えている。検索エンジンから来た人にだけ、別のページが返っている。そういう形のほうが、むしろ多いのです。

だから「毎日見ているから大丈夫」は、残念ながら検知の仕組みにはなりません。かといって、高価な製品を入れるのも、一人運用の現場では現実的でないことが多い。この記事では、いま手元にあるもの(サーバー・ログ・Git・無料のツール)だけで、改ざんに気づく側に回るやり方を、小さい順に整理します。

結論:改ざん検知は、気づく入口を3つ持つと一気に楽になります。①外から(サイトの見え方の変化・検索エンジンからの通知)/②中から(ファイルの追加・更新の検知)/③記録から(ログイン・POST・更新の記録)。この3つのどれか1つでも仕込めば、気づける確率は大きく変わります。最初の一歩としていちばん費用対効果が高いのは、「昨日から更新されたファイルの一覧を、毎朝1通受け取る」こと。find 1行とcron1行で始められます。

なお、この記事は自分が管理を任されているサイト・サーバーに対して行う確認を前提にしています。他人の管理するサイトへの調査行為は対象外です。もし読んでいる途中で「これはもう改ざんされているかもしれない」と思ったら、検知の話より先に初動です。不正アクセスの疑いがあるときの初動と保全へ先に進んでください。

何が起きているか:改ざんは「隠れているほうが得」だから隠れる

昔ながらの「トップページが真っ黒になって犯行声明が出る」タイプの改ざんは、今では少数派です。理由は単純で、すぐバレると攻撃側の得にならないからです。

いま多いのは、気づかれないほうが長く使えるタイプです。

つまり、「異常が目に見える」という前提そのものが成り立たない。これは注意力の問題ではなく、そういう作りになっているだけです。見落としていたとしても、それはあなたの落ち度ではありません。

だからこそ、目でなく仕組みに見張ってもらう。ここから先は、その仕組みをいちばん軽いものから並べていきます。

気づく入口は3つある

改ざんに気づくための3つの入口を、サイトの見え方を外から確認する方法・サーバー内のファイルの変化を見る方法・アクセスや操作の記録から見る方法として横並びで示した図
気づく入口は3つ。どれか1つでも用意できれば、気づける確率は変わる

改ざんに気づくルートは、大きく3つに分けられます。全部そろえる必要はありません。まず1つ。慣れたらもう1つ。それで十分に前進です。

① 外から気づく:サイトの「見え方」の変化を拾う

サーバーの中に入らず、外から見える変化で気づく方法です。手間がいちばん少なく、条件付きリダイレクトのような中を見ても分かりにくい改ざんに強いのが利点です。

# 自分が管理しているサイトのトップページのHTMLを取得し、内容の指紋(ハッシュ)を出す
curl -s https://example.com/ | sha256sum

毎日の値を1行ずつファイルに残しておけば、変わった日が分かります。更新の多いサイトでは毎日変わってしまうので、その場合は「特定の1ページだけ」「フッターだけ」に絞ると使えます。

② 中から気づく:ファイルの追加・更新を検知する

いちばん本命の方法です。公開ディレクトリのファイルは、自分が触ったとき以外は変わらないはず——この当たり前を、機械に確認してもらいます。

いちばん軽い一歩は「昨日から更新されたファイルの一覧」を毎朝見ることです。

# 直近1日以内に更新されたファイルを、更新日時つきで一覧にする
# (公開ディレクトリのパスは自分の環境に置き換える)
find /var/www/html -type f -mtime -1 \
  -not -path "*/cache/*" -not -path "*/logs/*" \
  -printf '%TY-%Tm-%Td %TH:%TM  %p\n' | sort

-printf はGNU版の find の書式なので、環境によっては使えません。その場合は -ls に置き換えれば同じ目的を果たせます。キャッシュやログのように毎日変わる場所は、-not -path で最初から除いておくと、一覧が「見る気になる長さ」に収まります。ここを面倒がると、たいてい続きません。

これをcronに1行入れて、結果を自分宛てに送ります。

# 毎朝6時、昨日更新されたファイルの一覧をメールで受け取る(送信コマンドは環境に合わせる)
0 6 * * * find /var/www/html -type f -mtime -1 -not -path "*/cache/*" -ls | mail -s "[daily] 昨日更新されたファイル" you@example.com

慣れてきたら、ベースライン(正常時のひかえ)と比べます。 更新日時は書き換えられることがあるので、内容そのものの指紋を取っておくとより確かです。

# 正常だと分かっている時点で、ハッシュの台帳を「公開ディレクトリの外」に作る
find /var/www/html -type f -print0 | xargs -0 sha256sum > /var/backups/baseline.sha256

# 後日、変化したファイルだけを洗い出す(OK以外の行=中身が変わった/消えたファイル)
sha256sum -c /var/backups/baseline.sha256 2>/dev/null | grep -v ': OK$'

ひとつ大事な注意点があります。ハッシュの台帳は「新しく置かれたファイル」を見つけられません。 台帳に載っていないので、比べようがないからです。Webシェルの設置はまさにこの型なので、ファイル一覧そのものの差分も一緒に見ます。

# 正常時のファイル一覧を控えておく
find /var/www/html -type f | sort > /var/backups/files-base.txt

# 後日、いまの一覧と比べる(「>」で始まる行が、新しく増えたファイル)
find /var/www/html -type f | sort | diff /var/backups/files-base.txt -

台帳は、必ず公開ディレクトリの外(できれば別サーバーやバックアップ先)に置きます。同じ場所にあると、いざというとき台帳ごと書き換えられている可能性が残ってしまいます。

Gitでソースを管理しているなら、すでに強力な検知の仕組みを持っています。

# 本番の作業ディレクトリで、管理下のファイルに差分がないかを見る
git status --short
git diff

身に覚えのない差分が出れば、それが答えです。まだGit管理でないなら、バージョン管理なしのソースをGitに載せる手順から始めると、改ざん検知は副産物としてついてきます。

WordPressなら、公式が配っているファイルとの照合が使えます。

# コアファイルが公式配布物と一致しているかを確認する(WP-CLI)
wp core verify-checksums

# 公式ディレクトリ由来のプラグインについても同様に確認する
wp plugin verify-checksums --all

自分でカスタマイズしたテーマや、公式ディレクトリ外のプラグインは対象外になります。「対象外のものが何か」を把握したうえで使うのが要点です。

もう少し本格的にやるなら、ファイルの改変検知に特化した仕組み(AIDEなど、OSのパッケージで導入できるもの)もあります。ただ、最初からこれを目指して力尽きるより、find 1行を毎朝受け取るほうがずっと価値があります。続くほうが強い、というのは運用の一般則です。

③ 記録から気づく:入られた痕跡を見る

ファイルが変わる前に、必ず誰かが入るか、何かが送られています。その記録から気づく入口です。

# nginxの既定ログ形式の例。POSTのリクエストを時刻・送信元・パス・ステータスで拾う
grep '"POST ' /var/log/nginx/access.log | awk '{print $4, $1, $7, $9}' | tail -50
# 画像置き場など「本来プログラムが無いはずの場所」への .php アクセスを探す
grep -iE "/(uploads|files|images)/[^ ]*\.php" /var/log/nginx/access.log | tail -50

ログは、保存期間が短いとそもそも遡れません。ローテーションの世代数を確認して、少なくとも数週間は残るようにしておくと、いざというときの助けになります。

具体例:ある朝の「1件だけ増えたファイル」

小さな会社のコーポレートサイトを、ほかの業務と兼務で守っている担当者の例で、順番をたどってみます。

この例で効いたのは、高機能な製品ではありません。「置いた覚えのない場所に、置いた覚えのない種類のファイルがある」と気づけたこと。それだけです。そして、もし気づいていなければ、その .php は何か月も静かに使われ続けていたはずです。

もうひとつ大事なこと:この担当者は、見つけたファイルをすぐに消しませんでした。消すのがいちばん自然な反応ですが、消すと侵入経路の手がかりも一緒に消えます。詳しい順番は不正アクセスの疑いがあるときの初動と保全にまとめています。

影響:仕組みを持つと、何が変わるか

改ざん検知を仕込むと、防御力が上がる以上に、日々の気持ちの持ちようが変わります。

そして、いちばん大きいのはこれかもしれません。気づける仕組みがあると、四六時中気にしなくてよくなります。 常に不安を抱えているより、朝の1通に任せるほうが、心も業務も持続します。

明日やること:cronを1行だけ足す

大きな設計は要りません。明日できる、いちばん小さな一歩はこれです。

  1. 公開ディレクトリの正確なパスを確認する。Webサーバーの設定(DocumentRoot や root の行)で確かめます。思い込みのパスで監視していた、は本当によくあります。
  2. find を手で1回叩いてみる。find <公開ディレクトリ> -type f -mtime -1 -ls を実行して、普段どのくらい変わるのかを体感します。ここで大量に出るなら、キャッシュ・ログ・アップロード先を -not -path で除きます。
  3. 1行だけcronに入れる。毎朝、その結果を自分が必ず見る場所(メールでもチャットでも)へ送ります。まずは毎日「該当なし」が届く状態を作れば十分です。
  4. Search Console の通知先メールアドレスを確認する。登録していなければ登録を、していれば宛先が現役のアドレスかを見るだけです。5分で終わります。
  5. 「見覚えのないものが出たら消さずに相談」とメモに1行書いておく。将来のいちばん焦っている自分に向けた申し送りです。

1と3だけでも、今日と明日で確実に変わります。完璧な検知より、明日から動いている検知のほうが、現場では強いです。

改ざん検知チェックリスト

いま自分の現場でどこまでできているかを見る項目です。全部そろえる必要はありません。

まず外せない最低ラインはこの3つです。ここだけ押さえられれば十分に前進です。

次の項目は、余裕ができたときに1つずつ足していく分です。当てはまらないものは飛ばして大丈夫です。

全部に○が付かなくても大丈夫です。最低ラインの1つ目、find の一覧を毎朝受け取る。ここまで来ていれば、昨日までとは違う場所に立っています。

よければ、こちらも

改ざん検知は、単体で完結する仕事ではありません。周りを少しずつ整えると、検知そのものも軽くなります。

毎朝届く更新ファイルの一覧に異常がないことを確かめ、静かな安心とともに一日を始めている一人運用の保守担当者

改ざんの話がしんどいのは、「気づけていないだけかもしれない」という疑いに終わりがないからだと思います。何も起きていない日でも、心のどこかが少し落ち着かない。ひとりで守っていると、その感覚を分け合う相手もいません。

でも、その落ち着かなさは、あなたが真面目に責任を持っている証拠でもあります。そして、その不安の大半は、確認を仕組みに預けることでずいぶん軽くなります。毎朝1通、「昨日は何も増えていません」と届く。それだけで、疑い続けなくてよくなります。

今日いきなり全部そろえなくて大丈夫です。まずは公開ディレクトリのパスを1つ確かめて、find を1回叩いてみるところから。それがもう、気づく側に回った最初の一歩です。

ほかの実務ヒントは記事一覧からどうぞ。保守運用の小さな備えを、メールでも少しずつお届けしています。

関連用語