ブログ · · 約 9 分で
固定 IP で Webhook を送る方法:NAT ゲートウェイ・プロキシ・中継サーバーと費用
取引先が
要点
- 送信元の
IP を 固定する 方法は、 NAT ゲートウェイ・フォワードプロキシ・中継サーバーの 3 つです。 AWS の 東京で NAT ゲートウェイを 2 つ 置くと、 通信量を 除いて 月 約 98 USD です。 - 固定 IP の
サーバーは 取引先に 信頼される 送信元に なるので、 送る 直前の 名前解決の 検査と リダイレクトを 追わない 設定 (SSRF 対策) を 必ず 入れます。 - IP の
許可は 経路を 絞るだけなので、 受け側には 署名の 検証も 併用して もらいます。 送信元 IP は 秘密ではなく、 公開して 構いません。
取引先に
よくある場面
cybozu developer community に、
送る
受信を
構成 1:NAT ゲートウェイ
アプリを
AWS の
| 項目 | 単価 | 月額 |
|---|---|---|
| NAT ゲートウェイ | 0.062 USD / 時間 | 約 45.3 USD |
| NAT ゲートウェイの |
0.062 USD / GB | 通信量に |
| パブリック IPv4 アドレス | 0.005 USD / 時間 | 約 3.7 USD |
冗長化の
向いているのは、
出典: Amazon VPC の
構成 2:フォワードプロキシ
固定 IP を
import { ProxyAgent, fetch } from 'undici';
const proxy = new ProxyAgent(process.env.WEBHOOK_PROXY_URL!); // 例: http://user:pass@proxy.internal:4750
await fetch(endpointUrl, {
method: 'POST',
headers,
body,
dispatcher: proxy,
redirect: 'manual',
signal: AbortSignal.timeout(15_000),
});プロキシには、
費用は
構成 3:中継サーバー
アプリから
Fly.io はfly ips allocate-egress --app <アプリ名> -r nrt で
中継サーバーの
import { createHmac, timingSafeEqual } from 'node:crypto';
import http from 'node:http';
const SECRET = process.env.SHARED_SECRET!;
http.createServer(async (req, res) => {
const ts = String(req.headers['x-request-timestamp'] ?? '');
const sig = String(req.headers['x-request-signature'] ?? '');
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.writeHead(401).end();
const chunks: Buffer[] = [];
for await (const c of req) chunks.push(c as Buffer);
const raw = Buffer.concat(chunks).toString('utf8');
const expected = createHmac('sha256', SECRET).update(`${ts}.${raw}`).digest('base64');
if (sig.length !== expected.length || !timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.writeHead(401).end();
}
const { url, headers, body } = JSON.parse(raw);
// ここで宛先を検査してから送る(次の節)
const r = await fetch(url, { method: 'POST', headers, body, redirect: 'manual', signal: AbortSignal.timeout(15_000) });
res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify({ status: r.status }));
}).listen(8080);固定 IP の送信で必ず入れる SSRF の対策
固定 IP の
入れておく
- 登録の
ときに、 https だけ・ポートは 443 などに 限る・IP を 直接書いた URL と .internalなどの社内向けの 名前を 断る。 - 送る
直前に 名前を 引き、 返ってきた アドレスが 1 つでも プライベート・ループバック・リンクローカル (クラウドの メタデータを 含む) などに 当たれば 送らない。 - 検査を
通った IP に 直接つなぐ (名前を 引き直すと DNS リバインディングで 検査を すり 抜けられる) 。 - リダイレクトを
追わない。
SkyWay の
署名と併用する理由
IP の
取引先には、
IP を公開してよい理由
送信元の
公開する
- 一覧の
置き場所 : ドキュメントと管理画面の 両方に 載せる。 機械で 読める JSON も あると、 取引先が ファイアウォールの 設定を 自動で 更新できる。 - 変更の
知らせ方 : Stripe は7 日前に メーリングリストで 知らせています。 - 2 つ以上の
IP : 1 台の障害で 送れなくならないように。 取引先には 最初から 全部を 許可して もらう。
Webhook Admin での扱い
Webhook Admin では、
- 固定 IP の
送信元は 209.71.107.233の1 つです。 受け側では この IP を 許可します。 アドレスは 管理画面と ドキュメントにも 載せています。 - 送る
直前に 名前を 引いた IP を すべて 検査し、 社内向けの アドレスが 1 つでも あれば 送りません。 リダイレクトは 追いません。 送信元が IPv4 なので、 送信先には IPv4 の アドレス (A レコード) が 要ります。 - 署名
(Standard Webhooks) と 再送、 失敗の 記録は、 固定 IP の 送信でも 同じです。 送信の 記録には、 固定 IP から 送ったか どうかと 送信元の IP が 残ります。
API でfixed_ip を
curl -X POST https://api.webhookadmin.com/v1/endpoints \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"consumer_id":"con_...","url":"https://partner.example.jp/webhooks","fixed_ip":true}'構成の選び方
| 構成 | 月額の |
向いている |
|---|---|---|
| NAT ゲートウェイ |
約 98 USD+通信量 | 送信の |
| フォワードプロキシ |
サーバー代+IP 代 | 既存の |
| 中継サーバー |
IPv4 1 つ 3.60 USD+マシン代 | サーバーレスから |
| 配信サービスの |
各サービスの |
冗長化と |
取引先の
よくある質問
サーバーレスのアプリから固定 IP で送るにはどうしますか。
VPC の
固定 IP があれば署名の検証は要りませんか。
署名の
Webhook Admin の送信元 IP は何ですか。
209.71.107.233 の