夜勤の引き継ぎで「ログに不審なアクセスがないか見ておいて」と言われて、手が止まった経験はありませんか。アクセスログは1日で何万行にもなります。どこから見ればよいのか、そもそも何が異常なのかが分からないまま、画面を下までスクロールして終わってしまう。この記事では、nginxやApacheのアクセスログから攻撃の兆候を見つける集計のやり方を、順番に整理します。結論を先に言うと、注目すべきは404の多さではありません。/.env や /.git のような設定ファイルに200が返っている行です。404は「まだ狙われているだけ」ですが、200は「もう持っていかれた」を意味します。
アクセスログで本当に危ないのは404ではなく200
最初に順番を入れ替えておきます。アクセスログを見るとき、真っ先に確認するのは404の件数ではなく、返ってはいけないパスに2xxが立っていないかです。
理由は、この2つが意味する段階がまるで違うからです。404は「そんなファイルはありません」という応答なので、相手が探りを入れた事実は分かっても、被害は出ていません。一方で200は「ありました、どうぞ」と渡した記録です。相手が探していたのが .env や .git であれば、そこにはデータベースの接続情報やAPIキーが書かれている可能性があります。
マンションの見回りにたとえると分かりやすいと思います。404の山は、知らない人が廊下じゅうのドアノブを片っ端から回していった跡です。不愉快ではありますが、部屋は無事です。対して .env への200は、1つのドアが開いてしまい、相手が中に入った跡になります。見回りの報告書に書くべきは、どちらでしょうか。
つまりアクセスログの監視は、件数の多さを追う作業ではありません。「攻撃を受けている」と「すでに侵害された」を切り分ける作業だと考えると、見る場所が定まります。

アクセスログを集計する前に「本当の送信元IP」を確かめる
集計に入る前に、必ず片づけておく準備が1つあります。ログの左端に記録されているIPアドレスが、本当に相手のIPかどうかの確認です。
いまのシステムは、利用者とサーバのあいだにロードバランサやCDNが挟まっている構成がほとんどです。この場合、サーバから見える接続元は、利用者ではなく手前の中継機になります。その状態で送信元IPを数えても、同じ社内アドレスが上位に並ぶだけです。異常なアクセスをどれだけ受けていても、集計結果はまったく動きません。
本来の送信元は、中継機が付け足すヘッダに入っています。nginxならngx_http_realip_moduleのset_real_ip_from(信頼する中継機のアドレス)とreal_ip_header(読み取るヘッダ名)、Apacheならmod_remoteipのRemoteIPHeaderとRemoteIPTrustedProxyを設定して、そのヘッダの値をログに書くよう直します。ここで大切なのは、信頼する中継機の範囲を必ず指定することです。nginx公式はset_real_ip_fromを「正しい置き換えアドレスを送ることが分かっている信頼できるアドレスを定義するもの」と説明し、Apache公式も「この動作を有効にしてよいのは、このサーバが信頼する中継機(プロキシなど)からに限る。リモートのユーザーエージェントが別のユーザーエージェントになりすますのは容易だから」と警告しています。ヘッダは利用者側からでも詐称できるため、誰の申告でも信じる設定にすると、今度は偽のIPを記録することになります。
この一手間を飛ばすと、以降の7つの集計はすべて意味を失います。まずは自分のサーバのログを1行だけ開いて、左端のIPに心当たりがあるかを見てください。
アクセスログから兆候を見つける7つの集計
準備ができたら集計に進みます。特別なツールは不要で、awkとsortとuniqの組み合わせで足ります。7つを、意味する段階ごとに2つに分けて並べます。
まだ攻撃の段階を示す5つの集計
- 送信元IPの上位: 件数の多い順に20件ほど出します。1つのIPが突出していれば、機械が回している可能性が高いです
- ログイン系へのPOST: wp-login.php や xmlrpc.php へのPOSTが数百から数千件あれば、パスワードの総当たりと考えてよいです
- 404を量産しているIP: 存在しないパスばかり叩くIPは、脆弱性を探す自動ツールの動きです
- 探されているパスの一覧: 404になったパスを数えると、/.env、/.git、/wp-config.php.bak など、相手が何を狙っているかが並びます
- User-Agentの偏り: 名乗りが空だったり、ツール名がそのまま入っていたりする場合は、他の集計と重ねて判断します
たとえば送信元IPの上位は、次の1行で出ます。ログを空白で区切って1列目を取り出し、同じものを数えて多い順に並べているだけです。
zcat -f /var/log/nginx/access.log* | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
ログイン系へのPOSTが並ぶときは、認証のしくみそのものを見直す合図でもあります。パスワードを何度でも試せる入口が外に出ている状態だからです。認証の考え方については、OAuthの記事やパスキーの記事もあわせて読むと、対策の方向が見えてくると思います。
すでに侵害された可能性を示す2つの集計
- 要注意パスに返った2xx: .env、.git、.bak といった文字を含むパスで、200や206が返っている行を抜き出します。ここに1行でも出たら、その日のうちに上長へ報告する事案です
- 転送量の多い送信元: 応答のバイト数をIPごとに合計します。1つのIPだけ桁が違うときは、中身をまとめて持ち出されている可能性があります
この2つは件数が少ないぶん、埋もれやすいのが厄介なところです。何千件の404に目を奪われているあいだ、たった3行の200が下のほうで静かに記録されている、という並び方をします。だからこそ、集計の順番を逆にしておく価値があります。
アクセスログの監視は「前日との差分」にすると続く
7つの集計を毎日手で打つのは、正直なところ続きません。当番制にするなら、全件ではなく前日からの増加分だけを出すしくみにします。
理由は、攻撃の兆候が絶対値ではなく変化に表れるからです。404が毎日3,000件あるサーバでは、3,000件は異常ではありません。異常なのは、それが翌日に9,000件へ跳ねたときや、昨日まで一度も出ていなかったパスが上位に現れたときです。前日の集計結果をファイルに残しておき、差分だけを朝の報告に載せる形にすると、読む量が数行まで減ります。
攻撃元を自動で遮断するfail2banのような道具もあります。ただし新人のうちに覚えておきたいのは、遮断の設定を入れる前に、ignoreipへ社内と監視元の固定IPを書いておくことです。ここで取り違えやすいのがignoreselfとの違いです。ignoreselfは既定で有効ですが、守ってくれるのはそのサーバ自身のアドレスだけで、公式マニュアルにも「稼働ホスト自身のDNS名やIPを(ignoreipに)含める必要はない」と書かれています。つまりオフィスの回線も、別ホストにある監視サーバも対象外です。この2つを同じものだと思ってignoreipを空のまま有効にすると、監視のために何度もアクセスしていた自分たちが真っ先に締め出されます。復旧に呼ばれる夜勤を増やさないための、地味な作法です。
なお、応答が遅いといった性能面の調査には、アクセスログだけでは足りない場面が増えています。
考察: アクセスログで最初に身につけるべきは平常値の感覚
ここからは筆者の考えです。運用チームに入って最初に磨くとよいのは、コマンドの暗記ではなく、担当サーバの平常値を言える状態だと思います。
理由は、異常の定義が現場ごとに違うからです。同じ「1日1万件の404」でも、公開サイトなら日常で、社内システムなら大事件です。平常値を知らない人にとって、すべてのログは同じ濃さの灰色に見えます。逆に、平日はおよそ何件、休日は何件、上位のUser-Agentはいつもこの3つ、と言えるようになると、変化のほうから目に飛び込んでくるようになります。
そしてこの感覚は、AIに調べさせる場面でも効いてきます。ログを貼り付けて「危険なものはありますか」と聞けば、それらしい答えは返ってきます。ただ、その指摘が自分の環境で本当に異常なのかを判断できるのは、平常値を持っている人だけです。判断の基準を自分の中に持たないまま任せると、毎日出ている無害なアクセスに振り回されることになります。今週は、担当サーバの送信元IP上位20件を1回出して、手元にメモを残すところから始めてみてください。それが来週からの基準になります。
.envへの200を見つけてから慌てないために、そもそも鍵を.envに置かない設計もあわせて考えておきましょう。AIエージェント時代のAPIキーの置き場所で整理しました。
そもそも何を入れたかを記録していないと、ログの突き合わせも進みません。導入時の確認手順はcurlからbashへ直流しは危ないで扱いました。
兆候に気づいたあと、最初の数分で何をするかはインシデント初動で新人がやる5つのことを参考にしてください。
侵入されたあとに何が漏れ、パスワードはどこまで守られるのかは、漏れても「復元できない」パスワード|ハッシュ化とソルトの仕組みで整理しました。
.envを探す要求が実際にどれくらい届くのか、漏れた鍵を誰が止めるのかは、シークレットスキャンとは|業務システム65件中53件が対象外もあわせて読んでみてください。
侵入されたときにデータを戻せるかどうかは、バックアップの置き場所で決まります。ランサムウェアはバックアップも狙う|オフライン保管と復元訓練もあわせて読んでみてください。
不正アクセスの報道を自分の現場への問いに変える読み方は、情報漏洩ラッシュは本当か|件数は横ばいで規模が倍増した統計で紹介しています。
エラーにならない正常なアクセスで情報が抜かれた事例と、量で見つける考え方は普段どおりのアクセスで漏れる情報|発覚まで15日かかった理由で整理しています。
IPアドレスを次々に変えてくる攻撃では、IPごとの件数を数える監視だけでは気づきにくくなります。応答の偏りから見つける考え方はIP遮断が効かない攻撃|40分で326IPを使い分ける手口と対策で紹介しています。
まとめ
- アクセスログで最優先に見るのは404の件数ではなく、.envや.gitに2xxが返っていないか
- 集計の前に、ロードバランサやCDNの先にある本当の送信元IPを記録する設定を入れる
- 監視を続けるコツは全件を見ないこと。前日との差分にして、遮断設定では自社IPを必ず除外する
まずは自分の担当サーバで、404になったパスの一覧を出してみてください。何を狙われているかが分かると、守る場所が具体的になります。

コメント
コメント一覧 (12件)
[…] アクセスログの404より怖い200|侵害の兆候を見つける7つの集計 […]
[…] ただし、検証には土地勘が要ります。AIが「デプロイ直後に応答時間が伸びています」と書いたとき、それが本当に原因かを疑えるかどうかは、自分でログやメトリクスを追った経験に左右されます。分散トレーシングの基本やアクセスログの読み方を一度は手で確かめておくと、AIの出力を鵜呑みにせずに済みます。 […]
[…] 3つ目の記録は、事故が起きたあとに効きます。何をいつ入れたか分かれば、アクセスログから侵害の兆候を見つける集計と突き合わせて、原因を絞り込めます。 […]
[…] どのログを見ればよいかは、アクセスログで侵害の兆候を見つける記事が参考になります。 […]
[…] アクセスログの404より怖い200|侵害の兆候を見つける7つの集計 […]
[…] 注意したいのは、コンソールのイベント履歴には制限が2つあることです。さかのぼれるのは過去90日ぶんの管理イベントまでで、しかも複数の属性を組み合わせた検索ができません。つまり上の3段をコンソールの検索だけで一気に絞ることはできず、StartSessionで引いた結果を開いて確かめるか、AWS CLIやCloudTrail Lakeを使うことになります。長く残したい場合は、証跡(トレイル)やイベントデータストアを作る設定が必要です。ログを見る癖そのものは、アクセスログから侵害の兆候を読む話と同じで、日ごろの積み重ねがものを言います。 […]
[…] 学んだ内容は、ログを読む力にもつながります。IPアドレスやポートの意味がわかると、アクセスログから侵害の兆候を見つける集計も読みやすくなります。 […]
[…] 運用担当は、CPUやディスクの監視で「ふだんの波形」を毎日見ているはずです。その感覚がそのまま役立ちます。アクセスログの集計方法は、アクセスログの404より怖い200|侵害の兆候を見つける7つの集計でくわしく書いています。 […]
[…] 被害に気づいた直後の動き方は、インシデント初動で新人がやる5つのことでまとめています。バックアップのジョブが本当に終わっているかを見張る方法は、バッチ監視の4つの観点が参考になります。侵入の兆しの見つけ方は、アクセスログから侵害の兆候を見つける記事も読んでみてください。 […]
[…] アクセスログで侵害の兆しを探す集計のしかたは、アクセスログの404より怖い200で詳しくまとめています。気づいたあとの動き方は、インシデント初動で新人がやる5つのこともあわせて読んでみてください。 […]
[…] 鍵や認証情報の扱いは、APIキーを.envに置くのが危ない理由でも取り上げました。乗っ取りが疑われるときは、アクセスログから侵害の兆候を見つける集計が調べる手がかりになります。導入したソフトの脆弱性を確かめる流れは、SSM Agentの脆弱性を確認する手順も参考にしてください。 […]
[…] 鍵の置き場所そのものを見直す考え方は、APIキーを.envに置くのが危ない理由でまとめています。外から.envを探された形跡の調べ方は、アクセスログから侵害の兆候を見つける記事が参考になります。 […]