Contents
ESET Protect のアラート変数で起きる改行消失問題 – 改訂版
ポイント
1️⃣ ESET Protect が出力する$description・$detailsといったマルチライン変数は、Slack の Incoming Webhook にそのまま渡すと改行が失われます。
2️⃣ JSON ペイロード内で"\n"(エスケープされた LF)または Block Kit のコードブロックを利用すれば、改行を保持した状態で表示できます。
3️⃣ Base64 エンコードは「文字化け防止」には有効ですが、Slack が自動的にデコードしてくれるわけではありません。受信者側で手動またはスクリプトによる復号が必要です。
1. 改行が失われる仕組み
1‑1. Webhook の JSON エンコーディング
Slack は HTTP POST の本文を UTF‑8 の JSON として受け取ります。
JSON 文字列中に改行コードそのもの(\r、\n)がエスケープされずに埋め込まれると、パーサはそれを 空白 とみなします。その結果、次のように 1 行に連結されたテキストが表示されます。
|
1 2 |
検出されたマルウェア: - Trojan.Generic - Worm.Win32 |
実例(ESET フォーラム 2025‑03)
$description = "検出されたマルウェア:\n - Trojan.Generic\n - Worm.Win32"
→ Slack に送信すると改行が消失する
1‑2. 変数展開時の注意点(※根拠は公式ではなく実務上の観測)
ESET Protect のテンプレートエンジンは、変数名を 二重引用符で囲む と内部で文字列リテラル化し、\ がエスケープ対象から外れるケースがあります(フォーラム投稿 ID:11234 参照)。
公式ドキュメントに明記はされていないため、「変数名はそのまま埋め込む」ことを推奨します。
2. Slack 側で改行を正しく表示させる方法
| 手法 | 特徴 | 推奨シーン |
|---|---|---|
JSON エスケープ "\n" |
最もシンプル。文字列だけで完結。 | 短めのテキスト、text フィールドのみ使用する場合 |
| Block Kit のコードブロック(triple back‑ticks) | 等幅フォント+改行保持。レイアウトが崩れにくい。 | ログや長文アラートをそのまま表示したいとき |
| Base64 エンコード + 手動デコード | バイナリ・特殊文字の安全送信。自動復号はなし。 | JSON が壊れやすい極端に長いペイロード、外部ツールで閲覧するケース |
2‑1. "\n" を使った最小構成(PowerShell/Python/JavaScript 共通)
|
1 2 3 4 |
{ "text": "ESET アラートが届きました\n詳細は以下をご確認ください。" } |
ポイント:
"\n"は必ず 二重バックスラッシュ (\\n) にエスケープされた形で JSON に格納されます。
各言語別実装例
| 言語 | 文字列 → JSON 変換のベストプラクティス |
|---|---|
| PowerShell | ConvertTo-Json -Compress が自動的に \n をエスケープ。改行は LF ("n") に統一すると安全です。 |
| Python | json.dumps(payload, ensure_ascii=False) → \n が正しくエスケープされます。 |
| JavaScript | JSON.stringify(payload) だけで完了。テンプレートリテラル内に実際の改行を書けば自動的に \n に変換されます。 |
PowerShell 完全サンプル
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$description = @" 検出されたマルウェア: - Trojan.Generic - Worm.Win32 "@ # LF に統一し JSON エンコード $payload = @{ text = $description -replace "`r`n","`n" } | ConvertTo-Json -Compress Invoke-RestMethod -Uri $env:SLACK_WEBHOOK_URL ` -Method Post ` -ContentType 'application/json; charset=utf-8' ` -Body $payload |
2‑2. Block Kit のコードブロックで「そのまま表示」
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "*ESET アラート詳細*\n```\ 検出されたマルウェア:\n- Trojan.Generic\n- Worm.Win32\n発生日時: 2026‑04‑15 08:23:11\n対象端末: WIN-ABC1234```" } } ] } |
ポイント
mrkdwnのテキスト内部で\nを使って改行をエスケープ。- その後に続く triple back‑ticks(
)でコードブロック化すると、Slack が等幅フォントとともに全改行・空白を保持して表示します。
2‑3. Base64 エンコードは「安全な搬送手段」だが自動復号はしない
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import base64, json, os, requests description = """検出されたマルウェア: - Trojan.Generic - Worm.Win32""" b64_text = base64.b64encode(description.encode('utf-8')).decode('ascii') payload = { "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "*Base64 エンコードされた詳細*\n```" + b64_text + "```" } } ] } requests.post( os.getenv('SLACK_WEBHOOK_URL'), json=payload, headers={'Content-Type': 'application/json; charset=utf-8'} ) |
重要:上記のように Base64 文字列をコードブロックで送っても、Slack は「そのままテキスト」として表示します。受信者は
bash
echo "Base64文字列" | base64 -d
等の手段でデコードする必要があります。
3. Webhook 設定・テストフロー(ESET Protect 側)
3‑1. 手順概要
| 手順 | 操作内容 |
|---|---|
| 1 | 管理コンソール → 設定 → 通知 → 外部サービス に遷移 |
| 2 | 「Webhook」タイプを選択し、Slack の Incoming Webhook URL を貼り付け |
| 3 | ペイロードテンプレート に以下の JSON($description がマルチライン変数)を入力 |
| 4 | 変数展開オプションは 有効 にし、テスト送信で改行が保持されているか確認 |
推奨テンプレート例(コードブロック方式)
|
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "*ESET アラート*\n```$description```" } } ] } |
注記:変数名はそのまま
$descriptionと書くことを推奨します。二重引用符で囲むと一部ケースでエスケープが失われる(実務上の観測)ため、引用しない 方が安全です。
3‑2. curl でローカルテスト
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
cat > payload.json <<'EOF' { "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "*テストアラート*\n```検出されたマルウェア:\n- Trojan.Generic\n- Worm.Win32```" } } ] } EOF curl -X POST \ -H 'Content-Type: application/json; charset=utf-8' \ -d @payload.json \ https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX |
実行後、Slack に次のように表示されます。
|
1 2 |
*テストアラート* |
検出されたマルウェア:
- Trojan.Generic
- Worm.Win32
|
1 |
4. トラブルシューティングチェックリスト
| 症状 | 主な原因 | 確認すべき項目 | 推奨対策 |
|---|---|---|---|
| 改行が消える | \n がエスケープされていない |
ペイロード中に \n(二重バックスラッシュ)があるか |
文字列生成は必ず JSON.stringify / ConvertTo-Json 等のライブラリに任せる |
| 文字化け(〓・�) | UTF‑8 以外でエンコードされている | HTTP ヘッダーの Content-Type に charset=utf-8 が付与されているか |
PowerShell の -Encoding utf8、Python の json.dumps(..., ensure_ascii=False) を使用 |
| Block が無視される | blocks がトップレベルに配置されていない |
JSON 構造を jsonlint で検証 | blocks と text は同時に使用しない(どちらか一方が必須) |
| Base64 デコードできない | エンコード時に改行が混入している | エンコードコマンドのオプション(例: base64 -w 0)を確認 |
改行なしでエンコードし、受信側も同様に -d オプションだけで復号 |
| Webhook が全く届かない | URL が間違っている・IP 制限が掛かっている | 環境変数 SLACK_WEBHOOK_URL の中身を再確認 |
Slack 管理画面で URL を再生成し、ファイアウォール設定を見直す |
5. 補足情報
5‑1. Slack Markdown(mrkdwn)のポイント
\n→ 改行(エスケープが必要)*bold*・_italic_・はそのまま使用可code- コードブロックは
` で囲むと等幅フォントかつ改行保持
5‑2. 他言語でのエスケープ例(参考)
| 言語 | 改行統一・JSON エンコード |
|---|---|
| Ruby | payload = { text: description }.to_json (\n が自動エスケープ) |
| Go | json.Marshal(struct{ Text stringjson:"text"}{description}) |
| Node.js (TypeScript) | JSON.stringify({ text: description }) |
5‑3. 「変数名を二重引用符で囲むとエスケープが失われる」件の補足
公式ドキュメントに明記はなく、ESET フォーラム(2024‑11 投稿 ID:11234) の実務報告のみです。
この現象はテンプレートエンジンが 文字列リテラル化 する際に \ が二重引用符内部で無視されることが原因と推測されています。そのため、「変数はそのまま埋め込む」 の方が確実です。
6. 結論(再掲)
- 改行を保持したい場合は必ず JSON エスケープ
"\n"または Block Kit のコードブロックを使用。 - Base64 は搬送手段として有効だが、Slack が自動復号しない ことに留意し、受信側でデコード手順を案内する。
- 変数名は二重引用符で囲まない(公式根拠はなし)ことで、予期せぬエスケープ喪失リスクを回避できる。
これらのポイントを踏まえてテンプレートと送信ロジックを整備すれば、ESET Protect のマルチラインアラートが Slack 上で見やすく表示され、SOC エンジニアの作業効率が大幅に向上します。