django-axes 도입 후 테스트 문제
Source: Dev.to
배경
django-axes란?
django-axes는 로그인 시도를 모니터링하고 인증 설정에 따라 사용자를 차단하는 Django 패키지입니다. 무차별 대입 공격을 방지하는 데 도움이 됩니다.
왜 django-axes를 사용했는가
협업 프로젝트에서 로그인 기능이 있는 작은 앱을 개발하고 있었습니다. 무차별 대입 공격을 방지하기 위해 로그인 시도 횟수를 제한하고자 django-axes를 도입하기로 했습니다.
문제
django-axes를 적용한 뒤 모든 테스트를 실행했습니다. 이전에 통과하던 많은 테스트가 실패하기 시작했습니다. 실패 원인은 모두 로그인 기능과 관련이 있었으며, 테스트에 요청 객체가 포함되지 않았기 때문입니다.
테스트에서 client.login을 사용할 경우(아래 예시), 사용자는 HTTP 요청 없이 인증됩니다. 하지만 django-axes는 요청을 검사하여 사용자가 인증되었는지 판단하므로 실패가 발생합니다.
실패 패턴 (client.login 사용)
self.user = User.objects.create_user(
username="login_user",
email="login@example.com",
password="LoginPass123",
)
self.client.login(email="login@example.com", password="LoginPass123")
정상 패턴 (client.post 사용)
self.user = User.objects.create_user(
username="login_user",
email="login@example.com",
password="LoginPass123",
)
self.client.post(
self.login_url,
{"email": "login@example.com", "password": "LoginPass123"},
REMOTE_ADDR="192.168.1.1",
)
해결 방법
두 가지 실용적인 방법을 찾았습니다.
1. 테스트에서 django-axes 비활성화
테스트 설정에 AXES_ENABLE = False 를 지정하면 테스트 중에 django-axes 검사를 비활성화할 수 있습니다.
django-axes와 관련된 기능을 테스트해야 할 경우 AXES_ENABLE = True 로 다시 활성화하면 됩니다.
이 방법을 사용하면 실제로 django-axes가 필요한 테스트에만 동작을 제한할 수 있습니다.
2. force_login() 사용
force_login()은 django-axes가 훅을 건 인증 과정을 우회합니다. 로그인 검증과 직접적인 관련이 없는 테스트에서는 client.login() 대신 force_login()을 사용하는 것이 합리적입니다.
정상 패턴 (force_login 사용)
self.user = User.objects.create_user(
username="login_user",
email="login@example.com",
password="LoginPass123",
)
self.client.force_login(self.user)
앞서 언급했듯이 client.post() 역시 요청을 포함하므로 정상적으로 동작합니다.
결론
django-axes는 애플리케이션 보안을 강화하는 매우 유용한 패키지입니다. 그러나 이를 도입할 때는 테스트에서 인증이 어떻게 처리되는지에 주의해야 합니다. 앱 구조와 테스트 전략에 따라 가장 적합한 해결책을 선택하세요—테스트에서 django-axes를 비활성화하거나, force_login()/client.post()를 사용해 인증하는 방법 중 하나를 선택하면 됩니다.
비슷한 문제를 겪고 있는 분들에게 도움이 되길 바랍니다.