핸드폰 인증 제작기
회사에서 진행한 핸드폰 번호 유효성 검증 시스템 구축에 대해 공유하고자 합니다. 기존에 구글 폼 양식을 HTML에 옮겨서 이를 통해 렌탈 서비스를 받고 있었지만, 고객이 입력한 핸드폰 번호가 실제로 사용 가능한 번호인지 확인할 필요성이 생겼습니다. 이를 해결하기 위해 어떤 과정을 거쳤고, 어떻게 구현했는지 설명하겠습니다.
목차
프로젝트 배경 및 목표
문제점
회사는 현재 구글 폼을 통해 렌탈 서비스 신청을 받고 있습니다. 하지만 고객이 입력한 핸드폰 번호가 실제로 사용 가능한 번호인지 확인할 수 없어서 연락이 되지 않는 경우가 발생했습니다.
목표
- 핸드폰 번호의 유효성 실시간 검증
- 자동화된 SMS 인증 시스템 도입
- 보안성과 신뢰성을 갖춘 구현
해결 방안 모색
초기 접근
처음에는 기존에 사용 중인 카페24 인증 시스템으로 쓰고 있는 NHN KCP를 활용하려 했습니다. 카페24 회원가입 시 사용하는 인증 기능을 사용할 수 있는지 문의했지만, 지원되지 않는다는 답변을 받았습니다.
대안 탐색
이전에 NCLOUD의 지도 API를 사용한 경험을 바탕으로, NCLOUD SENS를 활용하기로 결정했습니다. 이를 통해 SMS 인증 시스템을 구축할 수 있었습니다.
구현 과정
3.1 온프레미스 서버 설정 및 Fastify 사용
Fastify는 Node.js 기반의 웹 프레임워크로, 빠르고 확장성이 좋아 선택했습니다.
- CORS 설정: 회사 홈페이지 도메인만 허용하도록 설정하여 보안을 강화했습니다.
fastify.register(require('fastify-cors'), {
origin: 'https://company-website.com',
methods: ['POST']
});
3.2 NCLOUD SENS API 연동
HMAC SHA256 알고리즘을 사용하여 API 인증에 필요한 시그니처를 생성했습니다.
const CryptoJS = require('crypto-js');
const url = `/sms/v2/services/${NCLOUD_SERVICE_ID}/messages`;
const timestamp = Date.now().toString();
const method = 'POST';
const space = ' ';
const newLine = '\n';
const accessKey = NCLOUD_ACCESS_KEY;
const secretKey = NCLOUD_SECRET_KEY;
const hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, secretKey);
hmac.update([method, space, url, newLine, timestamp, newLine, accessKey].join(''));
const signature = hmac.finalize().toString(CryptoJS.enc.Base64);
- 랜덤 인증번호 생성 및 저장
3.3 프론트엔드 구현 및 hCaptcha 도입
- 핸드폰 번호 입력 폼 개선: 구글 폼에서 가져온 HTML을 기반으로, 핸드폰 번호 입력란과 인증번호 확인란을 추가했습니다.
- 번호 형식 검증: 정규식을 사용하여 '010'으로 시작하는 11자리 번호만 허용했습니다.
const phoneRegex = /^010\d{8}$/;
if (!phoneRegex.test(inputPhoneNumber)) {
alert('유효한 휴대폰 번호를 입력해주세요.');
}
- hCaptcha 도입: 봇이나 스팸을 방지하기 위해 hCaptcha를 도입했습니다.
- 서버 측 검증 추가: 클라이언트 측 검증만으로는 보안에 취약하므로, 서버에서도 입력 데이터에 대한 검증을 추가했습니다.
3.4 SSL 인증서 자동 갱신 설정
Certbot을 사용하여 SSL 인증서를 발급받고 자동 갱신하도록 설정했습니다.
- ssl-renew.sh 스크립트 작성
#!/bin/bash
# SSL 인증서 갱신
sudo certbot renew --quiet
# 인증서 파일 복사
sudo cp /etc/letsencrypt/live/your-domain/cert.pem /home/server/keys/cert.pem
sudo cp /etc/letsencrypt/live/your-domain/privkey.pem /home/server/keys/privkey.pem
# 파일 권한 변경
chmod 644 /home/server/keys/cert.pem
chmod 644 /home/server/keys/privkey.pem
# 서버 재시작
pm2 reload all
- sudo 권한 설정: 스크립트 실행 시 비밀번호 없이
sudo
명령을 사용할 수 있도록visudo
를 통해 설정했습니다.
your_username ALL=(ALL) NOPASSWD: /home/server/ssl-renew.sh
- cron에 등록: 매월 30일 오전 8시에 스크립트가 실행되도록 설정했습니다.
cron에 등록하기 위해서는 그냥 crontab -e 가 아니라, sudo EDITOR=nvim crontab -e 으로 접근해야 했습니다.
0 8 30 * * /bin/bash /home/server/ssl-renew.sh >> /home/server/cron.log 2>&1
배운 점
- 서버 측 검증의 중요성: 클라이언트 측 검증만으로는 충분하지 않으며, 서버 측에서도 철저한 검증이 필요함을 깨달았습니다.
- HMAC의 이해와 활용: NCLOUD SENS API를 사용하면서 HMAC에 대해 배우고 실제로 적용해볼 수 있었습니다.
- 자동화의 편리성: Certbot과 cron을 활용하여 SSL 인증서 갱신을 자동화함으로써 운영 효율을 높였습니다.