From 9e900085759eae1188094a52f6da570bcc12d101 Mon Sep 17 00:00:00 2001 From: posimai Date: Mon, 6 Apr 2026 00:39:18 +0900 Subject: [PATCH] fix: WebSocket auth gate + SSRF private IP blocklist in posimai-dev --- posimai-dev/server.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/posimai-dev/server.js b/posimai-dev/server.js index 65bce37d..fd4a59e5 100644 --- a/posimai-dev/server.js +++ b/posimai-dev/server.js @@ -235,7 +235,7 @@ app.get('/api/vps-health', async (req, res) => { // ── サービス死活チェックプロキシ (/api/check?url=...) ────────── // ブラウザの mixed-content 制限を回避するためサーバー側から HTTP チェック // SSRF 対策: http/https のみ許可、クラウドメタデータ IP をブロック -const BLOCKED_HOSTS = /^(169\.254\.|100\.100\.100\.100|metadata\.google\.internal)/; +const BLOCKED_HOSTS = /^(127\.|localhost$|::1$|169\.254\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|100\.100\.100\.100|metadata\.google\.internal)/i; function isCheckUrlAllowed(raw) { let parsed; try { parsed = new URL(raw); } catch { return false; } @@ -277,7 +277,15 @@ const proto = tlsOpts ? 'https' : 'http'; const wss = new WebSocketServer({ server, path: '/terminal' }); -wss.on('connection', (ws) => { +wss.on('connection', (ws, req) => { + // Tailscale ネットワーク外からの接続を拒否 + const ip = req.socket.remoteAddress || ''; + const allowed = ip === '::1' || ip === '127.0.0.1' || ip.startsWith('100.'); + if (!allowed) { + ws.close(1008, 'Forbidden'); + return; + } + // セッションID・ログファイル作成 const sessionId = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19); const logPath = path.join(SESSIONS_DIR, `${sessionId}.log`);