名古屋でAIシステムの開発をしている小嶋です。レンタルサーバーに置いたホームページが、書き換えられていないか・怪しいファイルが置かれていないかを毎時見張り、見つけたらメールで知らせるシステム「Kurage Security Watch」を作りました。当社のサイトで動かしていて、デモを公開し、Kurage App Store に出品しています。
Kurage Security Watch(デモ・架空の会社のサイトの記録) https://proto.exbridge.jp/ksecwatch/#ref=vibeblog-ksecwatch
なぜ作ったか
先週、URLを入れるだけで外から見える守りを診断する「Kurage Security Check」を作りました。
Webサイトの脆弱性診断を、URLを入れるだけで(Kurage Security Check を作った記録) https://exbridge.jp/vibeblog/2026-10-24-website-zeijakusei-shindan-url.html#ref=vibeblog-ksecwatch
外から見える守りは、それで測れます。ただ、本当に怖いのは、気づかないうちにサイトの中に何かを置かれることです。画像を置くフォルダに PHP が1本増える、.htaccess が書き換えられて別のサイトへ飛ばされる、WordPress の本体に数行足される。外から見ても分からず、見つかったときには何週間もたっていることがあります。
当社のサイトも、ふつうのレンタルサーバー(heteml)に置いています。管理者の権限が無いので、サーバーの中に監視の道具を入れることはできません。そこで、レンタルサーバーでも置ける形で、改ざん検知を作ることにしました。
FTP で全部を見る方式は捨てた
最初に考えたのは、FTP でファイルの一覧を取り、前回と比べる方式です。どこのレンタルサーバーでも使えます。
ところが、当社の4サイトは合わせて約17万ファイルあり、FTP で一覧を取るだけで10分以上かかりました。しかも、短い時間に接続を重ねると、サーバー会社に当社のIPが遮断されます(以前、実際に遮断されたことがあります)。毎時見張るには使えません。
そこで、比べる作業をサーバーの中でやることにしました。
しくみ:サーバーの中で比べ、判定は外でする
- レンタルサーバーに、小さな見張り役の PHP を置きます。置き場は公開フォルダの外で、権限は 700 にします。公開フォルダに置くのは呼び出し口だけです
- 見張り役は、全ファイルの大きさ・更新日時・ctime・権限を台帳と比べ、違いだけを返します。中身の指紋(SHA-256)は、変わったファイルだけ取り直します
- 当社のサーバーから毎時呼び、増えた・変わった PHP などは中身をもらって、オープンソースの検査規則 php-malware-finder(YARA)にかけます
- 見つけたら、メールで知らせます
当社の4サイト・171,635ファイルで、サーバーの中の比較は1回2秒ほどでした。1日1回は全部の指紋を取り直す総点検をしていて、これは12秒ほどです。
マルウェアの判定をサーバーの中でしないのには理由があります。共有サーバーの CPU を使いたくないことと、誤検知の調整を手元で済ませたいことです。
日時を戻す手口も見る
サイトを書き換える側は、ファイルの更新日時を元に戻して、変化を目立たなくすることがあります。更新日時は touch というコマンドで好きな日時にできます。
ただ、ctime(ファイルの情報が変わった時刻)は戻せません。そこで ctime も台帳に持ち、中身が変わったのに更新日時が古いままのファイルは、「日時が戻された」として知らせます。
自社の更新では知らせない
改ざん検知でいちばん困るのは、知らせが多すぎることです。サイトを更新するたびにメールが来たら、そのうち誰も読まなくなります。
そこで、手元の公開用のファイルと中身が同じものは「自社の更新」として分けることにしました。動かし始めてから見つかった変化は298件で、そのうち276件は自社の更新、17件はサーバー自身が書き換えるデータのファイルでした。知らせが要る変化は3件だけでした。2件は私が試験で置いたファイル、1件は見張りの仕組みを入れ替えたときに置き直した呼び出し口です。呼び出し口は手元に控えを残さずに置いていたので、いまは控えを残して「自社の更新」として分けるように直しています。
サーバー自身が書き換えるデータのファイル(当社のブログが使う Bludit のデータなど)は、変わるのがふつうです。こちらは、先頭の「実行を止める1行」が崩れていないかだけを確かめます。データのファイルに見せかけて PHP を書き込まれても、ここで気づけます。
誤検知の調整
最初は、PHP だけで動くマルウェア検査の道具(phpMussel)をサーバーに置きました。ところが、「system」や「systemd」のような、ふつうのプログラムにも出てくる語にまで反応しました。数えきれないほどの誤検知が出たので、外しました。
代わりに使った php-malware-finder(YARA の規則)でも、最初は誤検知が出ました。
- 日本語の文字に反応する規則(NonPrintableChars)。日本語のサイトでは、ほぼ全部のファイルが引っかかります
@includeに反応する規則。当社のアクセス計測の読み込みがこの書き方でした
この2つは、当社の書き方に反応するだけなので外しました。
初回の全件検査では、台帳にある動くファイル78,857件のうち、手元に同じ中身が無い11,440件を37秒で検査しました。反応したのは30件で、全部が試用で置いている顧客管理のオープンソース(EspoCRM)に入っている正規のライブラリでした。中身を確かめたうえで、「確認済み」にしています。確認済みにしたものも、中身がまた変われば、もう一度知らせます。
第三者に呼ばれないように
公開フォルダの呼び出し口は、外から誰でも叩けます。そこで、合言葉で作った署名と時刻(ミリ秒)が合うときだけ動くようにしました。合わない呼び出しには「ページが無い」(404)と答えます。同じ署名は二度使えないので、通信を盗み見て同じ呼び出しを送り直されても動きません。
最初は秒単位の時刻にしていましたが、同じ秒に2回呼ぶと2回目が断られたので、ミリ秒にしました。
お客様のサーバーにも置ける形に
当社用に作ったあと、設定ファイル1枚で切り替えられるようにして、配布用にまとめました。
- 見張られる側:PHP 8.0 以上が動き、FTPS でファイルを置けるレンタルサーバー(管理者の権限は不要)
- 見張る側:御社の Linux サーバー(Python)。cron で毎時・毎日動かします
- サイトの中身や記録は、御社のサーバーにだけ残ります
配布用の zip だけを使って、手順書どおりに別の場所へ新しく設置し、試しに無害な PHP を1本置いたところ、次の見張りで知らせが出て、メールが受信箱に届くところまで確かめました。手順書とAIエージェント向けの指示書を付けてあるので、Claude Code や Codex に渡せば、手順の確認を通しながら設置まで進めます。
よくある質問
改ざん検知とは何ですか
ホームページのファイルが、持ち主の知らないうちに書き換えられたり、増やされたりしていないかを見つけることです。侵入そのものを防ぐもの(WAF など)とは役割が違い、入られたあとに早く気づくためのものです。
どんなレンタルサーバーで使えますか
PHP が動き、FTPS でファイルを置けるレンタルサーバーで使えます。管理者の権限は要りません。当社は heteml で動かしています。
サーバーに負担はかかりませんか
見張り役は、ファイルの大きさ・日時・権限を台帳と比べるだけで、中身の指紋は変わったファイルだけ取り直します。17万ファイルで1回2秒ほどです。マルウェアの判定はサーバーではしません。
WordPress のサイトでも使えますか
使えます。画像を置くフォルダ(uploads)に置かれた PHP や、WordPress の本体・テーマの書き換えを見つけます。プラグインを更新したときは、手元に同じファイルを置いておけば「自社の更新」として分けられます。
Kurage Security Check とは何が違いますか
Kurage Security Check は、外から見える守り(https・守りの設定・古い部品)を診断します。Kurage Security Watch は、サイトの中のファイルの変化を見張ります。組み合わせて使えます。
Kurage Security Watch(導入版・Kurage App Store) https://kappstore.exbridge.jp/app.php?id=9dd7d5be638f9cb8#ref=vibeblog-ksecwatch
設置や、見つかったときの調べと直しは、AI-IT顧問で引き受けています。
AI-IT顧問 https://exbridge.jp/ai-it-komon.html#ref=vibeblog-ksecwatch
