서론

    많은 웹사이트에서 악성 사용자를 막기 위해 캡챠를 사용하곤 한다. 대표적으로 ReCaptcha가 있다.

    하지만 ReCaptcha는 일정 사용량 이상(10,000건)부터는 과금이 이루어진다.

    하지만 많은 유용한 도구들은 대체제가 있기 마련이다. 내가 제시하는 대안은 Turnstile 이다.

    Turnstile의 장점은 다음과 같다.

    1. 빠르다
    2. 정확하다.
    3. 저렴하다.

    Cloudflare에서 완전 무료를 선언한 Turnstile은 빠르고 정확하며 저렴하기까지 하다.
    ReCaptcha에서 넘어올 만 하지 않은가?

    본론

    사용법과 관련된 내용은 주로 Turnstile Documentation에서 가져온 내용이다.

    먼저 client 검증이다.

    <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" defer></script>
    <div class="cf-turnstile" data-sitekey="yourSitekey"></div>

    script 태그와 div 태그를 적절히 조합하면 위의 gif처럼 캡챠를 시작하는 모습을 볼 수 있다.

    만약 의심스러운 트래픽이라고 판단한다면 바로 인증을 하라는 메세지를 볼 수도 있다.

    data-sitekey에는 당연히 Turnstile 앱을 만든 뒤 나오는 site key를 넣으면 된다.

    server에서는 이 turnstile에서 넘어온 데이터를 검증해야 한다. 이 검증과정도 간단하다.

    curl 'https://challenges.cloudflare.com/turnstile/v0/siteverify' --data 'secret=verysecret&response=<RESPONSE>'`

    우선 cURL 예문이다. Turnstile 앱을 만든 뒤 나오는 secret key와 캡챠 인증 후 나오는 response token을 전송하면

    { success: Boolean } 형식의 응답이 온다. 더 정확히 응답형식을 보려면 Documentation을 확인하자!

    이걸 TypeScript와 fetch API로 바꾼다면 이렇게 변한다.

    const response: { success: boolean } = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
      method: 'POST',
      body: JSON.stringify({
        secret: 'verysecret',
        response: '<RESPONSE>'
      })
    })
    
    if (response?.success ?? false) { /* here to on success */ }

    ReCaptcha와 크게 다를것이 없다. Vue 라이브러리Nuxt 라이브러리도 준비되어 있다. 찾아본다면 React, Svelte 등도 있을 것이다.

    (240926 수정)

    @nuxtjs/turnstile 의 verifyTurnstileToken method를 사용할 때, Serverless 환경(ex: Cloudflare worker)에선 반드시 event를 두번째 인자로 넘겨줘야 한다.

    defineEventHandler(async (event: H3Event) => {
          const token = " /* your token */ "
        const result = await verifyTurnstileToken(token, event)
    })

    결론

    Turnstile은 ReCaptcha와 견줄만 한 인증 시스템이다.

    요즈음 Cloudflare 사를 이용하는 사이트가 많아진 것도 Turnstile의 정확도에 기여하고 있을 것이다.

    ReCaptcha를 감당하지 못하는 소규모 프로젝트라면 Turnstile을 사용하는 것은 어떨까?

    Posted by dalbodeule