클라우드 플레어의 캡차 기능, Cloudflare Turnstile 적용 후기

by
내 사이트, 에루라보는 지금까지 딱히 사람과 봇의 방문에 대해서 검열을 긋진 않고 있었다.
뭐 그도 그럴것이 예전엔 그냥 개발이나 겜글 한두개 올리는 변두리 블로그였기 때문이다.

그래서 그런지 방문자도 적고, 봇도 적고, 크롤러도 적고 뭐 그런 느낌이었다.
그래서 필요한 타이밍에 서버 로그를 보고 과도한 악의적 공격정도만 막는 수준으로만 대응을 했었다.

하지만 팬 자막 제작을 하면서 여러 유입이 늘게 되었고, 이에따라서 블로그 유입관리도 단계적으로 작업과 비용이 올라가게 되었다.


개인적으로 가장 힘들었던 부분이 악의적인 의도로 계속 내 서버를 노크하는 무차별 요청이 제일 곤란했다.
여러모로 웹 서버 비용도 나가면서 서버를 느리게 하는 주범이었기 때문이다.

그래서 이걸 막기위해 자주 요청되는 구조에는 내부 인증방식을 통한 우회방법도 고안해봤지만 뭐 잘 통하지 않았다.
그래서 찾게된게 캡차기능이었다.


클라우드 플레어의 캡차 기능, Cloudflare Turnstile 적용 후기

사실 기존에는 구글 캡차를 이용하긴 했었다.
다만 구글 캡차는 별도의 캡차용 api를 구현해야했었고, 이를 이용해 라라벨 인증단에서 써봤는데 생각보다 깔끔하게 적용되지않았다.

제일 귀찮았던게 사이트 인증방식이었던 것.

근데 클라우드 플레어의 캡차기능인 턴스틸은 전혀 그렇지 않았다.
그저 클라우드 플레어에서 계정을 만들고 턴스틸 위젯을 만들면 적용준비가 순식간에 완료된다는 것...


content_image걍 위젯만 만들고 키값만 얻어주면 준비 끝이다

적용과정은 아래와 같이 히스토리로 남겨보고자한다.


1. 적용대상

  • - 보호 대상: 파일 링크 다운로드 준비 단계
  • - 사용자 흐름: 게시글의 파일 링크 버튼 클릭 -> Turnstile 확인 -> 서버에서 1회용 다운로드 토큰 발급 -> 실제 다운로드 URL로 이동
  • - 적용 조건: 게시글 본문에 /file/{uid} 형식의 파일 링크가 있고, Turnstile site key가 설정되어 있을 때만 클라이언트 스크립트를 로드한다.


2. 환경변수

.env와 배포 환경에 아래 값을 설정한다.

TURNSTILE_SITE_KEY=
TURNSTILE_SECRET_KEY=Copy

Laravel 설정은 config/services.phpturnstile 항목에서 읽는다.

  • - site_key: 브라우저에서 Turnstile 위젯을 렌더링할 때 사용
  • - secret_key: 서버에서 Cloudflare siteverify API를 호출할 때 사용


3. 클라이언트 적용 흐름

클라이언트에서는 다음 순서로 처리한다.

1) 파일 링크 버튼 클릭을 가로챈다.
2) 버튼 주변에 Turnstile 위젯 영역을 배치한다.
3) Turnstile을 explicit render 방식으로 렌더링한다.
4) execution: execute 방식으로 사용자가 다운로드를 요청할 때 토큰을 발급받는다.
5) Turnstile action은 file_download로 지정한다.
6) 발급받은 Turnstile 토큰을 백단에 전달한다.
7) 서버가 파일다운로드 작업을 한다.
8) 실패하면 위젯을 reset하고 사용자에게 재시도 안내를 표시한다.

클라이언트 오류는 /file/{uid}/error로 전송해 관리자 로그에서 확인할 수 있게 한다. 광고 차단, 보안 확장 프로그램, 오래된 브라우저 등으로 Turnstile 실행이 막히는 경우를 추적하기 위한 목적이다.


4. 서버 검증 흐름

POST /file/{uid}/token 요청에서 서버는 다음 항목을 확인한다.

1) 올바른  요청인지 확인한다.
2) Origin 또는 Referer가 현재 사이트 호스트와 일치하는지 확인한다.
3) Turnstile secret key가 설정되어 있는지 확인한다.
4) 클라이언트가 보낸 Turnstile 토큰이 비어 있지 않고 허용 길이를 넘지 않는지 확인한다.
5) Cloudflare siteverify API에 요청을 보내 검증한다.
6) 응답 값이 내 사이트의 정보와 일치하는지 검증한다.

검증이 통과하면 서버는 짧은 TTL의 1회용 다운로드 토큰을 캐시에 저장하고, /file/{uid}/download 형태의 URL을 반환한다.


5. 실패 처리와 상태 코드

차단 사유는 로그에 남기고, 사용자에게는 일반화된 오류 메시지를 반환한다.

  • - 직접 접근, 컨텍스트 불일치, 토큰 누락, action/hostname mismatch 등 명확한 비정상 접근은 418로 분류한다.
  • - Cloudflare 검증 실패나 검증 요청 실패 등은 403으로 분류한다.
  • - 클라이언트 Turnstile 오류 로그 수집 요청은 정상 수집 시 200을 반환한다.

로그에는 원인 코드, 파일 링크 UID, 요청 출처, User-Agent, 세션 정보 등을 남겨 관리자 화면에서 집계할 수 있게 한다.


content_image코드 깎기

뭐 시행착오는 많았지만 이렇게 적용한 이후 무차별 공격도 많이 억제되었고 이제야 서버가 좀 고요해진 느낌이다.
확실히 대형 클라우드 업체의 기능이라 그런지 성능값은 톡톡히 하는게 아닐까...
역시 성능은 훌륭하다.

내 사이트에서 적용하는 과정이 키 등록이니 검증이니 좀 복잡한게 있었지만, 코덱스형과 함께하니 할만했다!


지금 파일 다운로드말고 코멘트쪽도 이걸 적용할까 고민하고있긴한데,
코멘트는 안그래도 남기기 귀찮은데 캡차까지하려면 나도 안할거 같으므로 오픈상태로 놔두려한다.

흠흠...
#JavaScript #Cloudflare
0 개의 댓글
×