SPF 레코드란 무엇인가? 문법, 10회 한도, 실패 패턴

요약

SPF 레코드란 무엇인가요? 도메인의 envelope sender에 대해 메일 발송을 허용한 서버를 나열하는 단일 DNS TXT 레코드이며 v=spf1로 시작합니다. 수신 서버는 연결 IP를 이 목록과 비교해 pass, fail, softfail을 반환합니다. 조회 한도는 10회이고, 전달 시 깨지며, Return-Path 도메인이 From 도메인과 일치할 때만 DMARC에 도움이 됩니다.

서버실 복도의 네트워크 랙과 초점이 맞은 패치 패널

SPF 레코드는 도메인 이름으로 메일을 보내도 되는 서버 목록을 DNS에 공개하는 TXT 레코드입니다. 수신 서버는 메일을 연결해 온 IP 주소를 이 목록과 비교해 pass, fail, softfail, neutral 중 하나를 반환합니다. 이 검사는 발신 경로를 인증하는 것이지, 사람이 화면에서 읽는 From 주소를 인증하지 않습니다. 대부분의 SPF 문제는 이 차이를 놓쳐서 생깁니다.

SPF 레코드는 DNS에 게시된 발신 허용 목록입니다

SPF는 Sender Policy Framework의 약자이고 RFC 7208에 정의되어 있습니다. 레코드는 도메인 루트에 놓인 TXT 항목이며 v=spf1로 시작합니다. 가장 단순한 형태는 다음과 같습니다.

example.com.  IN  TXT  "v=spf1 ip4:203.0.113.10 include:_spf.provider.example ~all"

왼쪽에서 오른쪽으로 읽습니다. 수신 측은 각 항목을 순서대로 확인하고 처음 일치하는 항목에서 멈춥니다. 마지막 all 항목은 앞에서 걸리지 않은 나머지 모든 경우를 처리합니다.

검사 대상은 From 헤더의 도메인이 아닙니다. SMTP의 MAIL FROM 명령에 들어 있는 도메인, 즉 envelope sender 또는 Return-Path입니다. 반송 메일처럼 이 값이 비어 있으면 수신 측은 HELO 이름으로 대신 검사합니다.

개발자 책상 위의 노트북 터미널과 손으로 그린 네트워크 다이어그램 노트

메커니즘은 ip4, ip6, a, mx, include, exists 여섯 가지입니다

SPF 항목 하나하나를 메커니즘이라고 부르며, 앞에 한정자(qualifier)를 붙일 수 있습니다. 실제 레코드 대부분은 아래 여섯 가지로 충분합니다.

한정자는 항목이 일치했을 때의 결과를 정합니다. +는 pass이며 기본값이고, -는 fail, ~는 softfail, ?는 neutral입니다. 따라서 -all은 목록에 없는 것은 모두 거부한다는 뜻이고, ~all은 받아들이되 표시한다는 뜻입니다.

가능하면 ip4:와 ip6:를 우선 쓰세요. 주소를 직접 통제하는 경우라면 조회 비용이 0이고, 다른 회사의 DNS가 바뀌어도 깨지지 않습니다.

10회 조회 한도가 실제 레코드를 깨뜨리는 제약입니다

RFC 7208은 하나의 SPF 평가에서 DNS 조회를 일으키는 항목을 10개로 제한합니다. 대상은 include, a, mx, ptr, exists, 그리고 redirect 수정자입니다. 중첩된 include도 모두 계산됩니다. 10개를 넘으면 결과는 permerror가 되고, 대체 경로 없이 검사가 실패합니다.

또 하나의 제한은 덜 주목받습니다. 응답이 비었거나 NXDOMAIN인 조회는 void lookup으로 분류되며, 스펙은 이를 두 번까지만 허용합니다. 작년에 쓰지 않게 된 공급사를 가리키는 include가 남아 있다면, 그것은 아무 효과 없이 조회 예산을 쓰는 void lookup입니다.

팀들이 이 한도에 부딪히는 과정은 대개 비슷합니다. Google Workspace가 include 하나를 차지하고, 트랜잭션 메일 제공사가 하나, 마케팅 플랫폼이 하나를 차지하는데 이 플랫폼은 안에서 다시 세 개를 더 include합니다. 고객지원 데스크, CRM, 청구 도구가 각각 하나씩 더해지면, 특별한 일을 하지 않았는데도 이미 11회에 도달합니다.

실패는 조용히 일어납니다. 메일은 계속 발송되고 일부 수신 서버는 그대로 전달합니다. 하지만 SPF는 더 이상 아무것도 인증해 주지 못합니다. SPF 정렬을 통해 DMARC를 통과하던 경로가 그 순간 사라지며, 레코드를 평탄화하거나 발신자를 줄이기 전까지는 복구되지 않습니다.

수정 방법은 세 가지이며, 우선순위 순서대로 나열합니다.

여러 발신 서비스에서 가운데 상자 하나로 화살표가 모이는 화이트보드 스케치

도메인마다 SPF 레코드는 하나만 게시합니다

한 도메인에 SPF 레코드를 둘 이상 게시하면 안 됩니다. 수신 측이 v=spf1로 시작하는 TXT 항목을 두 개 찾으면 결과는 조회 한도 초과와 같은 permerror입니다. 한 사람이 새 도구를 위해 레코드를 추가하고, 다른 사람은 이미 있는 레코드를 그대로 두는 상황에서 흔히 생깁니다.

해결 방법은 기계적입니다. 항목을 하나의 레코드로 합치고, 시작에는 v=spf1 하나, 끝에는 all 하나만 둡니다. 공급사 문서가 추가하라고 한 내용은 모두 기존 레코드 안에 include:로 넣으면 되며, 새 TXT 항목으로 만들면 안 됩니다.

작은 함정도 두 가지 있습니다. 255자를 넘는 TXT 문자열은 같은 레코드 안에서 여러 개의 따옴표 문자열로 나눠야 하며, 대부분의 DNS 공급사가 이를 자동으로 처리합니다. 그리고 가능하면 응답 전체를 약 450바이트 이내로 유지하세요. 더 큰 응답은 UDP에서 TCP로 넘어가야 하는데, 일부 리졸버는 이를 제대로 처리하지 못합니다.

softfail과 hardfail은 내가 볼 수 있는 범위에 따라 고릅니다

all 항목은 정책 선언입니다. "-all을 쓰세요"라는 일반적인 조언은 중요한 부분을 건너뜁니다. 모든 정당한 발신자를 알고 있을 때만 hard fail이 안전합니다.

메시지 흐름을 읽어 보면 저희가 따르는 기준은 다음과 같습니다.

실제로는 차이가 생각보다 작습니다. 대부분의 대형 수신 서버는 SPF를 여러 신호 중 하나로 보고, DMARC 정책이 있으면 최종 판단은 DMARC가 합니다. 그래도 불완전한 레코드에 -all을 붙이면 청구서 메일이 막히는 식의 사고가 납니다.

서버 랙에 묶여 있는 라벨 붙은 이더넷 케이블 다발

전달(포워딩)에서 SPF가 깨지는 것은 설계 때문입니다

SPF는 수신 서버에 연결한 IP를 검사합니다. 메일이 전달되거나, 메일링 리스트가 재배포하거나, 별칭 서비스가 중계하면 연결 IP는 중계자의 것이지 여러분의 것이 아닙니다. 여러분이 잘못한 것이 없어도 SPF 검사는 실패합니다.

이는 SPF 안에서 해결할 수 없습니다. DKIM이 SPF와 함께 존재하는 이유가 바로 이것입니다. 서명은 전달 과정에서도 살아남지만 IP 목록은 그렇지 않습니다. SPF에만 의존하는 도메인은 전달되는 모든 메시지에서 인증 실패를 보게 됩니다.

같은 이유로 전달되는 메일에서는 SPF만으로 DMARC를 충족할 수 없습니다. 이런 메일은 DKIM이 맡을 수 있도록 설계하세요.

SPF 정렬: 통과와 From 도메인 일치는 같지 않습니다

메시지는 SPF를 통과하고도 DMARC에서 실패할 수 있습니다. DMARC는 SPF를 통과한 도메인, 즉 Return-Path 도메인이 사용자에게 보이는 From 도메인과 일치하기를 요구합니다. 많은 공유 발송 서비스는 기본값으로 자체 바운스 도메인을 씁니다. 그러면 SPF는 provider-mail.net에 대해서는 통과하지만 example.com에는 아무 도움이 되지 않습니다.

원시 헤더에서 확인하세요. Authentication-Results 줄의 smtp.mailfrom= 값이 여러분의 도메인이나 그 하위 도메인이 아니라면, SPF는 통과하고 있어도 여러분에게 도움을 주지 않습니다.

해결책은 자신의 하위 도메인에 커스텀 Return-Path를 두는 것입니다. 대부분의 주요 발송 서비스가 이를 지원하지만, 기본으로 켜져 있지는 않은 경우가 많습니다.

수신 제공자는 모든 발신자에게 인증을 요구합니다

2024년 2월부터 Google은 모든 발신자에게 SPF 또는 DKIM 인증을 요구하고, Gmail로 하루 5,000통 이상 보내는 발신자에게는 SPF, DKIM, DMARC를 모두 갖추도록 요구합니다. 자세한 내용은 Google 이메일 발신자 가이드라인에 있습니다. Yahoo도 같은 시기에 비슷한 기준을 도입했습니다.

이로써 SPF는 있으면 좋은 설정에서 전달의 필수 조건으로 바뀌었습니다. 레코드가 없거나 깨져 있으면 평판 점수가 낮아지는 정도가 아니라, 거부와 스팸 분류로 바로 나타납니다.

메시지 흐름을 몇 년간 추적하며 본 결과, 이 규칙은 주로 인증이 전혀 없는 도메인과 스팸 신고율이 높은 발신자를 걸러냅니다. 올바른 SPF 레코드 하나만으로 받은편지함에 들어가는 것은 아니지만, 레코드가 없으면 확실히 막힙니다.

SPF 레코드를 네 단계로 확인하고 고치는 법

아래 순서대로 진행하고, DNS를 바꿀 때마다 다시 확인하세요.

  1. 현재 레코드를 조회합니다. dig +short TXT example.com을 실행해 v=spf1로 시작하는 항목을 찾습니다. 두 개가 있다면 하나로 합칩니다.

  2. 조회 수를 셉니다. include, a, mx, exists, redirect와 include 안에 중첩된 모든 조회를 더합니다. 8회 이상이라면 11회가 되기 전에 정리 계획을 세우세요.

  3. 실제 발신자를 나열합니다. 테스트 발송에서 얻은 Authentication-Results 헤더나 DMARC 집계 보고서를 사용하고, 실제로 나타나는 출처만 추가합니다.

  4. 테스트 메일을 보내 헤더를 읽습니다. spf=pass이고 smtp.mailfrom이 여러분의 도메인이어야 합니다.

DNS 변경은 전파에 시간이 걸리며, 기존 레코드의 TTL이 이전 응답이 얼마나 오래 남을지 결정합니다. 계획된 변경 하루 전에 TTL을 300초로 낮춰 두세요.

발신자 세 곳을 가진 SaaS 회사의 레코드 예시

Google Workspace, 트랜잭션 메일 제공사, 고객지원 데스크에서 메일을 보내는 제품을 생각해 봅시다. 깔끔한 레코드는 다음과 같습니다.

example.com.  IN  TXT  "v=spf1 include:_spf.google.com include:spf.transactional.example include:spf.helpdesk.example -all"

include가 세 개이고, 각각이 숨겨진 중첩 조회를 가지고 있습니다. 게시하기 전에 반드시 세어 보세요. 겉으로 보이는 길이는 실제 예산을 알려 주지 않습니다. include 세 개짜리 레코드도 이미 7~8회에 도달할 수 있습니다.

그래서 목적별로 나누는 것이 좋습니다. 사람이 보내는 메일은 루트 도메인에 두고, 제품 알림은 notify.example.com에 두어 트랜잭션 제공사만 나열하게 합니다. 루트 레코드는 짧게 유지되고, 하위 도메인은 자체 10회 예산을 가지며, 한 스트림의 평판 문제가 다른 스트림을 끌고 내려가지 않습니다.

이렇게 나누면 DMARC 보고서도 읽기 쉬워집니다. 각 스트림이 자신의 Return-Path 도메인을 가지므로, 실패가 발생하면 수많은 발신자 중 하나가 아니라 한 발신자를 가리킵니다.

SPF가 하지 않는 일

SPF는 From 주소를 위조하는 것을 막지 못합니다. 그 헤더를 한 번도 보지 않기 때문입니다. 메시지를 암호화하지도 않고, 메일이 왜 스팸함에 들어갔는지도 알려 주지 않습니다. 또한 10회 조회 예산을 넘어서는 것은 지속적인 관리 없이는 막을 수 없습니다.

SPF는 함께 게시해야 하는 세 가지 레코드 중 하나로 보세요. 발신 경로를 위한 SPF, 메시지 무결성을 위한 DKIM, 그리고 이 둘을 From 도메인에 연결하는 정책인 DMARC입니다. SPF만 있고 나머지가 없다면, 다음 구체적 단계는 DMARC를 p=none으로 게시하고 2주 동안 보고서를 읽는 것입니다.

자주 묻는 질문

SPF 레코드를 쉽게 설명하면 무엇인가요?
도메인을 대신해 메일을 보낼 수 있는 서버를 나열한 DNS TXT 레코드입니다. 수신 서버는 발신 IP가 이 목록에 있는지 확인해 SPF 통과 여부를 판단합니다.
도메인마다 SPF 레코드를 몇 개 둘 수 있나요?
하나입니다. v=spf1로 시작하는 레코드를 두 개 게시하면 permerror가 발생합니다. 모든 발신자를 하나의 레코드에 합치고 끝에 all 항목 하나만 두세요.
SPF의 DNS 조회 10회 한도는 무엇인가요?
RFC 7208은 하나의 SPF 평가에서 DNS 조회를 일으키는 항목을 10개로 제한합니다. include, a, mx, ptr, exists, redirect가 대상이며 중첩된 include도 모두 포함됩니다.
전달된 메일에서 SPF가 실패하는 이유는 무엇인가요?
SPF는 연결한 IP를 검사하므로, 중계자가 메일을 전달하면 검사 대상 IP가 원래 발신자가 아닌 중계자의 IP가 됩니다. 이런 경우에는 DKIM 서명이 메시지를 지켜 줍니다.
SPF 통과인데 DMARC가 실패하는 이유는 무엇인가요?
DMARC는 SPF를 통과한 Return-Path 도메인이 보이는 From 도메인과 일치해야 합니다. 공유 발송 서비스의 기본 바운스 도메인으로 통과했다면 DMARC 정렬은 실패합니다.
notificationharbor
무료로 시작하기