내가 담당하는 서비스는 Passwordless 방식의 로그인 기능만 지원하고 있다.
Passwordless-login은 말 그대로 패스워드 대신 신뢰할 수 있는 대체 수단을 이용해 인증하는 방식을 말한다. PIN 번호/생체인증 또는 휴대전화 인증과 계좌인증 등을 떠올리면 이해가 쉬울 것이다.
일반적인 ID/PW 인증 방식은 유효한 ID와 PW만 있다면 쉽게 자동화가 가능하지만 내가 담당한 서비스의 Passwordless-login 방식은 해결해야 할 문제점들이 많았다. 로그인 과정에서 SMS로 전달받은 인증번호가 필요하고 SMS 인증 후에는 계좌 1원 인증, 그 이후에는 PIN 인증까지 해결해야 했다.
이번엔 위 언급한 과정 중에 SMS 인증을 어떻게 우회하여 해결할 수 있는지 검토해 본 결과를 기록해 보려 한다.
자동화 코드가 실행되어 통신사, 유효한 핸드폰 번호를 입력하고 인증요청을 보내면 테스트 단말기에 문자 메시지가 전송된다. 테스트 단말기에 수신된 SMS를 편하게 읽어올 수 있는 방법이 있으면 좋으련만 그런 방법은 찾지 못했다. 그래서 그냥 직접 구현하기로 했다.
간략한 흐름을 정리해 보면 다음과 같다.
테스트 단말기 내에 설치된 리눅스에서 python 코드를 실행하여 SMS를 읽어오고, 정규표현식으로 읽어온 메시지 중 숫자 6자리만 발라내어 웹훅으로 전달해 주는 형태를 구상했다.
테스트 단말기에 리눅스를 설치하는 방법은 간단하다. 구글 스토어나 f-roid를 통해 Termux(ubuntu)를 설치해준다.
그리고 Termux를 통해 안드로이드 시스템에 접근하기 위해 f-roid에서 Termux-API도 설치해 준다. 안드로이드 시스템에 접근하여 Termux-API를 이용하면 전화를 건다거나 문자를 보내거나 다양한 동작을 수행할 수 있다.
그 외에 Python 설치 과정, pip install 과정은 기록을 생략한다.
실제 구현한 코드 일부이다.
코드를 보면 알겠지만 파이썬 스케줄 모듈을 이용하여 매 5초마다 SMS 내역을 읽어오고,
읽어온 내역을 파싱하여 웹훅으로 쏴주도록 구현이 되어 있다.
def parse_sms_text(data: list) -> str:
"""얻어온 SMS 내역 중 인증번호 발라내기"""
target_number = "15663355"
current_datetime = datetime.now()
before_datetime = current_datetime - timedelta(seconds=5)
for sms in reversed(data):
received_date = datetime.strptime(sms.get("received"), "%Y-%m-%d %H:%M:%S")
if sms.get("number") == target_number and before_datetime <= received_date <= current_datetime:
text = sms.get("body")
number_in_text = re.sub(r"\D", "", text)
return number_in_text
return "검색된 SMS 없음."
def send_dm(user_id, message):
"""슬랙으로 인증번호 전송하기"""
if message.isdigit():
try:
response = client.chat_postMessage(channel=user_id, text=message)
print(f"메시지 전송 : {response['message']['text']}")
except SlackApiError as e:
print(f"메시지 전송 에러 : {e}")
else:
print(f"인자로 전달된 메시지 본문이 숫자가 아닙니다. 넘어온 메시지: {message}")
def execute_multiple_function():
"""스케줄잡에서 실제 실행하는 함수"""
result = subprocess.run(['termux-sms-list'], capture_output=True)
output = result.stdout
json_data = json.loads(output) # 실행 결과 JSON으로 저장
user_id = "**********"
send_dm(user_id, parse_sms_text(json_data))
# 스케줄잡 생성
schedule.every(5).seconds.do(execute_multiple_function)
while True:
schedule.run_pending()
time.sleep(1)
안드로이드에 설치된 리눅스를 통해 간단한 Python 코드를 실행하여 SMS를 읽어오고, 읽어온 결과를 정규표현식으로 파싱하여 서버로 전달할 수 있다. 테스트 인프라와 결합해서 잘 활용해 볼 수 있을 것 같다.
좋은 글 감사합니다. 자주 올게요 :)