타자 테스트는 부정행위를 어떻게 잡아낼까요? 저희의 검사 방법

타자 테스트는 각 점수 뒤에 있는 키 입력 로그를 확인해서 부정행위를 잡아내요. 저희는 모든 결과를 키 입력 로그로 다시 계산하고, 해시를 확인하고, 로그의 구조와 타이밍을 검사하며, 130 WPM을 넘으면서 타이밍도 이상해 보이는 시간제 결과는 재테스트를 통과할 때까지 공개 보드에 올리지 않아요. 타이밍 검사는 허술한 봇을 잡고, 재테스트는 정교한 봇에게 모든 걸 다시 하게 만들어요.

저희 타이밍 검사를 처음 통과한 봇은 저희 것이었어요.

저희의 엔드투엔드 테스트 도우미는 40 ms 고정 간격으로 키를 눌렀어요. 테스트 스크립트는 원래 그렇게 하니까요. 서버는 결과를 다시 계산하고 해시를 확인한 다음, 그 기록을 의심스럽다고 판정했어요. 키 입력 사이 편차 0, 롤오버 0, 키를 누르고 있는 시간도 모두 똑같았거든요. 저희 테스트 묶음이 사람 같은 결과를 올리게 하려면 단어마다 무작위 흔들림과, 가끔 80~300 ms의 "생각하는" 멈춤을 넣어야 했어요. 그 옵션은 humanLike라는 이름으로 지금도 코드에 남아 있어요.

이 검사들은 애쓰지 않는 것은 모두 잡아내지만, 애쓰는 것은 통과할 수 있어요. 그래서 설계의 진짜 무게는 재테스트에 실려 있어요.

1단계: 모든 것을 다시 계산하기

브라우저는 저희에게 WPM을 보내지 않아요. 키 입력 로그(모든 keydown, keyup, input, composition 이벤트에 단조 증가하는 performance.now() 시계로 타임스탬프를 찍은 것), 브라우저가 계산한 지표, 정규화한 결과의 SHA-256 해시를 보내요.

서버는 같은 지표 코드를 로그에 돌려서 비교해요. 숫자 하나라도 0.01 넘게 다르면 결과는 metrics_mismatch로 거부돼요. 해시가 맞지 않으면 hash_mismatch로 거부돼요. 클라이언트를 믿는 사이트에서 가장 흔한 부정행위인, WPM 값을 고치는 브라우저 확장 프로그램은 여기서 걸려요. 화면에 보이는 숫자와 데이터베이스에 들어가는 숫자를 같은 함수가 만들어요. 그래서 저희 지표 페이지는 계산 예시가 소수점 둘째 자리까지 똑같이 재현된다고 약속할 수 있어요.

왜 서버에서 시간을 재지 않을까요? 그러면 점수에 네트워크가 포함되기 때문이에요. 모든 키 입력이 연결 상태에 따라 들쭉날쭉하게 조금씩 늦게 도착하고, 느린 회선을 쓰는 빠른 타자수는 실제로 가진 속도를 잃게 돼요. 로그 덕분에 정확도는 클라이언트의 시계로, 정직함은 서버의 재계산으로 확보할 수 있어요.

2단계: 로그가 말이 되나요?

타이밍을 분석하기 전에, 제출된 기록의 형태를 단순하게 확인해요.

  • 테스트는 15초 또는 10단어 이상이어야 해요. 더 짧으면 순위를 매기기엔 변동이 너무 크고, 부풀리기도 가장 쉬워요.
  • 결과는 테스트가 끝날 수 있는 시점, 즉 시작 시각에 테스트 길이를 더한 시점보다 먼저 도착할 수 없어요. 시작하고 20초 만에 도착한 60초 결과는 실제로 일어난 일이 아니에요.
  • 이벤트 수는 입력한 글자 수와 맞아야 해요.
  • 데스크톱에서는 모든 input 이벤트가 50 ms 안에 keydown 뒤에 와야 해요. 이 규칙으로 붙여 넣은 텍스트, 스크립트로 만든 input 이벤트, 그리고 실제 키 없이 텍스트를 쏘아 넣는 키 입력 주입 도구 대부분을 잡아요. 입력기(IME 조합)로 입력하는 경우는 예외이고, 휴대폰 기록은 공개 보드에 오르지 않아요.
  • 시작이나 끝이 없거나, 타임스탬프가 단조 증가하지 않는 로그는 형식이 잘못된 것으로 보고 곧바로 거부해요.

전혀 기발하지 않지만, 이것만으로 대부분이 걸러져요.

3단계: 키 입력 타이밍은 무엇을 드러낼까요?

이 부분은 일부러 전부 공개하지 않아요. 특징 목록은 공개하지만, 기준값과 가중치는 공개하지 않아요. 공개된 기준값은 과녁이 되니까요. "표준편차가 N밀리초 미만이면 표시한다"고 밝히면, 모든 스크립트의 다음 버전은 N에 1을 더할 거예요. 저희가 점수를 매기는 특징은 다음과 같아요.

키 사이 평균 간격과 그 편차. 사람의 타자는 불규칙해요. Dhakal과 동료들이 2018년에 타자수 168,960명을 연구한 결과, 키 사이 평균 간격은 약 239 ms, 표준편차는 약 112 ms였어요. 고정 간격으로 치는 스크립트는 편차가 거의 없어요. 키 입력 기반 CAPTCHA를 다룬 2025년 arXiv 연구도 50 ms 고정 지연으로 치는 테스트 봇에서 바로 그 현상을 봤어요. 이것이 저희의 가장 강한 신호이고, 저희 도우미가 걸린 신호이기도 해요.

40 ms 미만 간격의 비율. 40 ms 간격을 계속 유지하면 분당 1,500자, 다섯 글자를 한 단어로 치면 300 WPM이에요. 손가락도 롤오버로 키를 겹쳐 누를 때는 그렇게 짧은 간격을 한 번씩 만들어 내니, 짧은 간격 하나는 아무 의미가 없어요. 간격의 상당 부분이 그렇게 짧은 로그는 타자가 아니에요.

키를 누르고 있는 시간. 실제 손가락은 수십 밀리초씩 차이가 나요. 합성 이벤트는 누르는 시간이 똑같거나 0에 가까운 경우가 많아요. 도구가 keydown과 keyup을 연달아 쏘기 때문이에요.

롤오버 비율. 앞의 키가 올라오기 전에 다음 키가 내려가는 빈도예요. Dhakal은 평균 롤오버 비율 25%를 측정했고, 빠른 타자수 대부분은 키 입력의 40~70%에서 롤오버를 했으며, 키가 평균 30 ms씩 겹쳤어요. 느린 타자수는 롤오버를 거의 하지 않으니, 롤오버가 전혀 없는 빠른 결과는 눈에 띄어요. 봇은 키를 겹쳐 누르는 일이 드물어요.

가장 긴 멈춤, 초 단위 속도 변화, 1초 넘는 간격의 비율. 사람은 머뭇거려요. 스크립트는 그걸 흉내 내라고 일일이 지시받아야 해요.

이 특징들을 조합한 점수 모델이 결과를 의심스럽다고 표시할 수 있어요. 130 WPM 미만에서는 표시만으로 거부되는 일은 없어요. 결과가 본인에게 숨겨지는 일도 절대 없어요. 이 검사는 순위에 올릴지 말지만 정해요.

타자 테스트 부정행위가 타이밍 검사를 통과할 수 있나요?

정교하게 만들었다면 그래요. 2026년 1월 데이비드 콘드리(David Condrey)의 arXiv 논문은 사람이 친 텍스트와 AI가 생성한 텍스트를 구분하려는 키 입력 타이밍 탐지기를 시험했어요. 완전히 자동화된 주입은 완벽하게 구분했지만, 사람의 타이밍을 쓴 공격(사람이 AI 텍스트를 다시 치거나, 프로그램이 사람의 타자 데이터에서 지연을 뽑아 쓰는 방식)은 다섯 개 분류기를 모두 99.8% 이상의 비율로 피해 갔어요. 이 논문은 타자 테스트가 아니라 작성자 판별에 관한 것이지만, 교훈은 그대로 적용돼요. 3단계는 허술한 것만 잡고 그 이상은 별로 잡지 못해요.

저희 테스트 도우미도 작은 규모로 같은 점을 보여 줘요. 무작위 흔들림과 멈춤 몇 번만으로 누가 봐도 합성인 기록이 그럴듯한 기록이 됐어요.

그래서 3단계는 필터예요. 판정은 4단계에서 나와요.

4단계: 검증 재테스트

시간제 결과가 130 WPM을 넘으면서 타이밍도 이상해 보이면, 결과는 본인에게 보이고 저장되지만, 검증 재테스트를 통과할 때까지 공개 보드에는 오르지 않아요. 재테스트는 새로 치는 30초 테스트이고, 주장한 속도의 75% 이상을 내야 해요. 한 번뿐인 요행이나 빌려 온 로그는 두 번째 시도를 버티지 못해요.

왜 130 WPM일까요? Dhakal 데이터의 평균 51.56 WPM의 약 2.5배로, 대부분의 타자수를 훌쩍 넘는 속도이고, 정말 그만큼 빠른 사람이라면 두 번도 칠 수 있어요. 갑자기 나온 빠른 결과에 타이밍까지 이상하다면 빌려 온 로그나 스크립트가 만드는 모양이고, 정직한 결과라면 테스트 한 번 더는 작은 대가예요.

재테스트는 일반 텍스트로 치는 평범한 타자 테스트예요. 일그러진 이미지나 이상한 기호로 가득한 페이지가 아니에요. 읽기 어려운 텍스트는 모두를 느리게 만들고, 가장 크게 느려지는 건 재테스트로 혐의를 벗겨 주려는 바로 그 정직하고 빠른 타자수예요. 정직하고 빠른 타자수가 떨어지는 검증은 없느니만 못해요. 일반 텍스트는 검사를 공정하게 만들기도 해요. 재테스트의 로그도 다른 결과와 똑같은 타이밍 검사를 거치니까요.

제출 횟수 제한과 이용 제한

제출 횟수에는 제한이 있어요. 로그인한 사용자당 분당 30회, IP 주소당 60회예요. 검사에 계속 걸리는 계정은 섀도밴, 즉 조용히 보드에서 숨겨지고, 24시간 안에 심각한 부정행위 방지 이벤트가 세 번 발생하면 자동으로 그렇게 돼요. 일정 기간 안의 이벤트를 세기 때문에 이상한 결과 하나로 계정을 잃는 일은 없고, 계속 실패하는 스크립트는 금방 멈춰요.

역대 리더보드에 오르려면 계정에 30분 이상의 타자 기록도 있어야 해요. 그래서 완벽한 기록 하나뿐인 새 계정이 1위에 오를 수는 없어요.

의도치 않게 표시되는 경우

표시된 결과 대부분은 부정행위가 아니에요. 정직하게 검사에 걸리는 경우는 이래요.

휴대폰 자동 수정. 수정된 내용은 여러 글자를 바꾸는 input 이벤트 하나로 들어와요. 저희는 이걸 키 입력 한 번으로 세고, 표시해 두며, 거부하는 대신 안내 문구와 함께 공개 보드에서 제외해요.

붙여 넣은 텍스트. 붙여 넣기는 막혀 있고, 붙여 넣기를 시도한 결과는 보드에서 제외돼요.

탭 전환. 테스트 도중 포커스가 2초 넘게 페이지를 벗어나면 중단된 것으로 표시돼요. 저장되고 보이지만 순위에는 오르지 않아요.

멈춤. 단어나 인용문 테스트에서 5초 넘게 멈추면 일시정지로 표시돼요. 처리는 같아요.

IME 조합. 일본어, 한국어, 중국어 입력은 composition 이벤트로 들어오기 때문에, 이 경우에는 keydown 규칙을 건너뛰어요. 그런데도 뭔가 이상해 보인다면 그건 버그이니, 로그를 보내 주시면 좋겠어요.

오프라인 결과. 끝나고 10분 넘게 지나서 동기화된 결과는 기록에는 남지만 순위에는 오르지 않아요. 시계를 검증할 수 없으니까요.

정말로 빠른 경우. 130 WPM을 넘으면 재테스트를 만나게 돼요. 아마 처음으로 컨디션이 좋은 날일 거예요.

이의 제기 방법

제외된 기록마다 기록 페이지에 이유가 표시돼요. 어떤 결과나 제한에 대한 저희 판단이 틀렸다고 생각한다면, 계정에 등록된 이메일 주소로 저희 부정행위 방지 페이지에 있는 이의 제기 주소에 메일을 보내 주세요. 결과 링크나 테스트 날짜와 시간을 함께 적어 주세요. 사람이 직접 키 입력 리플레이를 보고 며칠 안에 답장해요. 이의 제기는 절대 자동 모델만으로 결정하지 않아요.

방금 검사 통과법을 공개한 걸까요? 일부는 그래요. 특징 목록은 원래 동작을 보면 알아낼 수 있었고, 기준값은 계속 비공개예요. 중요한 건 재테스트이고, 그걸 통과하는 방법은 직접 치는 것뿐이에요.

자주 묻는 질문

타자 테스트는 봇을 어떻게 잡아내나요?

잘 만든 테스트는 키 입력 로그를 읽어요. 모든 글자 뒤에 실제 키 누름이 있는지, 키 사이 간격이 얼마나 들쭉날쭉한지, 키를 어떻게 누르고 겹쳐 누르는지를 봐요. 스크립트는 지나치게 규칙적인 경향이 있어요. 정교한 봇은 사람을 흉내 낼 수 있어서, 저희는 재테스트를 더해요.

봇이 타자 테스트의 부정행위 방지를 통과할 수 있나요?

정교한 봇은 타이밍 검사를 통과할 수 있어요. 키 입력 타이밍 탐지기를 다룬 연구에서 사람처럼 위조한 타이밍은 거의 매번 탐지를 피했어요. 그래서 저희는 빠른 결과를 재테스트까지 보류해요. 봇은 같은 검사를 통과하는 두 번째 로그로 다시 한번 통과해야 해요.

제 타자 테스트 결과가 순위에 오르지 않은 이유는 뭔가요?

보통 15초 또는 10단어보다 짧은 테스트, 5초 넘는 멈춤, 탭 전환, 또는 재테스트를 기다리는 130 WPM 초과 결과 때문이에요. 기록 페이지에 이유가 나와요.

출처