Apache単体で作る簡易ハニーポットWebページ設計
本記事の位置づけ
この記事では、Apache単体で動作する簡易ハニーポットWebページの設計を整理します。前提は次のとおりです。
- WebサーバはApache単体
- PHP、CGI、Python、Node.js、DBは使わない
- HTML、CSS、JavaScriptでログイン画面風のWebページを作る
- ID/PASS入力欄を置く
- POSTは受ける
- ただしPOST本文は保存しない
- 最優先は「侵害され、踏み台にされないこと」
- 次点で「意味のある脅威インテリジェンスの獲得」
この構成は、攻撃者を深く誘い込む高対話型ハニーポットではありません。インターネットに置かれた「攻撃の入口に見える観測点」として設計します。
目次
- 1. 基本方針
- 2. なぜApache単体にするのか
- 3. ハニーポットの目的を絞る
- 4. やること・やらないこと
- 5. 案A:POST先も静的に扱う
- 6. 全体アーキテクチャ
- 7. 機能要件
- 8. 非機能要件
- 9. 画面設計
- 10. URL設計
- 11. ディレクトリ設計
- 12. Apache設定設計
- 13. HTML/CSS/JavaScript設計
- 14. ログ設計
- 15. 観測できる攻撃パターン
- 16. セキュリティ設計
- 17. ネットワーク設計
- 18. 運用設計
- 19. 動作確認項目
- 20. 受入基準
- 21. 将来拡張
- 22. 結論
1. 基本方針
今回のハニーポットは、攻撃者を深く誘導するものではありません。「ログイン画面らしきもの」をインターネットに置き、そこに対する探索、スキャン、認証試行の痕跡を観測するためのものです。
最も重要なのは、ハニーポット自体が侵害され、第三者攻撃の踏み台にされないことです。そのため、設計思想は次のようになります。
- 機能を増やさない
- 動的処理を持たない
- 認証成功を作らない
- 入力値を保存しない
- アップロード機能を作らない
- コマンド実行機能を作らない
- 内部ネットワークに接続しない
- 重要情報を同居させない
- 観測はApacheログ中心にする
つまり、「攻撃者に触らせる面」は作りますが、「攻撃者が利用できる機能」は作りません。
2. なぜApache単体にするのか
ハニーポットというと、攻撃者の操作を深く観測するために、SSH、Telnet、Webアプリ、疑似DB、疑似ファイルシステムなどを用意する構成もあります。しかし、今回の優先順位ではそれは過剰です。
最優先が「侵害され、踏み台にされないこと」である以上、アプリケーション実装はできるだけ削るべきです。Apache単体にする理由は明確です。
- 実装バグを減らせる PHP、Python、Node.jsなどを使わなければ、アプリケーション層の脆弱性を大幅に減らせます。
- 攻撃面を減らせる ファイルアップロード、DB接続、認証処理、セッション管理を持たないため、悪用できる機能が少なくなります。
- 運用が単純になる Apacheの設定、静的ファイル、ログだけを管理すればよくなります。
- 監視対象が明確になる アクセスログ、エラーログ、OSログに絞れます。
- 壊れても業務影響が小さい 本番業務システムと切り離せば、可用性より安全性を優先できます。
3. ハニーポットの目的を絞る
この構成で得たい情報は、攻撃者の「侵入後の行動」ではありません。得たいのは、攻撃者が最初に何を探し、どのようなパターンでアクセスしてくるかです。
3.1 得たい情報
- どのIPアドレスから来たか
- どのUser-Agentを使っているか
- どのHostヘッダでアクセスしてきたか
- どのパスを探索しているか
- どのHTTPメソッドを使っているか
- どの程度の頻度でアクセスしてくるか
- POST
/loginを試したか - WordPress狙いか
.envや.git狙いか- 管理画面狙いか
- VPNやリモートアクセス基盤狙いか
- APIや開発用エンドポイント狙いか
3.2 得ない情報
逆に、今回の構成では次の情報は積極的に取得しません。
- 入力されたID
- 入力されたパスワード
- POST本文
- 認証成功後の操作
- 攻撃者が設置したファイル
- マルウェアの挙動
- C2通信
- 攻撃者のシェル操作
ここを割り切ることが重要です。深い情報を取りに行くほど、ハニーポット自体が危険なシステムになります。
4. やること・やらないこと
4.1 やること
- Apacheで静的HTMLを配信する
- ログイン画面風のページを作る
- ID/PASS入力欄を置く
form method="POST" action="/login"を設定する- POST
/loginを受ける - 常にログイン失敗画面へ遷移させる
- Apacheアクセスログを詳細化する
- 404や403の探索パスを記録する
- User-Agent、Host、X-Forwarded-Forを残す
- DocumentRootを読み取り専用に近づける
- 不要なApacheモジュールを無効化する
- ログローテーションを設定する
- サーバを本番環境から分離する
- 外向き通信を制限する
4.2 やらないこと
- 本物のログイン処理を作らない
- 認証成功画面を作らない
- DBを使わない
- PHPを使わない
- CGIを使わない
- PythonやNode.jsを使わない
- ファイルアップロードを作らない
- 管理画面を作らない
- Cookieやセッションを発行しない
- JWTを発行しない
- POST本文を保存しない
- 入力されたID/PASSを保存しない
- 外部APIに送信しない
- 外部CDNを使わない
- 実在企業名や実在ロゴを使わない
- 攻撃者に反撃しない
5. 案A:POST先も静的に扱う
今回採用するのは「案A」です。
5.1 案Aの概要
案Aでは、POST /login を受けますが、アプリケーションとして処理しません。Apacheの設定で、POST /login をログイン失敗画面へリダイレクトします。
つまり、サーバ側では次のことをしません。
- IDを読まない
- パスワードを読まない
- POST本文をパースしない
- 認証判定をしない
- DBに保存しない
- セッションを発行しない
一方で、Apacheのアクセスログには、POST /login が来たという事実は残ります。
5.2 案Aのメリット
- 最も安全寄り
- 動的処理がない
- 実装バグが入りにくい
- POST本文を保持しないため管理リスクが低い
- ハニーポット自体が踏み台化されにくい
- Apacheログだけで運用できる
5.3 案Aのデメリット
- 入力されたID/PASSの中身は分からない
- クレデンシャルスタッフィングの詳細分析はできない
- 攻撃者の侵入後行動は観測できない
- 高対話型ハニーポットとしての情報量は少ない
5.4 なぜ案Aでよいのか
今回の最優先は「踏み台化されないこと」です。そのため、脅威インテリジェンス取得のために動的処理を増やすより、機能を削り、安全性を優先します。
認証情報そのものよりも、次の情報に価値を置きます。
- 誰が来たか
- どのパスを探ったか
- どの頻度で来たか
- どのUser-Agentか
- どのHostヘッダか
- POST
/loginを試したか - 404探索の傾向は何か
これであれば、Apache単体でも十分に観測できます。
6. 全体アーキテクチャ
Internet
|
| HTTP / HTTPS
v
Apache
- 静的HTML配信
- CSS配信
- JavaScript配信
- POST /login 受付
- 303で失敗画面へ遷移
- アクセスログ記録
- エラーログ記録
|
| read only
v
/var/www/honeypot
- index.html
- login-failed.html
- assets/style.css
- assets/app.js
- error/*.html
ログ:
/var/log/apache2/honeypot_access.log
/var/log/apache2/honeypot_error.log
この構成で重要なのは、Apacheの背後にアプリケーションが存在しないことです。攻撃者がPOSTしても、そこにログイン処理はありません。攻撃者が怪しいパスを探索しても、存在しないパスは404になります。.env や .git などは明示的に403にします。
7. 機能要件
F-001 トップページ表示
ログイン画面風の静的HTMLを表示します。
- URL:
GET / - 応答:
200 OK、index.html - 補足: 実在企業、実在製品、実在ロゴは使いません。
F-002 ID/PASS入力欄
ログイン画面にID入力欄とパスワード入力欄を表示します。
- 入力項目:
user、password - HTML属性:
<form method="POST" action="/login" autocomplete="off"> - 補足: 入力値はサーバ側で保存しません。
F-003 POST受付
POST /login を受け付けます。
- URL:
POST /login - 応答:
303 See Otherでログイン失敗画面へ遷移 Location: /login-failed.html
方針は次のとおりです。
- 認証判定しない
- 成功画面を返さない
- セッションを発行しない
- POST本文を保存しない
F-004 ログイン失敗画面
認証失敗風の静的画面を表示します。
- URL:
GET /login-failed.html - 表示文言例:
Authentication failed. Please check your credentials and try again. - 注意: 成功画面、管理画面、ダッシュボード画面へは進ませません。
F-005 エラー画面
403、404、405、500用の静的エラー画面を表示します。Apache標準エラーをそのまま出さず、見た目を統一します。
/error/403.html/error/404.html/error/405.html/error/500.html
F-006 静的アセット配信
CSSとJavaScriptを配信します。
- 外部CDNを使わない
- 外部フォントを使わない
- 外部画像を使わない
- JavaScriptは演出のみに使う
F-007 ログ記録
記録対象は次のとおりです。
- 日時
- 送信元IP
- HTTPメソッド
- パス
- クエリ文字列
- ステータスコード
- レスポンスサイズ
- Referer
- User-Agent
- Host
- X-Forwarded-For
- 処理時間
- TLS有無
記録しない対象は次のとおりです。
- POST本文
- 入力されたID
- 入力されたパスワード
- Cookie値
- Authorizationヘッダ全文
8. 非機能要件
8.1 安全性
- Apache単体で稼働する
- 動的実行機能を無効化する
- DocumentRoot配下は原則読み取り専用
- Apache実行ユーザーに不要な権限を与えない
- 外向き通信を遮断する
- 重要情報を配置しない
8.2 可用性
このハニーポットは業務システムではないため、高可用性は最優先ではありません。落ちても業務影響がない構成にします。ただし、ログ肥大化によるディスク枯渇は避けます。
8.3 保守性
- ファイル数を少なくする
- Apache設定を単純にする
- ログ分析は別環境で行う
- ハニーポット本体に分析機能を持たせない
8.4 観測性
- アクセスログを厚めに取る
- 404パスを分析しやすくする
- POST試行を識別しやすくする
- User-AgentとHostヘッダを残す
8.5 法務・倫理面
- 攻撃者から入力された認証情報そのものは保存しない
- 実在企業名や実在サービス名を使わない
- 第三者を誤認させるブランド表現を避ける
- 攻撃者に反撃しない
- 外部への能動的アクセスをしない
9. 画面設計
9.1 画面一覧
| ID | 画面名 | パス |
|---|---|---|
| S1 | ログイン画面 | / |
| S2 | ログイン失敗画面 | /login-failed.html |
| S3 | 403画面 | /error/403.html |
| S4 | 404画面 | /error/404.html |
| S5 | 405画面 | /error/405.html |
| S6 | 500画面 | /error/500.html |
9.2 S1 ログイン画面
表示項目は次のとおりです。
- サービス名風タイトル
- サブタイトル
- User ID入力欄
- Password入力欄
- Sign inボタン
- 監視文言
- バージョン番号風表記
入力項目は user と password です。送信先は POST /login とします。
「本物の社内システム」と断定される表現は避けます。実在企業、実在サービス、実在製品を模倣しません。
9.3 S2 ログイン失敗画面
表示項目は次のとおりです。
Authentication failedPlease check your credentials and try again.Back to sign in
遷移は / に戻るリンクのみです。成功画面や管理画面には遷移させません。
9.4 エラー画面
403、404、405、500は静的HTMLで用意します。Apache標準のエラー画面をそのまま見せないことで、見た目を統一できます。
10. URL設計
| パス | Method | 挙動 |
|---|---|---|
/ | GET | ログイン画面 |
/index.html | GET | ログイン画面 |
/login | POST | 303で失敗画面へ遷移 |
/login-failed.html | GET | ログイン失敗画面 |
/assets/style.css | GET | CSS |
/assets/app.js | GET | JavaScript |
/error/403.html | GET | 403画面 |
/error/404.html | GET | 404画面 |
/error/405.html | GET | 405画面 |
/error/500.html | GET | 500画面 |
10.1 POST /login の扱い
POST /login は303で /login-failed.html に遷移させます。
POST /login
↓
303 See Other
↓
GET /login-failed.html
この方式には次の利点があります。
- POST本文を処理しない
- ブラウザ再読み込み時の再POSTを避けられる
- アクセスログ上はPOST
/loginの事実が残る - 成功画面を作らずに済む
11. ディレクトリ設計
/var/www/honeypot/
index.html
login-failed.html
assets/
style.css
app.js
error/
403.html
404.html
405.html
500.html
Apache設定ファイルは次の場所に置く想定とします。
/etc/apache2/sites-available/honeypot.conf
ログは次のように分けます。
/var/log/apache2/honeypot_access.log
/var/log/apache2/honeypot_error.log
11.1 権限方針
| 対象 | 所有者 | グループ | 権限 |
|---|---|---|---|
/var/www/honeypot | root | root | 755 |
| 静的ファイル | root | root | 644 |
assetsディレクトリ | root | root | 755 |
Apache実行ユーザーには、DocumentRootへの書き込み権限を与えません。
12. Apache設定設計
12.1 基本方針
Apache設定では、次の点を重視します。
- Apacheの情報露出を抑える
- ディレクトリ一覧を無効化する
.envや.gitを拒否する- CGIを使わない
- Overrideを許可しない
- POSTサイズを制限する
- タイムアウトを短くする
- ログを専用ファイルに分ける
12.2 必須設定
ServerTokens Prod
ServerSignature Off
TraceEnable Off
Options -Indexes -FollowSymLinks
AllowOverride None
LimitRequestBody 8192
ErrorDocument 403 /error/403.html
ErrorDocument 404 /error/404.html
ErrorDocument 405 /error/405.html
ErrorDocument 500 /error/500.html
12.3 ログフォーマット
LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\" \"%{X-Forwarded-For}i\" %D" honeypot
| 項目 | 意味 |
|---|---|
%v | VirtualHost名 |
%h | 送信元IP |
%t | 時刻 |
%r | リクエストライン |
%>s | 最終ステータスコード |
%b | レスポンスサイズ |
Referer | 参照元 |
User-Agent | クライアント情報 |
Host | Hostヘッダ |
X-Forwarded-For | プロキシ経由情報 |
%D | 処理時間、マイクロ秒 |
12.4 Apache設定サンプル
ServerTokens Prod
ServerSignature Off
TraceEnable Off
LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\" \"%{X-Forwarded-For}i\" %D" honeypot
<VirtualHost *:80>
ServerName example.invalid
DocumentRoot /var/www/honeypot
ErrorLog ${APACHE_LOG_DIR}/honeypot_error.log
CustomLog ${APACHE_LOG_DIR}/honeypot_access.log honeypot
LimitRequestBody 8192
RequestReadTimeout header=10-20,MinRate=500 body=10,MinRate=500
<Directory /var/www/honeypot>
Options -Indexes -FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<FilesMatch "^\.">
Require all denied
</FilesMatch>
<LocationMatch "^/(\.git|\.env|server-status|cgi-bin|phpmyadmin|phpMyAdmin)">
Require all denied
</LocationMatch>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} =POST
RewriteRule ^/login$ /login-failed.html [R=303,L]
ErrorDocument 403 /error/403.html
ErrorDocument 404 /error/404.html
ErrorDocument 405 /error/405.html
ErrorDocument 500 /error/500.html
</VirtualHost>
12.5 必要モジュール
必要なモジュールは次のとおりです。
mod_rewritemod_reqtimeoutmod_log_config
通常有効なモジュールは次のとおりです。
mod_authz_coremod_authz_hostmod_mimemod_dir
不要または無効化候補は次のとおりです。
mod_cgimod_cgidmod_phpmod_proxymod_proxy_httpmod_statusmod_autoindexmod_userdirmod_include
使わない機能は無効化します。特に、CGI、PHP、Proxy、SSI、Status公開は避けます。
13. HTML/CSS/JavaScript設計
13.1 HTML設計
HTMLは静的ファイルとします。外部CDN、外部フォント、外部画像は使いません。
index.html は次のようにします。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Secure Access Portal</title>
<link rel="stylesheet" href="/assets/style.css">
</head>
<body>
<main class="page">
<section class="card">
<div class="brand">
<div class="logo">S</div>
<div>
<h1>Secure Access Portal</h1>
<p>Restricted system access</p>
</div>
</div>
<form method="POST" action="/login" autocomplete="off" id="loginForm">
<label for="user">User ID</label>
<input id="user" name="user" type="text" maxlength="64" required>
<label for="password">Password</label>
<input id="password" name="password" type="password" maxlength="128" required>
<button type="submit">Sign in</button>
</form>
<p class="notice">
Unauthorized access is prohibited. Activity may be monitored.
</p>
<p class="version">
Portal Version 4.2.1
</p>
</section>
</main>
<script src="/assets/app.js"></script>
</body>
</html>
13.2 ログイン失敗画面
login-failed.html は次のようにします。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Authentication Failed</title>
<link rel="stylesheet" href="/assets/style.css">
</head>
<body>
<main class="page">
<section class="card">
<div class="brand">
<div class="logo">S</div>
<div>
<h1>Authentication failed</h1>
<p>Secure Access Portal</p>
</div>
</div>
<p class="notice">
Please check your credentials and try again later.
</p>
<a class="link-button" href="/">Back to sign in</a>
<p class="version">
Portal Version 4.2.1
</p>
</section>
</main>
</body>
</html>
13.3 CSS設計
assets/style.css は次のようにします。
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: linear-gradient(135deg, #101827, #1f2937);
color: #111827;
}
.page {
min-height: 100vh;
display: grid;
place-items: center;
padding: 24px;
}
.card {
width: 100%;
max-width: 420px;
background: #ffffff;
border-radius: 14px;
padding: 28px;
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
}
.brand {
display: flex;
gap: 14px;
align-items: center;
margin-bottom: 24px;
}
.logo {
width: 48px;
height: 48px;
border-radius: 12px;
background: #1f2937;
color: #ffffff;
display: grid;
place-items: center;
font-weight: 700;
font-size: 24px;
}
h1 {
font-size: 22px;
margin: 0;
}
.brand p {
margin: 4px 0 0;
color: #6b7280;
font-size: 14px;
}
label {
display: block;
margin: 14px 0 6px;
font-size: 14px;
color: #374151;
}
input {
width: 100%;
padding: 12px;
border: 1px solid #d1d5db;
border-radius: 8px;
font-size: 16px;
}
button,
.link-button {
width: 100%;
display: inline-block;
margin-top: 22px;
padding: 12px;
border: 0;
border-radius: 8px;
background: #1f2937;
color: #ffffff;
font-size: 16px;
text-align: center;
text-decoration: none;
cursor: pointer;
}
button:hover,
.link-button:hover {
background: #111827;
}
button:disabled {
cursor: default;
opacity: 0.75;
}
.notice {
margin-top: 20px;
color: #6b7280;
font-size: 12px;
line-height: 1.5;
}
.version {
margin-top: 12px;
color: #9ca3af;
font-size: 11px;
text-align: right;
}
13.4 JavaScript設計
JavaScriptは演出だけに使います。入力値の送信、保存、外部通信はしません。
assets/app.js は次のようにします。
const form = document.getElementById("loginForm");
if (form) {
form.addEventListener("submit", function () {
const button = form.querySelector("button");
if (button) {
button.disabled = true;
button.textContent = "Signing in...";
}
});
}
13.5 JavaScriptでやらないこと
fetchしないXMLHttpRequestしないlocalStorageに保存しないsessionStorageに保存しない- Cookieを書かない
evalを使わない- 外部スクリプトを読み込まない
- 入力されたID/PASSを加工しない
- 入力されたID/PASSを別URLへ送らない
14. ログ設計
14.1 アクセスログ
ファイルは /var/log/apache2/honeypot_access.log です。目的は、攻撃者のアクセス傾向を観測することです。
主な分析項目は次のとおりです。
- IP
- Host
- Method
- Path
- Status
- User-Agent
- Referer
- X-Forwarded-For
- 処理時間
14.2 エラーログ
ファイルは /var/log/apache2/honeypot_error.log です。目的は、Apache側の異常、拒否、設定不備を観測することです。
主な分析項目は次のとおりです。
- 存在しないファイルへのアクセス
- 拒否されたアクセス
- 設定エラー
- 過大リクエスト
- タイムアウト
14.3 保存しないもの
- POST本文
- ID入力値
- Password入力値
- Cookie値
- Authorizationヘッダ全文
Authorizationヘッダをログに残す設計は避けます。Basic認証の試行を見たい場合でも、ヘッダ全文を保存すると認証情報らしきものを保持することになります。
今回の設計では、入力値そのものではなく、アクセスの事実とメタデータに絞ります。
15. 観測できる攻撃パターン
15.1 WordPress探索
例は次のとおりです。
/wp-login.php/wp-admin//xmlrpc.php
汎用BotによるCMS探索である可能性があります。WordPressを使っていないサーバにも大量に来るため、インターネット上の一般的なスキャン傾向を把握しやすいアクセスです。
15.2 設定ファイル探索
例は次のとおりです。
/.env/.git/config/config.php/settings.py
設定ファイル、認証情報、ソースコード管理情報の露出を狙った探索です。実環境でも同様のパスが露出していないか確認する材料になります。
15.3 管理画面探索
例は次のとおりです。
/admin//administrator//manager/html/phpmyadmin/
既知管理画面への総当たり探索です。Tomcat Manager、phpMyAdmin、CMS管理画面などを広く探している可能性があります。
15.4 リモートアクセス基盤探索
例は次のとおりです。
/vpn//remote/login/owa//ecp//rdweb/
VPN、メール、リモートデスクトップ、リモートアクセス基盤を狙っている可能性があります。この種のアクセスが増えている場合、実環境のVPN、IdP、メール基盤のログと比較する価値があります。
15.5 API探索
例は次のとおりです。
/api//v1//swagger//openapi.json/actuator/
API、管理エンドポイント、開発用エンドポイントの露出を狙っている可能性があります。Spring Boot Actuator、Swagger UI、OpenAPI定義ファイルなどは特に観測対象になりやすいパスです。
15.6 POST /login 連続試行
ブルートフォース、クレデンシャルスタッフィング、ログインフォーム探索の可能性があります。今回の設計では入力値を保存しないため、試行内容ではなく、頻度、送信元、User-Agent、時間帯を見ます。
16. セキュリティ設計
S-001 動的処理排除
PHP、CGI、Python、Node.jsなどを使いません。これにより、アプリケーション実装バグによる侵害を避けます。
S-002 POST本文非保存
ID/PASSの入力値を保存しません。認証情報らしき情報を保持すると、管理責任が増えます。今回の目的は「認証情報収集」ではなく「攻撃入口の観測」です。
S-003 認証成功なし
どのID/PASSでも成功させません。成功後画面を作ると、その画面自体が新たな攻撃面になります。
S-004 DocumentRoot書き込み禁止
Apache実行ユーザーにDocumentRootへの書き込み権限を与えません。Webシェル配置、改ざん、ファイル生成を防ぐためです。
S-005 外向き通信遮断
OSまたはクラウド側ファイアウォールで外向き通信を制限します。万一侵害されても、第三者への攻撃、C2通信、踏み台化をしにくくします。
S-006 管理ポート非公開
SSHをインターネットに公開しません。やむを得ず公開する場合は、接続元IPを限定します。ハニーポットよりもSSH自体が狙われる可能性が高いためです。
S-007 情報露出抑制
ApacheバージョンやOS情報を出しにくくします。不要な攻撃材料を与えないためです。
S-008 ログ保護
ログファイルの権限を制限します。攻撃観測情報の改ざんや削除を防ぎます。
S-009 容量制限
リクエストボディサイズ、ログローテーション、ディスク監視を設定します。ログ肥大化による停止を防ぎます。
17. ネットワーク設計
17.1 公開ポート
80/tcp443/tcp
17.2 非公開ポート
22/tcp- DBポート
- 管理ポート
- メトリクスポート
- その他すべて
17.3 外向き通信
原則拒否します。例外候補は次の程度に留めます。
- OSアップデート用のリポジトリ
- ログ転送先
- 時刻同期
ただし、MVPでは外向き通信なしでもよいです。
17.4 推奨配置
- 専用VPS
- 専用VM
- 専用クラウドインスタンス
- 内部ネットワークと接続しない
- 本番環境と同居しない
- 重要な認証情報を置かない
18. 運用設計
18.1 初期構築時
- 専用サーバを用意
- Apacheを最小構成で導入
- 不要モジュールを無効化
- 静的ファイルを配置
- Apache設定を適用
- 権限を読み取り中心に設定
- SSHを制限
- 外向き通信を制限
- logrotateを設定
- 動作確認
18.2 日次運用
- アクセスログ確認
- エラーログ確認
- ディスク容量確認
- POST
/login件数確認 - 404上位パス確認
18.3 週次運用
- 攻撃パス集計
- 送信元IP集計
- User-Agent集計
- 新規探索パス確認
- 403/404/405の傾向確認
18.4 月次運用
- 傾向レポート作成
- 本番環境との関連確認
- 不要な機能追加がないか確認
- OSとApacheの更新状況確認
- FW/WAF/SIEM側に反映すべき観点の整理
18.5 logrotate設計
ログ肥大化による停止を防ぐため、日次ローテーションを設定します。
/var/log/apache2/honeypot_access.log
/var/log/apache2/honeypot_error.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 root adm
sharedscripts
postrotate
/usr/sbin/apachectl graceful > /dev/null 2>&1 || true
endscript
}
19. 動作確認項目
19.1 トップページ確認
curl -i http://example.invalid/
期待結果は 200 OK です。
19.2 POST /login 確認
curl -i -X POST http://example.invalid/login -d 'user=test&password=test'
期待結果は次のとおりです。
303 See Other
Location: /login-failed.html
19.3 ログイン失敗画面確認
curl -i http://example.invalid/login-failed.html
期待結果は 200 OK です。
19.4 存在しないパス確認
curl -i http://example.invalid/wp-login.php
期待結果は 404 Not Found です。
19.5 .env 拒否確認
curl -i http://example.invalid/.env
期待結果は 403 Forbidden です。
19.6 .git 拒否確認
curl -i http://example.invalid/.git/config
期待結果は 403 Forbidden です。
19.7 TRACE拒否確認
curl -i -X TRACE http://example.invalid/
期待結果は 405 Method Not Allowed または拒否です。
19.8 ディレクトリ一覧拒否確認
curl -i http://example.invalid/assets/
期待結果は 403 Forbidden または 404 Not Found です。
19.9 アクセスログ確認
tail -f /var/log/apache2/honeypot_access.log
期待結果は、GET、POST、404、403が記録されることです。
19.10 POST本文非保存確認
確認内容は、honeypot_access.log に user=test や password=test が出ていないことです。期待結果は、POST本文が保存されないことです。
20. 受入基準
20.1 安全性
- PHPが無効である
- CGIが無効である
- Proxyが不要なら無効である
- DocumentRootへApache実行ユーザーが書き込めない
- SSHが公開されていない、またはIP制限されている
- 外向き通信が制限されている
20.2 画面
- ログイン画面が表示される
- ID/PASS欄がある
- POSTできる
- ログイン成功しない
- 失敗画面が表示される
- 外部CDNを使っていない
20.3 ログ
- POST
/loginがアクセスログに残る - 404探索パスがアクセスログに残る
- User-Agentが残る
- Hostヘッダが残る
- X-Forwarded-Forが残る
- POST本文は残らない
20.4 運用
- logrotateが設定されている
- ディスク容量を確認できる
- Apache再起動後も設定が有効
- エラー画面が表示される
21. 将来拡張
21.1 Phase 1:MVP
- Apache静的ハニーポット
- POST本文なし
- アクセスログ分析
まずはここまででよいです。最初から高対話型にしません。
21.2 Phase 2:ログ分析強化
- ログを別環境へ転送
- 簡易ダッシュボード化
- IP、AS番号、国別集計
- 本番環境ログとの突合
本体に分析機能を持たせず、別環境で分析するのが望ましいです。
21.3 Phase 3:検知専用mod_security
- mod_securityを検知専用で導入
- ルールヒット情報を取得
- ブロック目的ではなく観測目的
ただし、設定ミスや運用負荷が増えるため、MVPの後で検討します。
21.4 Phase 4:高対話型ハニーポット
- 別環境で高対話型ハニーポットを検討
- SSH、疑似ファイルシステム、疑似サービス等
- 今回のApache単体構成とは分離する
高対話型にする場合は、今回の構成とは別物として扱うべきです。
22. 結論
今回の簡易ハニーポットは、攻撃者を中に入れる罠ではなく、攻撃の入口を観測するための装置です。
設計の中心は次の考え方になります。
Apache単体
+
静的ログイン画面
+
ID/PASS入力欄
+
POST /login
+
303で失敗画面
+
POST本文非保存
+
404探索ログ分析
+
サーバ分離
+
外向き通信制限
得られる情報は、入力された認証情報そのものではありません。得るべき情報は次のようなメタデータです。
- 誰が来たか
- どのパスを探ったか
- どのUser-Agentか
- どのHostヘッダか
- どのHTTPメソッドか
- POST
/loginを試したか - どの頻度で来たか
- どのような404探索をしたか
逆に、取得しない情報も明確にします。
- 入力されたID
- 入力されたパスワード
- POST本文
- 認証成功後操作
- 攻撃者のファイル
- マルウェア
- コマンド履歴
ハニーポットは、情報を取りに行きすぎるほど危険になります。今回のように「侵害され、踏み台にされないこと」を最優先にするなら、収集能力を増やしすぎないことが重要です。
安全なハニーポットとは、攻撃者を深く誘い込むものではなく、攻撃者に余計な機能を与えず、入口の痕跡を静かに観測するものです。
付録A:最小ファイル一覧
/var/www/honeypot/
index.html
login-failed.html
assets/
style.css
app.js
error/
403.html
404.html
405.html
500.html
/etc/apache2/sites-available/
honeypot.conf
/etc/logrotate.d/
honeypot-apache
付録B:MVPチェックリスト
- Apacheのみで動いている
- PHPを使っていない
- CGIを使っていない
- DBを使っていない
- 外部CDNを使っていない
- ログイン画面が表示される
- ID/PASS入力欄がある
- POST
/loginができる - 認証成功しない
- 303で失敗画面へ遷移する
- POST本文がログに残らない
- 404探索パスがログに残る
- User-Agentがログに残る
- Hostヘッダがログに残る
- DocumentRootがroot所有である
- Apache実行ユーザーがDocumentRootに書き込めない
-
.envが403になる -
.git/configが403になる - ディレクトリ一覧が無効である
- TRACEが無効である
- logrotateが設定されている
- SSHが制限されている
- 外向き通信が制限されている
- 本番環境と分離されている
付録C:この設計で十分なケース・不十分なケース
十分なケースは次のとおりです。
- インターネット上のスキャン傾向を知りたい
- どのようなパスが狙われるか見たい
- POST
/loginの試行有無を見たい - User-AgentやIPの傾向を見たい
- 踏み台化リスクを極小化したい
- 低コストで始めたい
- Apacheだけで完結させたい
不十分なケースは次のとおりです。
- 攻撃者の侵入後操作を観測したい
- 入力されたID/PASSの傾向を分析したい
- マルウェアの配置挙動を見たい
- C2通信を見たい
- 攻撃者のシェル操作を見たい
- 高対話型ハニーポットを作りたい
この場合は、別環境で高対話型ハニーポットを検討します。ただし、その場合でも本番環境とは完全に切り離すべきです。