カテゴリー: PC Page 1 of 64

試作版:ipsetによるufwブロックの効率化スクリプト。

攻撃者の種は尽きまじという形。

この、ufwの効率化を図るスクリプトを試作です。

前提条件

上記リンク先にあるとおり、ipsetをipset-persistant抜きで入れている場合。なので、相当、対象者は限られます。

スクリプト内容

#!/bin/bash

# セット名の定義
SET_NAME="ufw-blocklist"
SAVE_FILE="/etc/ufw/ipsets.save"

# 1. root権限チェック
if [[ $EUID -ne 0 ]]; then
   echo "エラー: このスクリプトは sudo または root 権限で実行してください。"
   exit 1
fi

# 保存用関数
save_ipset() {
    read -p "設定をファイルに保存しますか? (y/n): " confirm
    if [[ "$confirm" =~ ^[Yy]$ ]]; then
        ipset save "$SET_NAME" -f "$SAVE_FILE"
        echo "保存完了: $SAVE_FILE"
    else
        echo "保存をスキップしました(メモリ上の設定のみ更新)。"
    fi
}

# ipsetが存在しない場合に作成
if ! ipset list "$SET_NAME" > /dev/null 2>&1; then
    echo "情報: $SET_NAME が見つからないため新規作成します。"
    ipset create "$SET_NAME" hash:net
fi

while true; do
    echo "------------------------------------------"
    echo " ipset 管理メニュー ($SET_NAME)"
    echo "------------------------------------------"
    echo "1) IP/ネットワークを追加 (例: 198.51.100.42, 203.0.113.0/24)"
    echo "2) IP/ネットワークを削除"
    echo "3) ステータス表示 (list)"
    echo "q) 終了"
    echo "------------------------------------------"
    read -p "番号を選択してください: " choice

    case $choice in
        1)
            echo "--- 追加モード ---"
            read -p "追加する IP/NW: " target
            if [ -n "$target" ]; then
                if ipset add "$SET_NAME" "$target"; then
                    echo "追加成功: $target"
                    save_ipset
                fi
            fi
            ;;
        2)
            echo "--- 削除モード ---"
            read -p "削除する IP/NW: " target
            if [ -n "$target" ]; then
                if ipset del "$SET_NAME" "$target"; then
                    echo "削除成功: $target"
                    save_ipset
                fi
            fi
            ;;
        3)
            echo "--- 現在のリスト ---"
            ipset list "$SET_NAME"
            ;;
        q)
            echo "終了します。"
            exit 0
            ;;
        *)
            echo "無効な選択です。"
            ;;
    esac
    echo ""
done

後は

sudo chmod 755 ipset-block.sh

等として実行権限を付与。

sudo bash ipset-block.sh

等で実行することで

------------------------------------------
 ipset 管理メニュー (ufw-blocklist)
------------------------------------------
1) IP/ネットワークを追加 (例: 198.51.100.42, 203.0.113.0/24)
2) IP/ネットワークを削除
3) ステータス表示 (list)
q) 終了
------------------------------------------

番号表示。

--- 追加モード ---
追加する IP/NW: 

で、IP/NWを設定すれば、後はセーブまでしてくれます。

今後の展望

  • 引数
  • ファイルからの一括入力
  • 既にあるリストとの突き合わせ

など。興味は尽きません。

Ubuntu 24.04にapache mod_securityを導入。

ApacheのWAFモジュールであるmod_securityを導入します。

  • AWS 時代から早々とインストールしていた
  • 各種不審なIPアドレスを弾くための盾

として機能している、筆者のVPS運用の核となる技術。その2026年版です。

そもそもWAFとは?

WAFとはWeb Application Firewallの略で、Webアプリケーション層の脆弱性を狙った攻撃を防ぐためのセキュリティシステムです。

  • UFWやFail2banがIPアドレスやポート番号といった家の玄関を監視するのに対し、WAFは、Webサーバーへ届く手紙(HTTPリクエスト)の中身を解析し、悪意あるスクリプトやコマンドの有無をチェックします。
  • UFWでは、通常のポート(80番や443番)を通る攻撃は防げませんが、WAFは攻撃の内容を解析し、独自のルールセットに基づき「このアクセスは許可するが、このコードがアクセスすることは許可しない」という、より柔軟で厳しいセキュリティチェックを施します。

この機能により、Webサーバーやアプリケーション本体に脆弱性が見つかったとしても、WAFが前段の盾としてこれをカバーできます。

ModSecurityとは?

ModSecurityは、IIS/Apache/Nginxといった主要なWebサーバープログラムにモジュールとして組み込みが可能なオープンソースのWAFです。

  • 導入コスト: ライセンス費用が不要であり、既存のWebサーバーと連携する形で容易に組み込めます。
  • 柔軟性: OSSであるため、高い柔軟性を持ち、設定(チューニング)次第でピンポイントの防御や包括的な防御を併せ持つことができます。

備考(バージョンの選択):

本稿で導入するModSecurityは、Ubuntu 24.04系のパッケージ管理で提供されるEOL (End-of-Life) となっているv2ですが、機能性は単一VPSの防御としては十分です。

v3への移行は、セキュリティ強度とメンテナンス性を考慮し、パッケージ化ないしはOSアップデートなどのタイミングでまた後日検討していきます。

環境

  • Ubuntu 24.04 (22.04でも動作確認)
  • Apache 2.4

※ パッケージ管理にaptitudeを用いています。必要に応じてaptに読み替えてください。

さっくりとした手順

  1. mod_securityのインストールを行います。
  2. mod_securityの設定を行います。
  3. Apacheのバーチャルサイトにmod_securityを組み込みます。
  4. 設定を反映して動作を確認します。

mod_securityのインストールを行います。

  • パッケージ全体のアップデート
sudo aptitude update
  • mod_securityインストール
sudo aptitude install libapache2-mod-security2
  • インストール確認
sudo apache2ctl -M |grep security
security2_module (shared)

と表示されていることを確認します。

ModSecurityの設定

  • 設定ファイル書き換え
sudo mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

推奨ファイルをそのまま設定ファイルとして書き換えます。

OWASP Core Rule Set (CRS)のインストールと設定

  • ディレクトリ移動
cd /usr/share/modsecurity-crs && pwd
  • ルールセットのダウンロード
sudo git clone https://github.com/coreruleset/coreruleset.git
  • ルールセットの設定書き換え
sudo mv /usr/share/modsecurity-crs/coreruleset/crs-setup.conf.example /usr/share/modsecurity-crs/coreruleset/crs-setup.conf

mod_securityモジュールにCRSを読み込む設定を追記

  • ディレクトリ移動
cd /etc/apache2/mods-available/ && pwd
  • ファイルのバックアップ
sudo cp -pi security2.conf /path/to/backup/directory/security2.conf.$(date +%Y%m%d)

任意のバックアップディレクトリを指定します。

  • バックアップ確認
diff -u /path/to/backup/directory/security2.conf.$(date +%Y%m%d) security2.conf

エラーがなければバックアップは成功です。

  • ファイル追記

/etc/apache2/mods-available/security2.confを、以下の差分になるように教義・信仰に沿ったエディタで編集します。(要root権限)

 <IfModule security2_module>
-       # Default Debian dir for modsecurity's persistent data
-       SecDataDir /var/cache/modsecurity
+    # Default Debian dir for modsecurity's persistent data
+    SecDataDir /var/cache/modsecurity

-       # Include all the *.conf files in /etc/modsecurity.
-       # Keeping your local configuration in that directory
-       # will allow for an easy upgrade of THIS file and
-       # make your life easier
-        IncludeOptional /etc/modsecurity/*.conf
+    # Include all the *.conf files in /etc/modsecurity.
+    # Keeping your local configuration in that directory
+    # will allow for an easy upgrade of THIS file and
+    # make your life easier
+    IncludeOptional /etc/modsecurity/*.conf

-       # Include OWASP ModSecurity CRS rules if installed
-       IncludeOptional /usr/share/modsecurity-crs/*.load
+    # --- OWASP Core Rule Set (CRS) の読み込み ---
+
+    # 1. CRSのセットアップファイルを読み込む(必須)
+    IncludeOptional /usr/share/modsecurity-crs/coreruleset/crs-setup.conf
+    
+    # 2. CRSのルールファイルを読み込む
+    #    パフォーマンス問題を起こすSQLデータ漏洩検知ルールを除外
+    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/REQUEST-*.conf
+    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-950-DATA-LEAKAGES.conf
+    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf
+    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf
+    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf
+    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-959-BLOCKING-EVALUATION.conf
+    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-980-CORRELATION.conf
+    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf

→ 修正後のsecurity2.conf全文

<IfModule security2_module>
    # Default Debian dir for modsecurity's persistent data
    SecDataDir /var/cache/modsecurity

    # Include all the *.conf files in /etc/modsecurity.
    # Keeping your local configuration in that directory
    # will allow for an easy upgrade of THIS file and
    # make your life easier
    IncludeOptional /etc/modsecurity/*.conf

    # --- OWASP Core Rule Set (CRS) の読み込み ---

    # 1. CRSのセットアップファイルを読み込む(必須)
    IncludeOptional /usr/share/modsecurity-crs/coreruleset/crs-setup.conf

    # 2. CRSのルールファイルを読み込む
    #    パフォーマンス問題を起こすSQLデータ漏洩検知ルールを除外
    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/REQUEST-*.conf
    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-950-DATA-LEAKAGES.conf
    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf
    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf
    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf
    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-959-BLOCKING-EVALUATION.conf
    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-980-CORRELATION.conf
    IncludeOptional /usr/share/modsecurity-crs/coreruleset/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
</IfModule>

※ なぜここまで除外するか?

この、RESPONSE-9x系のルールは、ページの内容に機密情報(クレジットカードのデータなど)が入っていないかを精査します。

これは重要なものですが、昨今のAIボットによる過剰なクロールが挟むと、サーバそのものへの負荷を強め、更にログの圧迫(実際にサーバ容量120GB全てを食い尽くしました)とサーバダウンにつながります。

こちらは個人サイト、単一VPSの運用を旨としているため、ここに関するデータはオミットです。 その分、他の設定の補強でセキュリティ強度を担保します。

例外ルールを追記

/usr/share/modsecurity-crs/coreruleset/rules && pwd

配下に

REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.confファイルを作成します。

#
# === CRS Exclusions - Before Rules Execution (Organized) ===
#

# ===================================================================
# 1. 共通ルール・汎用ルール (General/Common Rules)
# ===================================================================

# 1-1. 遅い通信(Slowloris)対策
# 矛盾するConnectionヘッダーを持つリクエストを遮断
SecRule REQUEST_HEADERS:Connection "@rx (?i)(?:keep-alive(?:,\sclose|,\skeep-alive)|close(?:,\skeep-alive|,\sclose))" \
    "id:10001,phase:1,t:none,block,msg:'[CUSTOM RULE] Contradictory Connection header, possible Slowloris probe.',tag:'application-attack',tag:'PROTOCOL_VIOLATION/INVALID_HREQ',setvar:'tx.inbound_anomaly_score_pl1=+%{tx.critical_anomaly_score}'"

# 1-2. IPアドレス直打ちアクセス対策
SecRule REQUEST_HEADERS:Host "@rx ^[\d.]+(:\d+)?$" \
    "id:10002,\
    phase:1,\
    deny,\
    status:404,\
    log,\
    msg:'[CUSTOM RULE] Host header is a numeric IP address (incl port). Blocked immediately.',\
    tag:'application-attack',\
    tag:'PROTOCOL_VIOLATION/INVALID_HREQ'"

# 1-3. Hostヘッダーが存在しない場合は即ブロック
SecRule &REQUEST_HEADERS:Host "@eq 0" \
    "id:10003,\
    phase:1,\
    deny,\
    status:404,\
    log,\
    msg:'[CUSTOM RULE] Missing Host Header. Blocked immediately.'"

なぜこの設定が必要なのか?

「雑なスキャナー/クローラーをまとめてブロックする」にあります。

  • 攻撃者は、 Connection: keep-alive, close という通常ではありえないヘッダーでサーバを枯渇させることが非常に多いです。(Slowloris などのDoS攻撃ツール)
  • 攻撃者のほぼ大半は、ドメイン名ではなくIPアドレスを指定。そして、Hostヘッダーを指定せずに無差別にスキャンを行います。

「ブラウザを用いて実際にアクセスする」方が

  • 矛盾したヘッダー
  • IPアドレス直打ち
  • Hostヘッダー抜きのアクセス

はあり得ません。これら雑なスキャナー/クローラーにWAFの計算力を与える必要はありません。

  • 設定追記の整合性を確認
sudo apache2ctl configtest

Syntax OKを確認します。

  • Apache再起動
sudo systemctl restart apache2.service
  • Apache再起動確認
systemctl status apache2.service

active (running) を確認します。

Apacheのバーチャルサイト編集

稼働済みのApacheバーチャルサイトの設定ファイルをいじります。バックアップ確認は入念に行ってください。

  • ディレクトリ移動
cd /etc/apache2/sites-available && pwd
  • バーチャルサイトの設定ファイルバックアップ
sudo cp -pi your_site.conf /path/to/backup/directory/your_site.conf.$(date +%Y%m%d)

.confファイルやバックアップディレクトリは自分の環境を指定します。

  • バックアップ確認
diff -u /path/to/backup/directory/your_site.conf.$(date +%Y%m%d) your_site.conf

エラーがなければバックアップは成功です。

  • ファイル追記

/etc/apache2/sites-available/your_site.confを、以下の差分になるように教義・信仰に沿ったエディタで編集します。(要root権限)

# Mod Security

## ModSecurity有効化
SecRuleEngine On
## ModSecurity検知モード
### 検知モードで動かす場合はSecRuleEngine Onをコメントアウトしてこちらを有効化します
#SecRuleEngine DetectionOnly

## ファイルのアップロードをできるようにします。
SecRequestBodyInMemoryLimit 524288000
SecRequestBodyLimit 524288000

## テスト用の検知パラメータを付け加えます。
    SecRule ARGS:modsecparam "@contains test" "id:4321,deny,status:403,msg:'ModSecurity test rule has triggered'"
  • ファイル差分
diff -u /path/to/backup/directory/your_site.conf.$(date +%Y%m%d) your_site.conf
+# Mod Security
+
+## ModSecurity有効化
+SecRuleEngine On
+## ModSecurity検知モード
+### 検知モードで動かす場合はSecRuleEngine Onをコメントアウトしてこちらを有効化します
+#SecRuleEngine DetectionOnly
+ 
+## ファイルのアップロードをできるようにします。
+SecRequestBodyInMemoryLimit 524288000
+SecRequestBodyLimit 524288000
+
+## テスト用の検知パラメータを付け加えます。
+    SecRule ARGS:modsecparam "@contains test" "id:4321,deny,status:403,msg:'ModSecurity test rule has triggered'"
+
  • 設定追記の整合性を確認
sudo apache2ctl configtest

Syntax OKを確認します。

  • Apache再起動
sudo systemctl restart apache2.service
  • Apache再起動確認
systemctl status apache2.service

active (running) を確認します。

mod_security動作確認

  1. ブラウザで、上記の設定を行ったWebサイトにアクセスし、閲覧できることを確認します。
  2. アドレスバーの末尾に?modsecparam=testを追加してアクセスします。

403 Forbidden

のように、アクセスできないことを確認します。

また、サーバでも

sudo cat /path/to/sites_log/directory/sites_error.log

※ログの格納場所やログの名前は自分の環境に合わせます。

を開き、

ModSecurity: Access denied with code 403 (phase 2). String match "test" at ARGS:modsecparam. [file "/etc/apache2/sites-enabled/your_site.conf"] [line "53"] [id "4321"] [msg "ModSecurity test rule has triggered"] [hostname "host_address"] [uri "/"] [unique_id "xxxxxxx"]

のように、エラーが発生していることを確認します。

備考

WordPress、Redmine等のWebアプリは自身の操作によって「不審なアクセス」として遮断することが極めてよくあります。(偽陽性)

そのため、テストを行った後は

## ModSecurity有効化
#SecRuleEngine On
## ModSecurity検知モード
### 検知モードで動かす場合はSecRuleEngine Onをコメントアウトしてこちらを有効化します
SecRuleEngine DetectionOnly

として検知モードとして動かした方が良いでしょう。

Mod_Securityが検知した「点火テスト」確認

Webサーバを運営していてよかったことの一つは、「悪意ある攻撃」をリアルタイムで見られること、に尽きます。

2026/02/17も、そのようなログを見かけました。どのような攻撃で、どんな悪意があったのかのメモです。

さっくりとした攻撃概要

  1. 攻撃者はNode.js系のサービスが生きているかを確認した。
  2. その上で、サーバ乗っ取りを画策した。

環境・備考

  • Apache 2.4
  • ModSecurity v2 / CRSを利用

以下、ご紹介するログは実際のログですが、

  • IPアドレス
  • どのサイトに来たか

は別のものに置き換えています。これはプライバシー配慮という点ではなく「攻撃者に名前を与えない」から来るものです。

攻撃ログ(抜粋)

攻撃者は、Unix系とWindows系の両方のサーバーを想定し、2回に分けて「点火テスト」を試みています。

A. Unix/Linuxターゲットのペイロード

[Tue Feb 17 03:16:50 2026] [security2:error] [client 192.0.2.55] 
ModSecurity: Access denied with code 403 (phase 2). 
[id "932130"] [msg "Remote Command Execution: Unix Shell Expression Found"]
[id "934100"] [msg "Node.js Injection Attack 1/2"]

[data "Matched Data: var res=process.mainModule.require('child_process').execSync('echo $((40261*44548))').toString().trim(); ..."]

[hostname "sub.example.jp"] [uri "/"]

B. Windowsターゲットのペイロード

[Tue Feb 17 03:16:51 2026] [security2:error] [client 192.0.2.55] 
ModSecurity: Warning. [id "932120"] [msg "Remote Command Execution: Windows PowerShell Command Found"]
[data "Matched Data: var res=process.mainModule.require('child_process').execSync('powershell -c 40261*44548').toString().trim(); ..."]

攻撃の構造解析:何が行われようとしたのか

この攻撃はサーバー乗っ取りを目的としたものです。

「点火テスト」による生存確認

攻撃コードの中にある 40261*44548 という計算式が肝です。

  • 手口:
    • サーバー上でこの計算を実行させ、その結果(1,793,526,428)をレスポンスとして返させようとしています。
  • 意図:
    • もし計算結果が返ってくれば、そのサーバーは「外部からの命令をそのまま実行する状態」にあることが証明され、攻撃者は本格的なマルウェアの設置へ移行します。

Node.jsの深部への侵入

  • 手口:
    • process.mainModule.require('child_process') という、Node.jsの最も強力な権限を持つ命令を呼び出そうとしています。
  • 意図:
    • これが成功すると、サーバー上で任意のOSコマンド(ファイルの削除、パスワードの窃取など)が実行可能になります。

プロトタイプ汚染 (Prototype Pollution)

  • 手口:
    • __proto__ という特殊なプロパティを操作しようとしています。
  • 意図:
    • アプリケーション全体の挙動を「根底から書き換える」手法です。Next.jsの内部ロジックを捻じ曲げ、セキュリティチェックをバイパスしようとしています。

特記事項

今回のログで最も注目すべきは、ModSecurityの異常スコア(Anomaly Score)が 45点〜50点というそこそこ高い数値を叩き出している点です。

  • Unixシェルの構文検知(RCE)
  • Node.jsの危険な関数検知(Injection)
  • プロトタイプ汚染の検知(JavaScript攻撃)
  • PowerShellの使用検知(Windows攻撃)

これら複数のフィルタが同時にに反応したため、ModSecurityはこれは間違いなく脅威であると断定し、即座に遮断しました。

まとめ

攻撃は「いきなり行う」というよりは「どの攻撃が効くか」を確認してからリソースを集中していきます。なので、実際のログを見て「これが攻撃の前段階である」をつかんでおくのは大事。(そのためのログ確認です)

『孫子 虚実篇 六』の

「攻めて必ず取る者は、其の守らざる所を攻むればなり。守って必ず固き者は、其の攻めざる所を守ればなり」

これは、守備側に立たされるサーバ管理者も持っておきたい心構えだと思いました。

Nextcloud、ドメイン変更時のメモ。

正直、かなり甘く見ていました。

やろうとしたこと

a.hoge.comというサブドメインでNextcloudを立ち上げて運用していたのですが、唐突にexample.comというネイキッドドメインで運用しようとしたのがきっかけ。

当初の手順

  1. DBバックアップ
  2. 設定ファイルバックアップ(apacheバーチャルサイトとNextcloudのconfファイル)
  3. 新DNSレコード変更
  4. apacheバーチャルサイトのURL変更およびSSL証明書の差し替え
  5. NextcloudのconfファイルのURL変更
  6. Apache / PHP-FPM再起動

まではすんなりいきました。

URL変更後の苦行

Nextcloudは単なるファイルストレージではなく、統合コラボスイート。非常に多岐にわたって運用していたんだと改めて痛感。

  • デスクトップクライアント
  • スマートフォンアプリ
  • ブックマークの変更

がそれなりにヘビー。それ以上にヘビーだったのが

  • 高性能バックエンド
  • AppAPI

の設定変更を忘れていたことでした。

DBと参照ディレクトリ変更の更なる苦行

また、動作確認後、「DBの向き先とNextcloud格納ディレクトリが新ドメインに即していない」ことがわかり、

  1. apacheのconfファイルをいったん無効化
  2. 再度DBバックアップ(サイト名などを変えていたため)
  3. DB及びユーザー新規作成作成
  4. 再バックアップしていたDBから新DBにデータ流し込み
  5. Nextcloud格納ディレクトリを-pirオプションをつけてコピー&リネーム
  6. Nextcloudのconfigを修正。DBのユーザ名とDB名を新しく作成したDBに変更
  7. ログ格納ディレクトリを新規作成、www-dataに所有者変更
  8. apacheのconfファイルの格納ディレクトリとログ格納ディレクトリの向き先変更
  9. /etc/logrotate.d配下のローテーションを新しいログ格納ディレクトリに変更
  10. apacheのconfファイル有効化
  11. apache再起動
  12. Nextcloudのcronを新ディレクトリに合わせる

までやって、完全移行が完成しました。

「サーバリプレースとどう違うのか」レベルではありましたが、うまくいって良かったです。

詳細な手順は相当なボリュームになりそうなので、様子を見て描いていきます。

ネイキッドドメインでSSL証明書を取得したかどうかを確認するための手順

概要

筆者はletsencryptでワイルドカード証明書を取得していますが、

*.example.com

の証明書を取得して、

example.com

の、「サブドメインが付かないドメインそのもの」 (hoge.example.com / foo.example.com / supercalifragilisticexpialidocious.example.com等を 含まない ドメイン)、いわゆるネイキッドドメインでの証明書を取っていないかどうかの確認手順です。

重要な仕様

割と躓きやすい仕様ですが、

*.example.comは、example.comを含みません。

ワイルドカード証明書は「何か」.example.comにマッチする証明書。つまり、この「何か」が空文字にならないルールです。

筆者が過去の記事でletsencryptで証明書を作成する際

certbot certonly --manual \
    --preferred-challenges dns \
    --server https://acme-v02.api.letsencrypt.org/directory \
    -m あなたの有効なメールアドレス@example.com \
    -d "*.example.com" \
    -d "example.com"

と、

  • -d "*.example.com"
  • -d "example.com"

のように、ワイルドカードとネイキッドドメインの両方を含めているのはまさにその理由です。

これを忘れたことによるありがちなエラー

*.example.com だけ取得

https://example.com にアクセス

証明書エラー

「え、ワイルドカードなのに!?」

という事態が多く発生します。

ネイキッドドメインの証明書を取得したか

以下の2つのコマンドを用います。

Let's encryptを利用している場合

非常に簡単です。

sudo certbot certificates

と実行するだけ。

 Certificate Name: example.com
    Serial Number: UID]
    Key Type: ECDSA
    Identifiers: *.example.com example.com

のように、Identifiersの欄に.*がついているとついていないドメインがついていればOKです。

Let's encryptを利用していない場合

openssl x509 -in /path/to/certs/directory/cert.pem -noout -text | grep -A1 "Subject Alternative Name"

と実行。(証明書の場所は合わせます)

X509v3 Subject Alternative Name: 
DNS:*.example.com, DNS:example.com

のように、DNSの欄に.*がついているとついていないドメインがついていればOKです。

以上、実務で予め両方の証明書を取得していれば「なんてことない」仕様ですが、これを取得していない場合のSSL再取得の手間はかなり手間です。

UbuntuサーバからIPv6を削除

「時代はIPv6」と呼ばれてから四半世紀。未だにIPv4が幅をきかせているという状態。

  • DNSの都合上、IPv4でないと困る
  • IPv6は管理で手に負えない

等の問題を抱えている運用者(つまり私)のため、「カーネルレベルでIPv4のみにする」手順のメモです。

環境

  • Ubuntu 24.04

そろそろUbuntu 26.04が出るタイミングではありますが、おそらく大幅な変化はないでしょう。

さっくりとした手順

  1. 現状を確認します。
  2. sysctlでIPv6を無効化するファイルを作成します。
  3. 作成したファイルを有効化してIPv6を無効化します。
  4. (利用している方は)ufw側の設定でIPv6を無効化します。

作業の前に

  • 本作業はカーネルをいじります。つまり、神経を使うという作業です。
  • 念には念を入れてサーバ再起動も伴います。

構築作業であれば好きなタイミングでサーバ再起動ができる環境を祝いましょう。
本番運用であればタイミングを調整する政治交渉が必要な環境を呪いましょう。

現状の確認

  • IPv6アドレス割当の確認
ip -6 addr

アドレスが返ってくればIPv6アドレスは有効化されています。何も表示されていなければ、ここからの作業は不要です。

ファイル追記

cat <<- __EOF__ | sudo tee -a /etc/sysctl.d/99-disable-ipv6.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
__EOF__

元々存在しないファイルなのでコマンドで流し込みます。

設定反映

  • 設定反映
sudo sysctl --system

エラーがなければOKです。

  • 設定反映確認
ip -6 addr

IPv6アドレスが無いことを確認します。

  • 念のためのサーバ再起動
sudo reboot

サーバ再起動を行います。

  • 再起動後にIPv6がないことを確認
ip -6 addr

link-local IPv6のみが見えていればOKです。(NICの中でのみ使えるv6アドレスです)

(オプション)ufwでIPv6の無効化

※この作業はufwをいじります。ufwを有効化しているという方は、下手にいじると自分自身がロックアウトされる怖さを知っていると思います。

慎重に、深呼吸をするなり飲み物を飲むなどして落ち着かせてから作業を行いましょう。もっと具体的に言うと

  • 物理環境であればコンソール近くにいること
  • vps環境はWebコンソールを開いて
  • SSH接続しかない場合は新規セッションで接続を維持する

の作業を推奨します。(この場合の推奨は義務という意味です

  • ufw設定ファイルのバックアップ
sudo cp -pi /etc/default/ufw /path/to/backup/directory/ufw.$(date +%Y%m%d)

任意のバックアップディレクトリを指定します。

  • ファイルのバックアップ確認
diff -u /path/to/backup/directory/ufw.$(date +%Y%m%d) /etc/default/ufw

差分が無いことを確認します。

  • ファイル修正

以下のような形で修正します。

IPV6=yes

これを

#IPV6=yes
#yyyy/mm/dd IPv6無効
IPV6=no

という形です。

日付管理をしないと「万が一のことがあったときにどっからおかしくなったか」を管理しやすくなります。同様に、コメントin/outとすることで切磋の対応をしやすくします。

  • ファイル修正確認
diff -u /path/to/backup/directory/ufw.$(date +%Y%m%d) /etc/default/ufw
-IPV6=yes
+#IPV6=yes
+#yyyy/mm/dd IPv6無効
+IPV6=no
  • ufw再起動

三回ぐらい深呼吸をしましょう。

sudo ufw reload

最終確認

  • IPv6無効化確認
ip -6 addr

link-local IPv6のみが見えていればOKです。

  • LISTENがない
ss -lntup | grep :::  

v6 のLISTENがないことを確認します。

  • ufw確認
sudo ufw status verbose

IPv6に関わるルールが無いことを確認します。

まとめ

以上、「IPv6無効」と簡単に言うけれど、言うほど簡単では無いという作業でした。

ASNとは何か?インターネットの“住所録”を支える番号と「盗人宿」の把握

インターネットの通信は、単にIPアドレスだけで動いているわけではありません。
その裏側には ASN(Autonomous System Number) という仕組みがあり、これが世界中のネットワークをつないでいます。

本記事では、

  1. ASNとは何か
  2. なぜ存在するのか
  3. セキュリティ運用でどう役立つのか

を順番に解説します。

ASNとは何か

ASNは:

インターネット上の「組織単位の番号」

です。

もう少し正確に言うと:

独立したネットワークを運用する組織に割り当てられる識別番号

です。

例えば:

組織ASN
Amazon AWSAS14618
GoogleAS15169
MicrosoftAS8075
NTTAS2914

IPアドレスが「端末の住所」だとすると、ASNは「プロバイダや企業の名前札」

のようなものです。

なぜASNが必要なのか

インターネットは巨大なネットワークですが、実態は無数のネットワーク同士の集合体です。

各プロバイダ、クラウド事業者、大学、企業はそれぞれ独立したネットワークを持っています。

この独立した単位をAutonomous System(AS)

と呼びます。そしてその識別番号が ASNです。

郵便で例えると

  • IPアドレス = 家の住所
  • ASN = 市区町村

と考えていただくと分かりやすいでしょう。

郵便物はまず「市区町村」に届き、そこから各家庭へ配送されます。

インターネットでも:

  1. まずAS単位でルーティング
  2. その中でIP単位に配送

という仕組みになっています。

BGPとASN

ASNが本領を発揮するのは:

  • BGP(Border Gateway Protocol)

というルーティングプロトコルです。

BGPは「どのネットワークがどのIPを持っているか」

を世界中で共有する仕組みです。

例えば:

このIPレンジはAS14618(Amazon)が持っています

という情報を各AS同士が交換しています。

これによって世界中のルータが最適な経路を選べる

ようになります。言い換えるなら、ASNとBGPがなければ、現在の規模のインターネットは成立しません。

セキュリティ運用でのASNの意味

サーバーログを見ると攻撃IPがどこから来ているかを知りたくなりました。

そこで、ASN単位でみることにしました。

なぜ運用者はASNを見るのか

筆者が運用しているVPSはONE OUTSという独自防御システムを敷いていますが、ここでの防御は

  • IP単体BAN
  • ASN単位防御

なぜなら、多くの攻撃者は海外の規制が緩いプロバイダ/組織を隠れ蓑にしています。

  • 利用の際に厳格な身分証明がなく
  • 当局の規制が緩い(どころかそういう行為を推奨している

(『鬼平犯科帳』で言うなら「盗人宿」の概念です。

実際の例

では、そういったASNをどのように調べるのか?

Linuxでは使いやすいコマンドが存在します。

whois -h whois.cymru.com " -v 8.8.8.8"

と打ってみます。(言わずと知れたGoogleのDNSです

AS      | IP               | BGP Prefix          | CC | Registry | Allocated  | AS Name
15169   | 8.8.8.8          | 8.8.8.0/24          | US | arin     | 2023-12-28 | GOOGLE - Google LLC, US
  • ASN
  • 事業者
  • IPレンジ

が見えてきたという次第。これをサーバのログから調べるのはかなり困難なので、以下のようなワンライナーを組んでみました。

エラーログからIPを抽出し、一意にソートしてWHOIS情報(AS番号、国、事業者名)を取得します。

grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' /var/log/apache2/web_server_error.log \
| sort -u \
| while read ip; do
    whois -h whois.cymru.com " -v $ip" | tail -n1
  done

以下、無害化した解析結果テーブルです。(無害化に関してはAIの力を借りています

AS      | IP               | BGP Prefix          | CC | Registry | Allocated  | Info (Sanitized)
--------|------------------|---------------------|----|----------|------------|-------------------------------------------
58466   | 106.75.x.x       | 106.75.144.0/20     | CN | apnic    | 2011-03-23 | Major ISP / IDC Network (CN)
4837    | 123.139.x.x      | 123.138.0.0/15      | CN | apnic    | 2007-02-28 | China Network Backbone
8075    | 13.86.x.x        | 13.64.0.0/11        | US | arin     | 2015-03-26 | Global Cloud Service Provider (MS)
14061   | 144.126.x.x      | 144.126.208.0/20    | US | arin     | 2020-01-09 | Cloud Hosting / VPS Provider (DO)
212238  | 149.40.x.x       | 149.40.50.0/24      | US | arin     | 1992-01-28 | International Content Delivery Network
396982  | 162.216.x.x      | 162.216.150.0/24    | US | arin     | 2013-07-02 | Global Cloud Infrastructure (G)
51167   | 173.212.x.x      | 173.212.224.0/20    | DE | ripencc  | 2009-10-26 | European VPS/Dedicated Server Provider
211298  | 185.247.x.x      | 185.247.137.0/24    | GB | ripencc  | 2018-03-01 | Cyber Security Research Entity
213412  | 195.184.x.x      | 195.184.76.0/24     | FR | ripencc  | 2022-11-09 | Internet Scanning & Security Platform
398324  | 206.168.x.x      | 206.168.34.0/24     | US | arin     | 2022-10-26 | Global Threat Intelligence Scanner
14618   | 34.224.x.x       | 34.224.0.0/12       | US | arin     | 2016-09-12 | Global Cloud Services (AWS)
132203  | 43.153.x.x       | 43.153.0.0/18       | SG | apnic    | 1989-02-21 | Asia-Pacific Cloud Network (T)
6939    | 65.49.x.x        | 65.49.0.0/17        | US | arin     | 2007-10-04 | International Internet Backbone Provider
200593  | 91.202.x.x       | 91.202.233.0/24     | RU | ripencc  | 2008-03-03 | Eastern European Network Services

注意点

ログが数万行に及ぶ環境ではこの解析は膨大なものになります

head -50 /var/log/apache2/web_server_error.log | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' \
| sort -u \
| while read ip; do
    whois -h whois.cymru.com " -v $ip" | tail -n1
  done

とした方が良いでしょう。

まとめ

こうして、ASNを調べることができれば、先に示した「悪辣な攻撃を行うクローラー/攻撃者が潜む盗人宿」的な事業体/ASNという、「盗人宿」ごとの対策が容易に行えます。

悪を知らぬものが悪を取り締まれるか

という「鬼平」の言葉を元にログを調べていく手法について紹介しました。

Matomo、強制SSL接続の実施

環境

  • Matomo 5.7.0
  • PHP-FPM8.3
  • Ubuntu 24.04

を利用中、Matomoの管理画面で

安全な SSL 接続のみで Matomo を使用することをお勧めします。 Http で安全でないアクセスを防ぐには、Matomo config / config.ini.php ファイルの General セクションに force_ssl = 1 を追加します。

と警告があったので、これに対処したときのメモです。

そもそもの問題として:SSL化することの意義

通信の盗聴と改ざんの防止(中間者攻撃対策)

HTTP(暗号化されていない接続)を利用している場合、ブラウザとサーバー間の通信内容はすべてプレーンテキスト(平文)で流れます。

  • ログイン情報の保護:
  • 管理画面にログインする際のユーザー名やパスワードがネットワーク上で丸見えになります。
  • 解析データの保護:
  • 収集しているアクセスログやレポートデータが第三者に盗み見られるリスクがあります。
  • 改竄防止:
  • 通信の途中でJavaScriptを注入されるなどの改竄を防ぎ、Matomoの正確な動作を保証します。

Cookie(セッション情報)の安全な送信

Matomoは管理者のログイン状態を保持するためにCookieを使用します。

  • セッションハイジャックの防止:
    • HTTPSを強制しない場合、ログイン状態を証明する「セッションID」が暗号化されずに送信される可能性があります。これが攻撃者に盗まれると、パスワードを知らなくても管理者としてログイン(なりすまし)されてしまいます。
  • Secure属性の有効化:
    • SSLを強制することで、ブラウザに対して「このCookieはHTTPS通信の時のみ送信する」という指示(Secure属性)が正しく機能するようになります。

ブラウザのセキュリティ仕様への対応

近年のWebブラウザ(Chrome, Firefox, Safariなど)は、セキュリティを重視しており、HTTP接続に対して厳格な制限を設けています。

  • SameSite属性の制限: 多くのブラウザでは、Cookieの SameSite=None 属性を利用する場合、Secure 属性(=HTTPS)が必須となっています。SSLを強制しないと、Matomoのトラッキングコードが正しく動作しなかったり、ログインが維持できなかったりする不具合の原因になります。
    -「保護されていない通信」の警告: HTTPでアクセスするとブラウザのアドレスバーに警告が表示され、ユーザーや管理者に不安を与えます。

リファラ(参照元)情報の保持

Webサイトの計測において重要な「どこから来たか」という情報(リファラ)は、「HTTPSのページからHTTPのページへ移動する際」にはセキュリティ上の理由でブラウザによって削除されることが一般的です。

もしMatomoのサーバーがHTTPで動作していると、HTTPS化されたサイトからの流入元データが取得できず、解析精度が著しく低下します。

筆者のサイトでは既に、apacheのバーチャルホスト設定で

<VirtualHost _default_:80>
ServerName hoge.example.com
 RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

としていますが、念には念を入れます。

大前提

「ドメインに即した証明書を取得していること」

が必要です。(設定メモ

さっくりとした手順

  1. matomoの.confファイルのバックアップを取ります。
  2. matomoの.confファイルの編集を行います。
  3. 設定を反映します。

matomoの.confファイルのバックアップ

  • バックアップディレクトリへコピー
sudo cp -pi /path/to/matomo/config/config.ini.php /path/to/backup/directory/conf_backup/config.ini.php.$(date +%Y%m%d)

`

.confの格納場所は自分の環境に合わせます。(筆者環境/home/www-data/matomo)

  • バックアップ確認
diff -u /path/to/backup/directory/conf_backup/config.ini.php.$(date +%Y%m%d) /path/to/matomo/config/config.ini.php

差分が無ければバックアップ成功です。

  • 再掲:なぜこの方法をとるのか?

「バックアップとオリジナルの両方があることが一発で分かるから」です。

cp -pi として、 ls -lを行うよりも確実です。

そして、この時点で差分があった場合は「これから修正するファイルを間違えた」というまたとない確認手段になります。(もしくはリアルタイムで改竄を受けているか、不思議なことが起こっているか)

matomoの.confファイルの編集

/path/to/matomo/config/config.ini.phpを、任意の方法で(教義・信仰に沿ったエディタで)編集します。

 [General]

セクションの下、trusted hostsあたりの直下に

force_ssl = 1

を追記して保存します。

  • 編集確認
diff -u /path/to/backup/directory/conf_backup/config.ini.php.$(date +%Y%m%d) /path/to/matomo/config/config.ini.php

以下のような結果が得られれば成功です。

 [General]
 salt = "UUID"
 trusted_hosts[] = "Your Domain"
+force_ssl = 1

このように、diffの元と先をcpの逆にすることは、編集したところが+で表示される視覚的な安心感を生みます。

設定反映

  • apache構文確認
sudo apache2ctl configtest

SyntaxOKを確認します。それ以外のエラーが起きていたら、編集時に誤りがあるので確認しましょう。

  • apache再開前確認
systemctl status apache2.service

active(running)を確認します

  • apache再開
sudo systemctl restart apache2.service
  • apache再開確認
systemctl status apache2.service

active(runnning)を確認します

  • php-fpm再開前確認
systemctl status php8.3-fpm.service 

active(running)を確認します

  • php-fpm再開
sudo systemctl restart php8.3-fpm.service 
  • php-fpm再開確認
systemctl status php8.3-fpm.service 

active(runnning)を確認します

設定反映確認

  1. 設定を行ったmatomoサイトに管理者権限でログインします。
  2. 設定 > システムの確認 > 完全なシステムチェックレポートを表示する をクリックします。
  3. 強制 SSL 接続にチェックが入っていれば設定完了です。

Matomoでcron処理を実行。

環境

  • Matomo 5.7.1
  • PHP-FPM8.3
  • Ubuntu 24.04

セルフホストでMatomoを用いている場合のcron処理を行ったときのメモです。

なぜcron処理が必要なのか?

Matomoには、データを処理する2つの方法があります。

  • リアルタイム集計(デフォルト): 管理画面を開いた瞬間に、溜まっている生データを計算してグラフを表示します。アクセスが少ないうちは良いですが、アクセスが増えると表示が非常に重くなります。
  • cronによる事前集計(推奨): 「5分に1回」などの頻度で、裏側でこっそり計算を済ませておきます。管理画面を開いたときは、計算済みの結果を表示するだけなので、動作が非常にサクサクになります。

さっくりとした手順

  1. crontabを編集します。
  2. Matomoの管理画面で設定を行います。

Crontab編集

  • crontabを開く
sudo crontab -u www-data -e

Matomoを実行しているユーザー(通常は www-data)として編集します。

  • 実行コマンドを追記する

ファイルの末尾に以下の1行を追加します(パスはご自身の環境に合わせて調整してください)。

5 * * * * /usr/bin/php /var/www/html/matomo/console core:archive --url=https://your-matomo-domain.com/ > /dev/null

解説: > 5: 毎時5分に実行するという意味。
/usr/bin/php: PHP 8.3の実行パス。
core:archive: これが「溜まったデータを集計しろ」というMatomo専用の命令です。

Matomo管理画面での設定変更

cronを設定しただけでは不十分です。Matomo側に「自分で集計するから、画面を開いたときに集計しなくていいよ」と教える必要があります。

  1. Matomoにログインし、「設定(歯車アイコン)」をクリックします。
  2. 左メニューの 「システム」 > 「一般設定」 を開きます。
  3. 「アーカイブの設定」 セクションを確認します。
    1. 「ブラウザでレポートを表示するときにアーカイブをトリガーする」を 「いいえ」 に変更。
  4. 下部の「保存」ボタンをクリックします。

注意点

  • PHP 8.3のメモリ制限:
    • 大規模なデータを集計する場合、CLI(コマンドライン)用の php.inimemory_limit を多めに(512Mや1Gなど)設定しておくと安心です。
  • ログの確認:
    • 最初は > /dev/null を書かずに実行して、エラーが出ないか確認することをおすすめします。

その他の設定に関しては改めて述べます。

Ubuntu パッケージ更新エラーの解決メモ

aptitude(apt)で捕まったときのメモです。

発生した状況

Ubuntu 24.04 で sudo aptitude update を実行した際、Phusion Passenger リポジトリに対して以下のエラーおよび警告が発生しました。

  • エラー:
    • 公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY D870AB033FB45BD1
  • 警告:
    • Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.

原因

GPG鍵の欠落:

システムが Passenger リポジトリのパッケージが真正なものであるかを確認するための公開鍵を持っていませんでした。

古い管理形式(非推奨):

以前の Ubuntu で一般的だった apt-key による鍵登録を行っていましたが、Ubuntu 24.04 ではその管理方式がセキュリティ上の理由で非推奨(Deprecated)となっていたためです。

対処内容

以下の手順で、鍵を新しい推奨形式(個別のキーリング管理)へ移行させました。

鍵の抽出と個別保存

sudo gpg --no-default-keyring --keyring /etc/apt/trusted.gpg --export D870AB033FB45BD1 | sudo tee /usr/share/keyrings/phusion-passenger.gpg > /dev/null

古い管理リストから鍵を削除

sudo apt-key del D870AB033FB45BD1

リポジトリ設定の更新

/etc/apt/sources.list.d/passenger.list 内の記述に [signed-by=/usr/share/keyrings/phusion-passenger.gpg] を追記し、特定のリポジトリと鍵を紐付けました。

→ 筆者にしては珍しく.listのバックアップを取っていませんが(切り戻しを取れるようにしていません)、これは「切り戻したところで古い鍵形式だから」です。

解決確認

sudo aptitude update

でエラーがないことを確認します。

作業が必要だった理由(背景)

Ubuntu 22.04 以降、OSのセキュリティ設計が強化され、

「すべてのリポジトリで共通の鍵束を使う方式」から「リポジトリごとに専用の鍵を個別に指定する方式」

への完全移行が推奨されているためです。これにより、以下のメリットがあります。

  • セキュリティ向上:
    • 万が一、一つのリポジトリの鍵が漏洩・悪用された場合でも、他のリポジトリの安全性に影響を与えない設計になっています。
  • メンテナンス性の向上:
    • どの鍵がどのリポジトリのものかが明確になり、不要になった鍵の削除や更新が安全に行えます。

Page 1 of 64

Powered by WordPress & Theme by Anders Norén