[시큐어코딩 가이드] 반복된 인증시도 제한 기능 부재
- 정보보안/시큐어코딩 가이드
- 2022. 8. 12.
■ 보안기능
보안기능(인증, 접근제어, 기밀성, 암호화, 권한관리 등)을 부적절하게 구현 시 발생할 수 있는 보안약점으로 적절한 인증 없는 중요기능 허용, 부적절한 인가 등이 포함된다.
반복된 인증시도 제한 기능 부재
■ 개요
일정 시간 내에 여러 번의 인증을 시도하여도 계정 잠금 또는 추가 인증 방법 등의 충분한 조치가 수행되지 않는 경우, 공격자는 성공할법한 ID와 비밀번호들을 사전(Dictionary)으로 만들고 무차별 대입 (brute-force)하여 로그인 성공 및 권한 획득이 가능하다.
Django는 사용자 인증 요청 횟수에 대해 제어하지 않는다. 인증 시스템에 대한 무차별 대입 공격으로부터 보호하기 위해 Django 플러그인(django-defender) 또는 웹 서버 모듈을 사용하여 요청을 제한할 수도 있다.
■ 안전한 코딩 기법
인증시도 횟수를 적절한 횟수로 제한하고 설정된 인증실패 횟수를 초과했을 경우 계정을 잠금 하거나 추가적인 인증과정을 거쳐서 시스템에 접근이 가능하도록 한다. 코드 상에서 인증시도 횟수를 제한하는 방법 외에 CAPTCHA나 Two-Factor 인증방법도 설계 시부터 고려해야 한다.
코드예제
다음 예제는 사용자 로그인 시도에 대한 횟수를 제한하지 않는 코드이다.
안전하지 않은 코드의 예 |
import hashlib from django.shortcuts import render def login(request): user_id = request.POST.get('user_id', '') user_pw = request.POST.get('user_pw', '') sha = hashlib.sha256() sha.update(user_pw) hashed_passwd = get_user_pw(user_id) # 인증시도에 따른 제한이 없어 반복적인 인증 시도가 가능 if sha.hexdigest() == hashed_passwd: return render(request, '/index.html', {'state':'login_success'}) else: return render(request, '/login.html', {'state':'login_failed'}) |
다음은 사용자 로그인 시도에 대한 횟수를 제한하여 무차별 공격에 대응하는 코드이다.
안전한 코드의 예 |
import hashlib from django.shortcuts import render LOGIN_TRY_LIMIT = 5 def login(request): user_id = request.POST.get('user_id', '') user_pw = request.POST.get('user_pw', '') # 로그인 실패기록 가져오기 login_fail = models.LoginFail.objects.filter(user_id) # 로그인 실패횟수 초과로 인해 잠금된 계정에 대한 인증 시도 제한 if login_fail.count() >= LOGIN_TRY_LIMIT: return render(request, '/account_lock.html', {'state':'account_lock'}) else: sha = hashlib.sha256() sha.update(user_pw) hashed_passwd = get_user_pw(user_id) if sha.hexdigest() == hashed_passwd: models.LoginFail.objects.filter(user_id).delete() return render(request, '/index.html', {'state':'login_success'}) else: # 로그인 실패횟수 DB 기록 models.LoginFail.objects.create(user_id) return render(request, '/login.html', {'state':'login_failed'}) |