Ubuntu 20.04에서 PHP와 함께 Redis®를 사용하여 Rate Limiter로 사용하기

2024년 7월 5일
조회수 233
코멘트0

목차

소개

Rate limiting은 서버에서 자원 사용을 제한하는 방법입니다. 예를 들어, API (응용 프로그램 프로그래밍 인터페이스)를 실행하는 경우, 특정 시간 내에 사용자가 서버에 요청 할 수있는 횟수를 제한하는 캡을 설정할 수 있습니다. 웹 애플리케이션의 요청 속도를 제어하면 DoS (서비스 거부) 공격의 위험을 줄일 수 있습니다. 이를 통해 애플리케이션에 공정한 사용 정책을 적용할 수 있습니다. 대규모 웹 애플리케이션에서 특정 제약을 초과하지 않도록 작업을 제한하면 대역폭 및 리소스 사용에 대한 큰 비용을 절약할 수 있습니다.

이 가이드에서는 Vultr Ubuntu 20.04 서버에서 PHP를 사용하여 웹 리소스에 대한 요청을 제한하는 데 Redis® 서버를 사용합니다.

사전요구사항

이 가이드를 따르려면 다음 사항이 필요합니다:

  • Ubuntu 20.04 서버
  • sudo 사용자
  • Lamp Stack
  • Redis® 서버

Redis® 확장 설치

Vultr Ubuntu 클라우드 서버에 로그인하고 php-redis 확장을 설치하세요. 이 모듈을 사용하면 PHP 코드에서 Redis® 라이브러리를 사용할 수 있습니다.

 $ sudo apt install -y php-redis

새 구성을 로드하기 위해 Apache 서버를 다시 시작하세요.

 $ sudo systemctl restart apache2

PHP 리소스 생성

서버의 루트 디렉토리에 PHP 리소스를 만드세요.

 $ sudo nano /var/www/html/resource.php

그런 다음 아래 정보를 파일에 추가하세요.

 <?php 
    try {             
            $redis = new Redis(); 
            $redis->connect('127.0.0.1', 6379); 

            $username = $_SERVER['PHP_AUTH_USER']; 
            $password = $_SERVER['PHP_AUTH_PW'];

            $key = $username;

            $allowed_requests_per_period = 3;
            $time_frame_in_seconds       = 10;

            $total_requests = 0;

            if ($redis->exists($key)) {
                $redis->INCR($key);                  
                $total_requests = $redis->get($key);                    

                if ($total_requests > $allowed_requests_per_period) {
                   echo "Hey, " . $username . ", You've already reached your requests limit. Total requests " 
                         . $total_requests . " Allowed requests " . $allowed_requests_per_period;
                   exit();                   
                }                

            } else {               
                $redis->set($key, 1); 
                $redis->expire($key, $time_frame_in_seconds); 
                $total_requests = 1;       
            } 

            echo "ok, total requests " . $total_requests;            

        } catch (Exception $e) {
            echo $e->getMessage();
        }
?>

파일 편집을 마치면 Ctrl + X, Y를 누르고 Enter를 눌러 저장하고 닫으세요.

/var/www/html/resource.php 코드 설명:

$redis = new Redis(); 
$redis->connect('127.0.0.1', 6379); 

위의 코드를 사용하여 로컬호스트의 포트 6379를 통해 Redis® 서버에 연결합니다.

$username = $_SERVER['PHP_AUTH_USER']; 
$password = $_SERVER['PHP_AUTH_PW'];

PHP를 Apache 모듈로 실행하도록 구성한 경우, $_SERVER['PHP_AUTH_USER']$_SERVER['PHP_AUTH_PW'] 변수는 HTTP 기본 인증 자격 증명을 각각 $username$password 변수에 할당합니다.

$key = $username;

웹 리소스에 액세스하는 여러 사용자가 있을 수 있으므로 $_SERVER['PHP_AUTH_USER'] 변수에서 검색한 $username 변수로 Redis® 키를 생성하여 각 사용자의 트래픽을 독립적으로 추적할 수 있습니다.

$allowed_requests_per_period = 3;
$time_frame_in_seconds       = 10;

위의 두 변수는 애플리케이션의 설정 사용 정책에 따라 웹 리소스 요청을 제한할 수 있게합니다. 이 예제에서는 사용자를 10초 동안 3회로 제한합니다. 필요에 따라 이 값을 조정하세요.

$total_requests = 0;

$total_requests 변수를 사용하여 사용자가 요청한 총 횟수를 초기화합니다.

if ($redis->exists($key)) {
     $redis->INCR($key);                  
     $total_requests = $redis->get($key);                    

     if ($total_requests > $allowed_requests_per_period) {
         echo "You've already reached your requests limit. Total requests " 
         . $total_requests . " Allowed requests " . $allowed_requests_per_period;
         exit();                   
     }                

 } else {               
     $redis->set($key, 1); 
     $redis->expire($key, $time_frame_in_seconds); 
     $total_requests = 1;       
 }

위의 코드는 Redis® 서버에서 $key 변수의 존재 여부를 확인합니다. 키가 존재하는 경우 $redis->INCR($key) 명령을 사용하여 1을 증가시킵니다. 키가 존재하지 않는 경우 $key 값을 1로 설정하고 $time_frame_in_seconds 변수로 정의된 만료 기간으로 새 키를 설정합니다. 그런 다음 $redis->get($key)를 사용하여 $key 키의 현재 수를 가져옵니다. 값을 가져온 후, $total_requests 변수에 할당합니다.

다음으로 PHP의 if...else 구문을 사용하여 클라이언트가 정의된 기간 동안 허용된 총 요청을 초과하는지 평가합니다. 제한을 초과하면 사용자에게 오류를 반환합니다.

echo "ok, total requests " . $total_requests;

파일 아래쪽에는 사용자가 제한을 초과하지 않은 경우 사용자가 한 요청의 수를 출력합니다.

Redis® Rate Limiter 테스트

서버의 명령 프롬프트를 열고, curl 명령을 사용하여 위에서 생성한 /var/www/html/resource.php 웹 리소스를 조회합니다. 'http://localhost/resource.php?[1-20]'의 더미 쿼리 문자열은 스크립트가 Redis® 서버에 의해 제한되는지 확인하기 위해 리소스에 20번 액세스할 수 있도록 합니다.

$ curl --user john:SAMPLE_PASSWORD 
  -H "Accept: text/plain" 
  -H "Content-Type: text/plain" 
  -X GET http://localhost/resource.php?[1-20]

위 코드를 실행한후, 아래 출력을 받을 수 있어야 합니다.

[1/20]: http://localhost/resource.php?1 --> stdout
--_curl_--http://localhost/resource.php?1
    ok, total requests 1
[2/20]: http://localhost/resource.php?2 --> stdout
--_curl_--http://localhost/resource.php?2
    ok, total requests 2
[3/20]: http://localhost/resource.php?3 --> stdout
--_curl_--http://localhost/resource.php?3
    ok, total requests 3
[4/20]: http://localhost/resource.php?4 --> stdout
--_curl_--http://localhost/resource.php?4
    Hey, john, You've already reached your requests limit. Total requests 4 Allowed requests 3
[5/20]: http://localhost/resource.php?5 --> stdout
--_curl_--http://localhost/resource.php?5
    Hey, john, You've already reached your requests limit. Total requests 5 Allowed requests 3
[6/20]: http://localhost/resource.php?6 --> stdout
...

첫 세 개의 요청이 수락되는 것을 확인할 수 있습니다. 그러나 네 번째 요청부터 PHP 스크립트가 비율 제한 오류를 발생시키기 시작했습니다.

결론

이 튜토리얼에서 Redis® 서버를 사용하여 Ubuntu 20.04에서 PHP로 리소스 사용을 제한하는 방법을 알아보았습니다. 이 가이드는 Redis®와 함께 소비자가 리소스를 제한하는 방법의 예시에 불과합니다. 이를 확장하여 웹 애플리케이션의 요구 사항에 맞게 조정 할 수 있습니다.

 

출처: https://docs.vultr.com/use-redis-as-a-rate-limiter-with-php-on-ubuntu-20-04

댓글 0