diff --git a/accounts/migrations/0010_smsauthenticate_sms_count.py b/accounts/migrations/0010_smsauthenticate_sms_count.py new file mode 100644 index 0000000..602fa8d --- /dev/null +++ b/accounts/migrations/0010_smsauthenticate_sms_count.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.1 on 2025-05-25 23:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0009_user_is_manager'), + ] + + operations = [ + migrations.AddField( + model_name='smsauthenticate', + name='sms_count', + field=models.IntegerField(default=0, help_text='인증 코드 발송 횟수'), + ), + ] diff --git a/accounts/migrations/0011_rename_sms_count_smsauthenticate_bad_sms_count.py b/accounts/migrations/0011_rename_sms_count_smsauthenticate_bad_sms_count.py new file mode 100644 index 0000000..d453c60 --- /dev/null +++ b/accounts/migrations/0011_rename_sms_count_smsauthenticate_bad_sms_count.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.1 on 2025-05-26 00:10 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0010_smsauthenticate_sms_count'), + ] + + operations = [ + migrations.RenameField( + model_name='smsauthenticate', + old_name='sms_count', + new_name='bad_sms_count', + ), + ] diff --git a/accounts/models.py b/accounts/models.py index a934db4..d98f252 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -59,7 +59,7 @@ class SMSAuthenticate(models.Model): user_phone = models.CharField(max_length=20, help_text="인증 받을 전화번호") sms_code = models.TextField(help_text="문자인증 코드") created_at = models.DateTimeField(auto_now_add=True, help_text="인증 코드 발송 시각") - + bad_sms_count = models.IntegerField(default=0, help_text="인증 코드 발송 횟수") def __str__(self): return f"{self.user_phone} - {self.sms_code}" diff --git a/accounts/views.py b/accounts/views.py index 456ce1c..6b8c136 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -317,6 +317,25 @@ def send_sms(self, request): "code": 429, "data": [{"detail": "인증 코드는 3분에 한 번만 요청할 수 있습니다."}] }, status=status.HTTP_429_TOO_MANY_REQUESTS) + + # 과도한 요청 방지 로직 + # 마지막 인증 시각과 현재 시각의 차이를 계산 + # 만약 마지막 인증 시각이 3분 이내라면 bad_sms_count 증가 + # 만약 bad_sms_count가 10 이상이면 차단 처리 + now = timezone.now() + delta = (now - last.created_at).total_seconds() + if 3*60 < delta <= 3*60 + 5: + last.bad_sms_count += 1 + last.save() + + if last.bad_sms_count >= 10: + return Response({ + "status": "error", + "message": "차단되었습니다", + "code": 429, + "data": [{"detail": "과도한 요청으로 인해 차단되었습니다."}] + }, status=status.HTTP_429_TOO_MANY_REQUESTS) + except SMSAuthenticate.DoesNotExist: pass