sgkstudio.
엔지니어링

간편인증 자동화 — PASS 로그인 9번 실패, 원인은 매번 달랐다

간편인증 자동화에서 9번 연속 실패한 원인은 하나가 아니었고, 그래서 우리는 10번째 자동 재시도 대신 멈추는 쪽을 택했습니다. 앞의 다섯 번은 서버가 '인증서를 발급하지 않으셨다면'이라는 문구로 거절해 인증서 문제처럼 보였지만, 실제로는 우리 코드가 숨은 주민번호 칸에 생년월일 일부를 흘려 넣은 탓이었습니다. 그 칸을 비우자 요청은 폰까지 갔고, 이번에는 네 번이 네 가지 다른 이유로 무너졌습니다. 매번 '직전 수정으로 고쳤다'고 믿고 돌렸다는 점이 이 글의 핵심입니다.

2026-09-27증상 — 2026년 9월 11일 정부24 간편인증 실전 9회 연속 실패. 1~5회차는 서버 거절(OACX_NO_USER), 6~9회차는 요청은 폰에 닿았으나 각각 다른 이유로 실패반증된 가설 1 — 거절 문구의 '인증서 미발급'. 제공자 5곳이 같은 코드로 거절했고 원인은 숨은 주민번호 칸 ssn1 오염이었다반증된 가설 2 — 6회차 '요청 유효시간 3분 만료'. 8회차 서명 화면의 기한은 요청 후 약 5분이었다관측 수단 — 서버 응답 JSON(oacxCode), 전송을 막은 요청 캡처, 폰 UI 트리(uiautomator), 폰 전면 앱 기록, 알림 목록결정 — 9회 실패 뒤 자동 재시도 중단, 운영자의 명시적 한 줄 신호가 있을 때만 재개. 테스트 13건 → 28건재개 결과 — 10·11회차 실패(옆 세션의 폰 조작, 우리 알림 오판), 12회차 PASS 로그인 성공(인증서 비밀번호 6자리 1회), 13회차 카카오 로그인 성공(지문 1회), 테스트 44건

증상 — 9번 돌렸고 9번 모두 로그인하지 못했다

2026년 9월 11일, 정부24 로그인 화면의 간편인증에 우리가 만든 자동화를 실제로 태웠습니다. 흐름은 이렇습니다. PC 쪽 에이전트가 정부24에 이름·생년월일·전화번호를 넣고 인증 요청을 보내면, 휴대폰에 PASS나 카카오톡 인증 알림이 옵니다. 폰 쪽 스크립트 `auth-touch.py`가 그 알림을 눌러 승인 화면까지 열어 두고, 사람은 지문이나 비밀번호만 넣습니다.

결과는 9회 연속 실패였습니다. 앞의 다섯 번은 요청이 폰까지 가지도 못했습니다. 서버가 `OACX_NO_USER`라는 코드로 거절했고, 폰에는 알림이 한 건도 오지 않았습니다. 여섯 번째부터는 요청이 폰에 닿았지만 매번 다른 곳에서 무너졌습니다. 그날 운영자가 받은 호출 텔레그램은 8회차까지 4건이었고, 로그인으로 이어진 것은 0건이었습니다.

표. 2026년 9월 11일 간편인증 실전 1회차부터 9회차까지. 1~5회차는 카카오톡, 통신사PASS 두 번, 토스, 삼성패스 순으로 모두 서버 거절. 6회차는 요청 성공 후 3분 19초 뒤 오류 4115, 7회차는 알림을 눌렀는데 무관한 앱이 앞에 뜸, 8회차는 동의 체크 전 서명 시도, 9회차는 만료된 옛 요청에 서명
실전 9회의 결과와 원인

처음 의심한 것 — 인증서를 발급하지 않았다는 서버 문구

1회차 카카오톡 요청에 서버는 이렇게 답했습니다.

입력하신 정보로 인증을 진행할 수 없습니다 … 인증서를 발급하지 않으셨다면 가입 후 이용하시기 바랍니다

문구가 원인을 친절하게 알려 주는 것처럼 보였습니다. 카카오 인증서를 안 만들었나 보다 싶어 통신사PASS로 바꿔 두 번 더 보냈고, 같은 문구와 `OACX_NO_USER`가 돌아왔습니다. 이 시점의 작업 기록에는 'PASS·카카오 실전 1차는 요청이 폰에 닿기 전 서버 거절, 인증서 보유 확인 후 재실전'이라고 적었습니다. 인증서가 없다는 가설을 사실상 믿고 있었습니다.

그 가설을 무엇으로 확인했나?

인증서가 정말 없는지 확인하려고, 에이전트가 직접 볼 수 있는 기록부터 모았습니다. 쓴 수단은 넷입니다.

  • 제공자 바꿔 보내기 — 카카오톡, 통신사PASS에 이어 토스와 삼성패스까지 보냈다. 토스는 판별용이었다. 한 제공자의 인증서 문제라면 다른 제공자는 통과해야 한다
  • 신원값 대조 — 값을 화면에 찍지 않고 일치 여부만 봤다. 전화번호는 폰 회선 번호와, 생년월일은 서로 다른 문서 두 곳과 일치했다. 통신사도 KT로 맞았다
  • 전송 본문 캡처 — 요청이 실제로 나가지 않게 막은 상태에서 보내는 내용의 형태만 확인했다. 이름·생년월일·전화번호 칸이 모두 채워져 나가고 있었다
  • 서버 응답 JSON — 화면 문구가 아니라 응답의 `oacxCode`와 `clientMessage`를 읽었다

5회차 삼성패스까지 결과는 같았습니다. 다섯 번 모두 `OACX_NO_USER`였고, 폰에는 알림이 오지 않았습니다.

왜 인증서 문제가 아니었나?

인증서 가설은 두 가지 사실과 맞지 않았습니다. 먼저 제공자 네 곳이 똑같이 거절했습니다. 카카오, PASS, 토스, 삼성패스 인증서를 한꺼번에 하나도 안 가졌을 수는 있어도, 네 곳이 같은 코드로 '이 사람 없음'이라고 답한다면 서버가 받은 신원 정보 쪽을 먼저 의심하는 편이 맞습니다. 다음으로 우리가 넣은 이름·생년월일·전화번호 세 값은 전부 맞았습니다.

세 값이 맞는데 서버가 사람을 못 찾는다면, 남은 곳은 우리가 넣지 않았다고 생각한 칸입니다. 그래서 전송 본문의 필드를 처음부터 끝까지 다시 봤습니다. 거기에 화면에 보이지 않는 주민번호 칸 `ssn1`이 있었고, 생년월일의 월 두 자리로 채워져 나가고 있었습니다. 새 창에서 열면 이 칸은 빈 값이었습니다. 금고에 둔 값을 입력칸에 옮기는 우리 주입 코드가 숨은 칸까지 건드린 결과였습니다.

코드 비교. 이전 전송 본문에는 이름, 생년월일, 전화번호와 함께 숨은 주민번호 칸 ssn1이 생년월일의 월 두 자리로 채워져 있었고 응답은 OACX_NO_USER. 이후에는 ssn1이 0자로 비어 있고 응답은 OACX_SUCCESS
전송 본문 — 숨은 칸 하나

`ssn1`을 비운 6회차 PASS 요청은 곧바로 `OACX_SUCCESS`, '앱에서 인증을 진행해주세요'로 바뀌었습니다. 나중에 카카오도 같은 조건으로 다시 보냈더니 통과해, 1회차 카카오 거절 역시 같은 오염이었다는 점을 확인했습니다. 이 일로 남긴 규칙은 하나입니다. 거절 문구의 '인증서를 발급하지 않으셨다면'은 원인 판정이 아닙니다. 신원값 셋이 맞으면 전송 본문의 모든 필드를 봅니다.

진짜 원인 — 요청이 닿은 뒤 네 번, 네 가지 결함

첫 원인을 잡았으니 이제 되리라 생각했습니다. 그런데 요청이 폰에 닿기 시작하자 새 결함이 한 번에 하나씩 나왔습니다.

6~9회차 — 요청은 성공했고 폰에서 무너졌다
회차폰에서 벌어진 일드러난 결함
6회차알림을 눌러 곧바로 지문 창이 떴고, 요청 후 3분 19초에 창이 닫힌 뒤 웹은 오류 4115창이 닫힌 뒤 화면 글자를 기록하지 않아 만료인지 취소인지 판정 불가
7회차알림창에서 PASS 알림 글자를 눌렀는데 전면에 KT '후후' 앱이 떴다누른 뒤 원하는 앱이 앞에 왔는지 확인하지 않았다. 흐름이 실패했는데도 웹 쪽이 '인증 완료'를 눌렀다
8회차'PASS 서명 요청' 화면에서 동의 체크 전에 '서명하기'를 누르고, 제목 '정부24 간편인증'을 '인증' 부분일치로 눌렀다UI 트리에 체크 상태가 없었다. 짧은 글자를 부분일치로 찾았다
9회차알림을 못 찾아 앱을 직접 열자 8회차의 만료된 요청이 떴고, '서명하기'와 실패 창의 '확인'까지 눌렀다실패·만료 글자를 봐도 멈추지 않았다. 서명 화면의 기한을 읽지 않았다

6회차에는 처음에 'PASS 요청 유효시간 3분이 지나 만료됐다'고 해석했습니다. 이것도 틀렸습니다. 8회차에 처음 본 서명 요청 화면의 기한은 13:33:16, 요청 후 약 5분이었습니다. 지금은 6회차에 뜬 지문 창이 서명용이 아니라 앱을 여는 잠금이었다고 봅니다(추정). 10회차에도 지문 뒤 화면이 서명 완료가 아니라 PASS 홈이었고 웹은 다시 4115였기 때문입니다.

흐름도. 웹 요청, 폰 알림, 알림 탭, 서명 요청 화면, 전체 동의, 서명하기, 인증서 비밀번호 또는 지문, 웹 인증 완료 순서. 6회차는 앱 잠금 지문 뒤 4115, 7회차는 알림 탭 뒤 다른 앱, 8회차는 동의 전 서명, 9회차는 만료 요청에 서명한 지점을 표시
간편인증 흐름과 회차별로 무너진 지점

왜 '이번엔 고쳤다'가 네 번이나 틀렸나?

8회차와 9회차는 둘 다 '직전 수정으로 고쳤다'는 확신 아래 돌렸습니다. 그리고 두 번 모두 새 결함이 나왔습니다. 수정은 매번 실제 결함을 고쳤으니 틀린 수정은 아니었습니다. 틀린 것은 '다음 시도는 다를 것'이라는 기대였습니다. 폰 화면은 알림 순서, 다른 앱, 동의 화면 모양처럼 우리가 아직 본 적 없는 경우를 계속 내놓았고, 한 번의 실전은 그중 하나만 드러냈습니다.

여기에 사람 몫이 끼어 있다는 점이 문제를 키웠습니다. 이 흐름은 마지막에 사람이 지문을 넣어야 끝나고, 지문을 늦게 넣으면 요청이 만료됩니다. 자동 재시도 한 번은 곧 운영자를 한 번 더 부르는 일입니다. 실패가 뻔한 시도에 사람 손을 쓰면, 나중에 정말 필요할 때 사람이 알림을 믿지 않게 됩니다.

9회차에는 프로세스 결함도 하나 있었습니다. 8회차 뒤 루프 감지 규칙에 따라 실전을 멈춘 상태에서, 운영자가 '왜 폰을 들고 있어야 하느냐'고 물었습니다. 에이전트는 이 질문에 답하는 과정에서 명시적 지시 없이 9회차를 다시 돌렸습니다. 질문은 재개 지시가 아니었습니다.

고친 방법 — 결함마다 막고, 자동 재시도는 멈췄다

회차마다 드러난 결함은 그 자리에서 코드로 막았습니다. 9회차 수리까지 포함해 `auth-touch.py` 테스트가 13건에서 28건으로 늘었습니다.

  • 숨은 칸 — 요청 전에 `ssn1`이 0자인지 확인한다
  • 알림 탭 뒤 전면 확인 — 누른 뒤 4.5초 안에 인증 앱이 앞에 오는지 보고, 아니면 뒤로가기를 누른 뒤 앱을 직접 연다. 무엇을 눌렀는지 기록한다
  • 웹 쪽 완료 버튼 — 폰 흐름이 성공했을 때만 '인증 완료'를 누른다. 실패면 75초 뒤 한 번만 확인한다
  • 동의 순서 — UI 트리에 체크 가능 여부와 체크 상태를 추가하고, 미체크 동의가 있으면 '전체 동의'부터 누른다. 4자 미만 글자는 정확히 일치할 때만 누른다
  • 실패 글자에서 멈춤 — 실패·만료 글자가 보이면 아무것도 누르지 않는다. 서명 화면의 기한이 지났으면 서명하지 않는다
  • 알림을 못 찾을 때 — 알림창에 보인 글자를 기록으로 남긴다

그리고 10번째 자동 재시도는 하지 않았습니다. 9회 연속 실패는 '3회 연속 실패하면 멈추고 사람을 부른다'는 루프 감지 규칙의 문턱을 세 배 넘은 숫자였습니다. 다음 실전은 운영자가 폰을 쥔 상태에서 'PASS 실전'이라고 한 줄을 입력할 때만 돌기로 했습니다. 마침 9회차 직후 폰의 무선 디버깅이 꺼져 20분 재연결 감시도 실패로 끝났으니, 재개 전 조건에 무선 디버깅을 다시 켜는 일도 붙었습니다.

막대그래프. auth-touch.py 테스트 건수. 멈추기 전 13건, 9회차 수리 뒤 28건, 10회차 수리 뒤 34건, 11회차 수리 뒤 40건, 13회차 수리 뒤 44건
실전 회차마다 늘어난 테스트

멈춘 뒤 다시 돌리자 무엇이 또 나왔나?

같은 날 오후 운영자가 'PASS 실전'이라고 입력해 10회차를 돌렸습니다. 이번에도 실패였는데, 원인은 폰 바깥에 있었습니다. '전체 동의'를 누른 직후 폰 전면이 LinkedIn 앱으로 바뀌었습니다. 같은 폰을 쓰던 다른 세션이 14:02:02에 LinkedIn을 열고 버튼을 누르고 있었습니다. 폰을 한 작업이 독점하는 장치가 없었습니다. 그래서 폰 조작 도구에 점유 표시를 넣었습니다. 한 작업이 폰을 잡고 있으면 다른 작업의 누르기 명령은 거절당하고, 기한이 지나거나 잡은 프로세스가 죽으면 풀립니다. 테스트는 34건이 됐습니다.

11회차는 우리 자신의 알림에 걸렸습니다. 알림창을 읽었더니 거기 쌓인 우리 텔레그램 미리보기 '지금 폰에서 지문 한 번 — PASS 인증 승인'의 '지문'이라는 글자를, 스크립트가 지문 창으로 판정했습니다. 같은 시각 회사 PC에서 돌던 다른 자동 로그인 테스트가 증권 앱을 띄운 것도 겹쳤습니다. 우리 알림 글자는 판정에서 빼고, 빈 알림창은 3회까지 다시 읽게 고쳐 테스트가 40건이 됐습니다.

12회차는 성공했습니다. 알림 탭, '전체 동의', '서명하기'까지 스크립트가 했고, 서명 단계에서 뜬 것은 지문이 아니라 PASS 인증서 비밀번호 6자리 입력 창이었습니다. 운영자가 알려 준 6자리를 화면 키패드로 넣자 '인증서 로그인이 완료되었습니다'가 떴고, 정부24 메인에 로그인한 상태로 넘어갔습니다. 13회차 카카오도 성공했습니다. 요청이 알림이 꺼진 대화방으로 와서 알림이 0건이었고, 동의 원형 체크가 UI 트리에 없어 좌표로 눌러야 했지만, 사람 몫은 지문 1회였습니다. 이 두 경우를 코드로 옮겨 테스트는 44건이 됐습니다.

숫자 카드. 1회차부터 11회차까지 로그인 성공 0회. 12회차 PASS 로그인 성공, 사람 몫 인증서 비밀번호 6자리 1회. 13회차 카카오 로그인 성공, 사람 몫 지문 1회
멈춘 뒤 재개한 실전의 결과

같은 실수를 막는 장치는 무엇인가?

코드 결함은 테스트로 막았습니다. 이번 일에서 더 중요한 장치는 코드 바깥의 규칙 셋입니다.

  • 사람 호출이 따르는 실험은 사람의 명시적 한 줄로만 다시 돈다 — 실패 직후 '이번엔 고쳤다'는 확신은 재시도 근거가 아니다. 이 폰 흐름에서 그 확신은 네 번 틀렸다
  • 질문은 재개 지시가 아니다 — 멈춘 상태에서 받은 질문에는 설명으로 답하고, 돌릴지는 따로 받는다
  • 거절 문구를 원인으로 읽지 않는다 — 서버 문구가 추측한 원인보다 서버가 실제로 받은 본문을 먼저 본다
  • 요청이 안 오면 폰을 건드리지 않는다 — 처음 초안은 끝에 무조건 홈 버튼을 눌렀다. 요청이 없던 회차에 그대로 끝났다면 운영자가 쓰던 앱을 닫았을 것이다
  • 실패·만료 글자 앞에서는 아무것도 누르지 않는다 — 9회차처럼 옛 요청에 서명하는 일을 막는다

돌아보면 9번의 실패 중 실제로 서로 다른 결함은 다섯 가지였고, 앞의 다섯 번은 숨은 칸 하나가 만든 같은 실패였습니다. 제공자를 바꿔 가며 같은 실패를 다섯 번 본 셈입니다. 그 뒤 네 번은 전부 달랐지만, 그 차이가 '다음은 성공한다'는 뜻은 아니었습니다. 반복을 세는 기준을 에러 문자열 대신 무엇으로 잡아야 하는지는 AI 에이전트 무한 루프 감지에 따로 적었습니다.

휴대폰 간편인증 자동화, 어디까지 가능한가?

해 보니 에이전트가 할 수 있는 범위는 생각보다 넓었습니다. PASS 앱은 보안 설정 때문에 화면 캡처가 전부 검게 나오지만, 화면 구성 정보인 UI 트리는 읽힙니다. 눈으로 못 봐도 글자와 좌표로 앱을 열고 알림을 누르고 동의를 체크할 수 있습니다. 남는 것은 마지막 지문이나 인증서 비밀번호 한 번입니다.

다만 '자동으로 된다'와 '믿고 맡길 수 있다' 사이의 거리는 실전 횟수로만 줄었습니다. 테스트 13건으로 시작해 44건이 되는 동안 늘어난 경우는 모두 실제 폰이 먼저 보여 준 것들이었습니다. 알림이 꺼진 대화방, 다른 작업이 폰을 쓰는 순간, 우리 자신의 알림 문구처럼 책상 앞에서는 떠올리기 어려운 경우들입니다.

사내 업무에 본인인증이 끼어 있어 자동화가 매번 사람 앞에서 멈춘다면, 어느 단계까지 기계에 넘기고 어디서 사람을 부를지부터 나눠 볼 만합니다. 비슷한 구조를 검토 중이라면 상담으로 현재 흐름을 알려 주세요.

같은 방식으로 우리 업무를 재보고 싶다면

이 글에 쓴 계측·판정·자동화는 저희가 실제로 매일 돌리는 방식 그대로입니다. 어떤 작업을 자동화할 수 있고 어디를 사람이 잡아야 하는지, 현재 업무 흐름을 놓고 같이 짚어 드립니다.

새 글이 올라오면 알려 드립니다

이런 계측 기록을 새로 쓰면 메일로 한 통 보냅니다. 광고나 판촉은 보내지 않습니다.