NGINX Rate Limiting 기능으로 어뷰징에 대처하자

Alex·2024년 12월 19일
0

Plaything

목록 보기
50/118

NGINX를 사용하면 HTTP Request의 요청량을 조절할 수 있다.

Rate Limiting with NGINX여기에 그 내용이 잘 설명돼 있다.

이 기능을 사용하면 http 리퀘스트의 요청량을 조절할 수 있다. brute‑force password‑guessing attacks(무차별 대입 공격)을 막는데 주로 활용할 수 있다. 실 이용자에 한해서만 http 리퀘스트 요청을 허용함으로써 DDoS attacks도 막을 수 있다.

 limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
 
    # 일반 HTTP API용
            location / {
                limit_req zone=mylimit;
                proxy_pass http://wsbackend;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
            }

limit_req_zone directive는 보통 http block에 정의된다. 여기는 세가지 파라미터가 존재한다.

  • key 제한이 적용될 요청을 정의하는 것이다. $binary_remote_addr이건 클라이언트의 ip 주소를 담고 있다. 즉, 클라이언트 ip마다 rate limit을 계산하고 차단한다는 것이다.

  • Zone은 공유 메모리 영역으로, 각 ip의 상태와 이 ip들이 url에 얼마나 자주 접근했는지를 저장한다.

  • Rate는 리퀘스트 rate의 최대치를 설정한다. 위 설정은 1초에 10번을 허용한다는 뜻이다.(더 정확히는 0.1초마다 1번의 요청을 허용한다는 뜻이다. burst 설정을 안해주면, 100ms 안에 요청이 2번 들어오면 거절된다)

트래픽이 갑자기 늘어나면?

지금 단계에서 고려할만한 이슈는 아니지만 NGINX는 트래픽 급증에 대비할 수 있는 burst 기능을 제공한다.

앞서 말했듯, NGINX는 rate=10r/s 를 설정하면. 0.1초마다 1건의 리퀘스트를 허용한다. 0.1초에 2~3개의 리퀘스트가 들어오면 503을 코드를 반환한다.

이때 추가로 들어온 요청을 buffer에 담아놓고 추후에 처리할 수 있다.
대신 이 방법은 로그인이나 결제같은 경우는 넣지 않고, 다른 api에 경우 추가해주는 게 좋아보인다.

이런식으로 설정해줄 수 있다.
그런데 지금은 이런 burst 설정을 해줄 필요는 없어 보인다.

이외에도 n개까지는 a의 속도로 처리, 그 이후로는 b 속도로 처리하는 기능과 특정 ip를 제외하는 기능들이 있다.

지금 우리 아키텍처에서는 burst같은 설정이 불필요해보인다.
각자 디바이스에서 백엔드 서버로 api 요청을 보내는 구조라서, 초당 10번 이상의 api 요청이 올 일은 거의 없기 때문이다.

rate limiting의 구조는 login이나 결제처럼 어뷰징을 강하게 막아야 하는 경우 초당 1번, 일반적인 api의 경우 초당 10번을 허용하는 느슨한 방식을 활용하기로 했다.

실제로 503 응답이 오는지 테스트해보자

이걸 어떻게 테스트하면 좋을지... 찾아보다가

for i in {1..3}; do
    curl -i -X GET http://localhost:80/api/v1/user/get-profile -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmbmVsMTIzIiwiZXhwIjoxNzM0NjA2OTEzLCJpYXQiOjE3MzQ1ODg5MTN9.knI17HxD7Euy0jKTGwLOnCrl8lEJ8i9ZcjPT0yj5Np0"
    echo "Request $i completed"
done

bash로 이렇게 스크립트를 짜서 요청을 3번 보낸다.(우선 초당 1번만 허용하게 했다)

503에러가 뜨는 걸 확인할 수 있다.

에러 로그에도 잘 잡힌다.
다만, 지금은 503 에러로 가기 때문에 이를 429 응답(TooManyRequest)로 변경해주자.

테스트 해보면 429 코드로 응답된다.

profile
답을 찾기 위해서 노력하는 사람

0개의 댓글