n8n 웹훅 URL은 비밀번호와 같습니다. 아마도 이미 공공장소에 붙여놓았을 것입니다
요약
n8n 사용자가 웹훅 URL을 비밀번호처럼 취급하고 관리해야 함을 강조합니다. 스크린샷 공유, JSON 워크플로우 내보내기, 로그 기록 등 다양한 경로를 통해 민감한 웹훅 URL이 유출될 수 있으며, 이는 무단 접근의 위험을 초래할 수 있습니다.
핵심 포인트
- 웹훅 URL은 베어러 토큰과 같으므로 비밀번호처럼 취급해야 합니다.
- URL 유출 경로는 스크린샷, 공유된 JSON 워크플로우, 로그/오류 메시지 등 다양합니다.
- 가장 중요한 해결책은 웹훅 노드에서 헤더 인증(Header Auth)을 활성화하는 것입니다.
- 개발 시에는 테스트 URL을 사용하고 배포 시에만 프로덕션으로 전환해야 합니다.
n8n 웹훅 URL은 비밀번호와 같습니다. 그리고 여러분은 아마도 그것을 어딘가에 공개적으로 붙여 놓았을 것입니다.
이 글은 프로덕션 환경에서 n8n으로 LLM 워크플로우를 실행하는 과정의 '공개적으로 구축하기(build-in-public)' 시리즈 중 일부입니다. 여기에 있는 모든 내용은 제가 판매하고 지원하는 실제 템플릿에서 가져온 것이며, 실수한 부분은 저의 잘못이고 수정된 부분은 테스트를 거쳤습니다.
존재해서는 안 될 실행 기록
몇 달 전, 저는 한 고객의 실행 목록을 검토하다가 설명할 수 없는 실행 기록을 발견했습니다. 이 워크플로우는 웹훅(Webhook)이 트리거하는 주문 처리기였는데, 오직 그들의 스토어에서 주문 이벤트가 발생했을 때만 작동해야 했습니다. 그런데도 거기에 있었습니다: 새벽 3시에 발생한 실행 기록이었고, 페이로드(payload)는 고객의 스토어 형식과 전혀 맞지 않았습니다. 쓰레기가 들어가서 절반 처리되더니, 누락된 필드 때문에 실패하며 저에게 알림을 보냈습니다.
누군가—혹은 무언가가—웹훅 URL에 직접 접근한 것입니다.
어떻게? 저는 그 URL을 공개적으로 게시한 적이 없습니다. 하지만 문득 기억났습니다: 3주 전, 제가 다른 문제를 설명하기 위해 포럼 스레드에 이 워크플로우의 스크린샷을 올렸던 것이었습니다. 웹훅 노드가 보였습니다. 전체 프로덕션 URL은 그 스크린샷 안에 있었고, 선명하게 읽을 수 있었습니다.
n8n 웹훅 URL은 베어러 토큰(bearer token)과 같습니다. 그것을 가진 사람은 누구나 여러분의 워크플로우를 트리거할 수 있습니다. 기본적으로는 2단계 인증(second factor), IP 허용 목록(IP allowlist), 또는 속도 제한(rate limit)이 없습니다. 저의 '비공개' 워크플로우가 제가 그 스크린샷을 공유한 날부터 공개적이 되어버렸습니다.
웹훅 URL이 유출되는 세 가지 장소
조사하기 시작하자, 저는 생각했던 것보다 더 많은 곳에서 제 URL들이 발견되었습니다:
1. 스크린샷 및 화면 녹화. 가장 큰 누출원입니다. 도움을 요청하기 위해 워크플로우를 공유할 때 웹훅 노드가 프레임에 들어가고, URL이 읽힐 수 있습니다. 자동화 포럼에서 웹훅 URL 패턴을 검색해 보면 실제 작동하는 것들을 찾을 수 있을 것입니다.
2. 공유된 워크플로우 JSON. 워크플로우를 내보내면(Export) 웹훅 노드는 여전히 path를 유지하며, 이를 자신의 n8n에 가져오는 사람은 누구나... 사실 자신만의 URL을 얻게 됩니다—도메인이 변경됩니다. 하지만 _path_는 그대로 남아있고, 만약 여러분이 전체 URL을 Set 노드나 Code 주석, 또는 다른 곳의 HTTP 노드에 붙여넣은 적이 있다면, 그것 역시 JSON과 함께 전송됩니다.
3. 로그 및 오류 메시지. 웹훅 URL은 실행 데이터, 알림으로 전달되는 오류 페이로드, 그리고 지원 티켓에 붙여넣어지는 곳에 남게 됩니다. 복사될 때마다 이는 공개된 상태의 또 다른 베어러 토큰(bearer token)입니다.
n8n에서는 별도의 테스트 및 프로덕션 URL을 제공하여 도움이 되지만, 대부분은 게으름 때문에 프로덕션 URL을 기준으로 구축하고 절대 전환하지 않습니다.
해결책: URL을 비밀로 취급하고, 그럼에도 호출자를 검증하라
두 가지 계층이 있습니다. 첫 번째는 위생(hygiene)이며, 두 번째가 실제로 당신을 구해줄 것입니다.
계층 1 — 위생 (오늘 당장 실천하세요).
- 웹훅 노드에서 인증 기능을 활성화하세요. n8n의 웹훅 노드는 헤더 인증(Header Auth)을 지원합니다. 이는 공유 비밀(shared secret)을 헤더에 담아 전송하며, 워크플로우가 실행되기 전에 확인됩니다. 설정하는 데 1분밖에 걸리지 않았고, 제 새벽 3시 실행을 막아주었습니다.
- 구축할 때는 테스트 URL을 사용하고, 배포할 때만 프로덕션으로 전환하세요.
- URL이 유출되면 웹훅의
path를 변경하세요. 새로운 경로는 새로운 URL이며, 이전 URL은 즉시 무효화됩니다. 이것이 당신의 로테이션 메커니즘(rotation mechanism)입니다. 이를 그렇게 사용하세요. - 웹훅 노드가 펼쳐진 스크린샷을 절대 게시하지 마세요. 흐리게 하거나 잘라내세요. 저는 여러분이 겪지 않아도 되도록 이 교훈을 값비싼 방법으로 배웠습니다.
계층 2 — 서명 검증 (제어할 수 없는 웹훅의 경우).
헤더 인증은 당신이 비밀을 선택할 때 작동합니다. 하지만 호출자가 Stripe, Shopify 또는 고객사의 스토어인 경우, 그들은 대신 페이로드를 서명합니다. 일반적으로 서명 비밀(signing secret)과 함께 원본 본문(raw body)의 HMAC-SHA256을 계산하여 헤더에 전송하는 방식입니다. n8n은 이를 자동으로 검증해주지 않으므로, 웹훅 직후의 첫 번째 노드가 어떤 부수 효과가 실행되기 전에 반드시 수행해야 합니다:
// 코드 노드(Code node), 웹훅 트리거 후 첫 단계 — 실패 시 종료(fail closed)
const crypto = require('crypto');
const secret = $env.WEBHOOK_SIGNING_SECRET; // 절대 하드코딩하지 마세요
...
여기서 중요한 세 가지 사항이 있습니다. 첫째, _raw_ 본문과 비교해야 합니다 (파싱된 JSON을 재직렬화하면 공백이 변경되어 HMAC가 깨질 수 있음). 둘째, timingSafeEqual과 비교해야 합니다 (단순한 ===은 민감한 공격자에게 비밀 값을 바이트별로 노출할 수 있습니다). 셋째, 워크플로우의 어떤 작업(LLM 호출, 데이터베이스 쓰기, 이메일 등)이 페이로드에 접근하기 전에 예외를 발생시켜야 합니다.
$env 사용법에 주목하세요. 서명 비밀 값은 워크플로우 JSON에 있는 것이 아니라 환경 변수(environment variable)에 존재해야 합니다. 워크플로우 JSON의 비밀 값은 내보내지고, 스크린샷이 찍히고, Git에 커밋될 수 있습니다. 제가 어떻게 아는지 물어보세요.
현재 모든 웹훅 워크플로우에 적용하는 체크리스트
- 웹훅 노드에서 헤더 인증(Header Auth)을 활성화하거나 (또는 호출자가 첫 번째 코드 노드에서 검증하는 HMAC 서명을 사용해야 함)
- 서명 확인은 어떤 부수 효과(side effect)가 발생하기 전에 실행되어야 하며, 실패 시 닫힌 상태(fail closed)로 처리하고 원본 본문(
raw body)에timingSafeEqual을 사용해야 합니다. - 서명 비밀 값은
$env에 있어야 하며, 워크플로우 JSON에는 절대 포함되어서는 안 됩니다. - 테스트 URL을 기반으로 구축하고, 프로덕션 URL은 배포 시점에만 사용합니다.
- 웹훅
path는 변경 가능한 것으로 취급되어야 합니다. 의심되는 유출이 발생하면 즉시 변경해야 합니다. - 실제 운영 웹훅 URL이 포함된 스크린샷, 내보내기 파일 또는 로그가 없어야 합니다.
웹훅 URL은 살아있는 동안 브라우저 주소창에 붙여넣는 비밀번호와 같습니다. 그것처럼 취급하고, 서명 확인을 통과할 때까지 워크플로우가 호출자를 불신하도록 만드세요.
저는 AI Automation Lab — 운영 준비가 된 n8n 워크플로우 템플릿을 만들고 있습니다. 무료 AI Hook Generator는 제가 실제 워크플로우를 어떻게 구성하는지 보여주며, 저의 오픈 소스 템플릿은 github.com/zhp910318/n8n-ai-automation-lab에 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기