Skip to content
isdnetworks
Go back

그 가드가 실제로 막는 것

(수정됨)

텔레그램 봇에 운영자 전용 명령을 몇 개 두면서 구독자 이메일 목록을 뽑는 /subscribers 도 넣었고 개인 대화에서만 되게 막아 놨다고 생각했다. 그런데 공개 그룹 채팅에서 그대로 동작해 목록이 그룹 전체에 나왔다.

Table of contents

Open Table of contents

원인 — 조건이 확인한 것

가드는 ctx.from.id 를 보는 이런 조건이었고 주석까지 달려 있었다.

if (ctx.from?.id !== OPS_CHAT_ID) {
  return;
}

주석에는 그룹에서는 발신자 ID 와 개인 대화 ID 가 결코 같지 않다고 적혀 있었는데 그 가정이 틀렸다. Telegram Bot API 명세대로 Message.from 은 메시지를 보낸 사용자이고 대화 종류는 Message.chat 의 type 에 private·group·supergroup·channel 로 따로 들어온다. 그러니 from.id 는 개인 대화에서 보내든 그룹에서 보내든 같은 값이고, 내 계정으로 보내면 어디서 보내도 내 식별자가 들어온다.

그러니까 이 조건은 운영자가 보냈는지만 확인하고 어디서 보냈는지는 확인하지 않는다. 개인 대화 여부를 거르는 조건이 애초에 없었고 대화 종류는 별도 필드로 봐야 했다. 고치는 데는 두 가지 방법이 있었는데 ctx.chat.type === 'private' 를 조건에 더하는 것과 운영자 명령을 아예 별도 봇으로 떼는 것이다. 앞쪽을 골랐다. 이유는 명령이 몇 개뿐이라 봇을 하나 더 두는 운영 비용이 더 커서다. 대신 명령을 추가할 때마다 같은 가드를 빠뜨리지 않아야 하는 것을 감수했다. 근거는 가드가 명령 핸들러 안에 있으면 핸들러를 새로 쓸 때 함께 써야 한다는 점이다.

교훈 — 못 본 이유

조건은 있었고 그 코드를 읽기도 했는데 그 조건이 무엇을 확인하는지는 따지지 않았다. 주석이 한몫했다. 그룹에서는 값이 다르다고 적혀 있으니 그것을 사실로 받아들였다. 주석은 작성자가 그렇게 믿었다는 기록이지 지금 그렇다는 관측이 아니다.

테스트도 개인 대화에서만 했고 통과했는데, 그 통과는 아무것도 가르지 못하는 통과였다. 그룹에서 한 번만 쳐 봤으면 그 자리에서 드러났을 것이다.

같은 형태의 다른 사례

안전장치가 한쪽 경로에만 걸린 경우가 있었다. 전송을 막는 send_disabled 플래그를 두고 안전하다고 여겼는데 그 플래그는 자동 전파 경로에만 걸려 있어서 화면에서 직접 수정하는 경로는 그 문을 지나지 않았다. 시험 삼아 저장했더니 실제로 외부에 전송이 나가고 상품 번호까지 생겼다.

검사가 예정을 센 경우도 있었다. DRY_RUN 모드에서 쓰기가 없는지 확인하는 grep 패턴이 미리보기 문구 안의 문자열과 일치해서, 검사는 돌았고 결과도 나왔지만 그 결과는 쓸 예정인 건수였다.

부재를 못 가른 경우도 있었다. 판매자센터에서 0건이 나와 주문이 없다고 판단했는데 실제로는 검색 필드가 그 유형을 못 잡거나 기간 제한에 걸리거나 세션이 끊긴 것이었고 셋 다 화면에는 0건으로 보인다.

판단 기준 — 가드를 볼 때 묻는 것

이 조건이 참이 되는 경우와 거짓이 되는 경우를 각각 말할 수 있는지 먼저 묻는다. 말하지 못하면 그 조건이 무엇을 거르는지 모르는 것이고, 그다음 막으려는 것이 이 조건으로 실제로 걸리는지 본다. 이번 건에서 막으려던 것은 공개 채팅에서의 실행이었는데 조건은 그것과 무관했다.

모든 진입 경로에 걸려 있는지도 확인한다. 자동 경로에만 걸고 화면의 save 경로를 빼면 그 플래그는 안전장치가 아니라 자동 경로 전용 필터다. 마지막으로 실패해야 하는 입력으로 한 번 돌려 본다. 그룹 채팅에서 쳐 보고 등록 안 된 주소에서 호출해 보고 확실히 없는 값으로 검색해 보는 것인데, 그 입력이 통과하면 그 가드는 없는 것과 같다.

정리


Share this post on:

Previous Post
Android SMS 릴레이 앱에서 MMS를 SMS처럼 PDU 파싱하면 생기는 문제
Next Post
LiteLLM Proxy 폴백 구조를 4단에서 2단으로 줄인 이유