웹 서비스 개발 중 사용자 인증 번호 발송이나 결제 알림을 위해 네이버 클라우드 플랫폼의 SENS(Simple & Easy Notification Service) API를 연동하려다 인증 오류(401 Unauthorized)로 몇 시간씩 애를 먹어본 경험이 있으신가요? 문서를 보며 헤더를 맞추어 전송해도 'Signature is invalid' 에러가 발생하면 당황하기 십상입니다. 다만 대부분의 개발자들은 SENS API가 요구하는 HMAC-SHA256 서명 방식의 문자열 조합 규칙과 타임스탬프 처리 방식을 정확히 이해하지 못한 채 인터넷 예제를 복사해 붙여넣다 실패를 겪곤 합니다. 이번에는 네이버 클라우드 SENS API의 서명 인증 원리부터 PHP로 실시간 SMS를 안전하고 정확하게 발송하는 방법까지 완벽하게 정리해서 소개하겠습니다.
네이버 클라우드 SENS(Simple & Easy Notification Service)는 SMS, LMS, MMS 및 카카오톡 알림톡 메시지를 API 호출만으로 대량 또는 실시간 발송할 수 있는 클라우드 서비스입니다.
일반적인 API가 단일 Bearer 토큰이나 API Key만을 헤더에 실어 보내는 것과 달리, 네이버 클라우드 API는 보안성 강화를 위해 **요청 시점마다 가변하는 타임스탬프와 HMAC SHA256 서명(Signature)**을 필수 인증 헤더로 요구합니다.
| 인증 헤더 항목 | 설명 | 예시 / 형식 |
|---|---|---|
| x-ncp-apigw-timestamp | 요청 시점의 Epoch 밀리초(milliseconds) 타임스탬프 | 1700000000000 |
| x-ncp-iam-access-key | 네이버 클라우드 마이페이지에서 발급받은 Access Key ID | ncp_iam_AK... |
| x-ncp-apigw-signature-v2 | HTTP 메소드, URL 경로, 타임스탬프, Access Key를 Secret Key로 암호화한 HMAC 서명 | Base64 인코딩된 문자열 |
SENS API로 메시지를 전송하기 전, 네이버 클라우드 콘솔에서 Service ID를 확인하고 API Access Key/Secret Key 쌍을 발급받아야 합니다.
서명(Signature)을 생성하기 위한 텍스트 조합 규칙은 다음과 같이 매우 엄격합니다.
서명 생성 시 결합되는 raw string 규칙:
1. HTTP Method (예: POST)
2. 한 칸 공백 (Space)
3. URI 경로 (도메인을 제외한 /sms/v2/services/{serviceId}/messages 전체)
4. 줄바꿈 (\n)
5. Timestamp (밀리초 단위)
6. 줄바꿈 (\n)
7. Access Key ID
PHP cURL을 활용하여 HMAC SHA256 서명을 생성하고 SMS 메시지를 전송하는 실전 코드입니다.
✗ 잘못된 코드 (단순 초 단위 타임스탬프 사용 및 필수 헤더 조합 누락):
// ✗ 서명 문자열 포맷 누락 및 타임스탬프 단위 오류
$timestamp = time(); // 초 단위 time()을 그대로 사용하면 401 인증 실패 발생
$rawString = "POST /sms/v2/services/".$serviceId."/messages"; // 줄바꿈과 AccessKey 결합 누락
$signature = base64_encode(hash_hmac('sha256', $rawString, $secretKey, true));✓ 올바른 코드 (밀리초 타임스탬프 계산 및 정확한 서명 조합 후 cURL 전송):
<?php
function sendNaverSms($accessKey, $secretKey, $serviceId, $fromPhone, $toPhone, $content) {
// 1. Epoch 밀리초 타임스탬프 생성
$timestamp = (string)round(microtime(true) * 1000);
// 2. 요청 URI 정의
$uri = "/sms/v2/services/{$serviceId}/messages";
$url = "https://sens.apigw.ntruss.com" . $uri;
// 3. HMAC-SHA256 암호화 대상 문자열 조합 (HTTP Method + 공백 + URI + \n + timestamp + \n + accessKey)
$message = "POST" . " " . $uri . "\n" . $timestamp . "\n" . $accessKey;
// 4. Secret Key를 이용한 HMAC SHA256 서명 생성 및 Base64 인코딩
$signature = base64_encode(hash_hmac('sha256', $message, $secretKey, true));
// 5. 요청 데이터 구조 생성
$data = [
'type' => 'SMS', // SMS 또는 LMS
'contentType' => 'COMM', // COMM(일반) 또는 AD(광고)
'countryCode' => '82',
'from' => $fromPhone, // 발신번호 (네이버 클라우드에 사전 등록된 번호)
'content' => $content,
'messages' => [
['to' => $toPhone]
]
];
$headers = [
'Content-Type: application/json; charset=utf-8',
'x-ncp-apigw-timestamp: ' . $timestamp,
'x-ncp-iam-access-key: ' . $accessKey,
'x-ncp-apigw-signature-v2: ' . $signature
];
// 6. cURL 요청 수행
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return [
'code' => $httpCode,
'body' => json_decode($response, true)
];
}
// 실무 적용 예시
$accessKey = "YOUR_NCP_ACCESS_KEY";
$secretKey = "YOUR_NCP_SECRET_KEY";
$serviceId = "ncp:sms:kr:1234567890:service_name";
$result = sendNaverSms($accessKey, $secretKey, $serviceId, "01012345678", "01098765432", "[서비스명] 인증번호는 5892 입니다.");
print_r($result);
?>출력 결과 (API 호출 성공 시):
{
"code": 202,
"body": {
"requestId": "20231025-102938-1234567",
"requestTime": "2023-10-25T10:29:38.123",
"statusCode": "202",
"statusName": "success"
}
}
SENS API 연동 중 가장 자주 발생하는 문제들과 해결책입니다.
- **HTTP 401 Unauthorized (Signature is invalid)**: 서명 생성 시 암호화 문자열 사이에 줄바꿈(`\n`) 대신 공백을 넣었거나 URI 경로의 대소문자가 틀린 경우입니다. 조합 규칙을 다시 한번 확인하세요.
- **HTTP 400 Bad Request (Invalid Sender Number)**: `from`에 입력한 발신번호가 네이버 클라우드 콘솔의 [발신번호 관리] 메뉴에 등록되어 있지 않거나 통신사 본인인증이 완료되지 않은 경우 발생합니다.
- **서버 타임스탬프 시간 오차**: API를 호출하는 웹 서버의 시계가 네이버 타임 서버와 5분 이상 벌어지면 인증이 거부됩니다. Linux 서버의 NTP(Network Time Protocol) 동기화 상태를 체크하세요.
네이버 클라우드 SENS API 연동은 HMAC SHA256 서명 생성 규칙만 정확히 지키면 매우 안정적이고 빠르게 메시지를 발송할 수 있는 강력한 도구입니다. 복잡해 보이는 보안 인증 절차도 밀리초 단위 타임스탬프 처리와 정해진 서명 포맷을 서포트 함수로 모듈화해 두면 재사용성과 보안을 모두 확보할 수 있습니다.
Naver Cloud SENS API는 회원가입 인증, 결제 완료 통지, 비상 상태 알림 등 웹 서비스의 핵심 소통 채널을 담당하는 중요한 기능이다. 작은 서명 생성 최적화와 예외 처리 습관이 모여서 서비스 전체의 안정성과 신뢰도를 만든다는 점을 잊지 말자. 이 글의 PHP 서포트 함수 예제를 참고해 본인의 프로젝트에 바로 연동해 보면, 인증 실패 없이 완벽하게 동작하는 SMS 알림 시스템을 구현할 수 있을 것이다.