로그인 기능은 웹 애플리케이션에서
사용자 인증을 담당하는 중요한 부분입니다.
보안을 강화하지 않으면 사용자의 계정이 탈취되거나
시스템에 무단 접근이 발생할 수 있습니다.
이번 글에서는 안전한 로그인 기능을 구현하기 위해
필수적으로 적용해야 할 보안 설정과
방법을 세세하게 살펴보겠습니다.
오늘은 프로그래밍 언어
파이썬(python)을 사용하겠습니다.
1. 비밀번호 보호
1.1 비밀번호 해싱 및 솔팅
비밀번호를 안전하게 저장하기 위해
해싱과 솔팅 기법을 사용합니다.
- 해싱: 비밀번호를 해시 함수(bcrypt, Argon2 등)를 사용하여 해시된 값으로 변환합니다. 해시는 단방향 함수이므로 원본 비밀번호를 추출할 수 없습니다.
- 솔팅: 각 비밀번호에 무작위 솔트 값을 추가하여 해시합니다. 동일한 비밀번호라도 솔트가 다르면 해시 값이 달라져서 무차별 대입 공격을 방지할 수 있습니다.
# bcrypt 설치
# pip install bcrypt
import bcrypt
def hash_password(password):
salt = bcrypt.gensalt()
hashed_password = bcrypt.hashpw(password.encode('utf-8'), salt)
return hashed_password
def check_password(hashed_password, user_password):
return bcrypt.checkpw(user_password.encode('utf-8'), hashed_password)
1.2 비밀번호 복잡성 규칙
강력한 비밀번호를 설정하도록 유도합니다.
최소 길이, 대문자, 소문자, 숫자, 특수문자를
포함하는 규칙을 설정합니다.
- 예시: 최소 8자 이상, 대문자 1자, 소문자 1자, 숫자 1자, 특수문자 1자 포함
import re
def is_password_strong(password):
if (len(password) < 8 or
not re.search(r"[A-Z]", password) or
not re.search(r"[a-z]", password) or
not re.search(r"\d", password) or
not re.search(r"[!@#$%^&*(),.?\":{}|<>]", password)):
return False
return True
password = "Example1!"
if is_password_strong(password):
print("Password is strong.")
else:
print("Password is weak.")
2. 로그인 시도 제한
2.1 로그인 시도 제한
사용자가 일정 횟수 이상 잘못된 비밀번호를 입력하면
계정을 일시적으로 잠금 처리합니다.
- 예시: 5회 실패 시 15분 동안 계정을 잠금
from datetime import datetime, timedelta
login_attempts = {}
def record_login_attempt(username, success):
if username not in login_attempts:
login_attempts[username] = {'attempts': 0, 'last_attempt': None, 'lock_until': None}
# 계정이 잠겨있는지 확인
if login_attempts[username]['lock_until'] and datetime.now() < login_attempts[username]['lock_until']:
return "Account is locked. Try again later."
# 로그인 성공 시 시도 횟수 초기화
if success:
login_attempts[username]['attempts'] = 0
else:
login_attempts[username]['attempts'] += 1
login_attempts[username]['last_attempt'] = datetime.now()
# 5회 실패 시 계정 잠금
if login_attempts[username]['attempts'] >= 5:
login_attempts[username]['lock_until'] = datetime.now() + timedelta(minutes=15)
return "Account is locked due to too many failed attempts."
return "Login attempt recorded."
2.2 캡차(CAPTCHA)
여러 번 로그인 실패 후 캡차를 요구하여 봇에 의한
자동화된 공격을 방지합니다.
캡차는 reCAPTCHA 등 서비스를 이용할 수 있습니다.
<form action="/login" method="post">
<!-- Other login fields -->
<div class="g-recaptcha" data-sitekey="your_site_key"></div>
<button type="submit">Login</button>
</form>
<script src="https://www.google.com/recaptcha/api.js"></script>
3. CSRF(Cross-Site Request Forgery) 토큰
3.1 CSRF 토큰 사용
로그인 폼에 CSRF 토큰을 포함하여,
서버가 해당 요청이 신뢰할 수 있는 출처에서 왔는지
확인합니다.
이를 통해 CSRF 공격을 방지할 수 있습니다.
from flask import Flask, request, session, render_template_string
import os
app = Flask(__name__)
app.secret_key = os.urandom(24)
def generate_csrf_token():
if 'csrf_token' not in session:
session['csrf_token'] = os.urandom(24).hex()
return session['csrf_token']
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
token = request.form.get('csrf_token')
if not token or token != session['csrf_token']:
return "CSRF token mismatch", 400
# Process login
return render_template_string("""
<form method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<!-- Other login fields -->
<button type="submit">Login</button>
</form>
""", csrf_token=generate_csrf_token())
4. 2단계 인증(Two-Factor Authentication, 2FA)
4.1 2단계 인증 도입
비밀번호 외에도 추가 인증 요소를 요구합니다.
예를 들어, SMS, 이메일로 전송된 인증 코드,
인증 앱(Google Authenticator 등)을 사용한 코드를 입력하도록 요구할 수 있습니다.
import random
def send_otp_via_sms(phone_number):
otp = random.randint(100000, 999999)
# Code to send SMS
return otp
def verify_otp(user_input, actual_otp):
return user_input == actual_otp
# 예시 사용법
otp = send_otp_via_sms("+1234567890")
user_input = input("Enter the OTP sent to your phone: ")
if verify_otp(user_input, otp):
print("OTP verified successfully.")
else:
print("Invalid OTP.")
5. 세션 관리
5.1 세션 타임아웃
일정 시간 동안 사용자의 활동이 없으면
자동으로 로그아웃 시킵니다.
from flask import Flask, session
from datetime import timedelta
app = Flask(__name__)
app.secret_key = os.urandom(24)
@app.before_request
def make_session_permanent():
session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=30)
5.2 세션 고정 공격 방지
로그인 시 새로운 세션 ID를 할당하여 세션 고정 공격을 방지합니다.
from flask import Flask, session
app = Flask(__name__)
app.secret_key = os.urandom(24)
@app.route('/login', methods=['POST'])
def login():
# Authenticate user
user = authenticate_user() # 가정한 함수
if user:
session.clear()
session['user_id'] = user.id
return "Login successful"
return "Invalid credentials"
6. SSL/TLS를 통한 데이터 암호화
6.1 SSL/TLS 사용
로그인 페이지 및 API 통신에 SSL/TLS를 사용하여 전송되는 데이터를 암호화합니다.
이를 통해 중간자 공격(MITM)을 방지할 수 있습니다.
- SSL 인증서를 설치하고 HTTPS를 적용합니다.
server {
listen 443 ssl;
server_name your_domain.com;
ssl_certificate /path/to/your_certificate.crt;
ssl_certificate_key /path/to/your_private.key;
location / {
proxy_pass http://localhost:5000;
# Other configurations
}
}
7. 계정 잠금 및 경고
7.1 계정 잠금
여러 번 로그인 실패 시 계정을 잠그고,
사용자가 등록한 이메일로 경고 메시지를 보냅니다.
def send_account_lock_email(user_email):
# Code to send email
pass
def lock_account(username):
# Lock account logic
send_account_lock_email(username)
7.2 로그인 알림
새로운 디바이스나 IP 주소에서 로그인 시 사용자가 알림을 받도록 설정할 수 있습니다.
def send_new_login_alert(user_email, ip_address):
# Code to send email alert
pass
8. 입력 데이터 유효성 검사
8.1 입력 데이터 검증
모든 사용자 입력 데이터에 대해 유효성 검사를 수행하여 SQL 인젝션, XSS 등의 공격을 방지합니다.
from flask import escape
@app.route('/login', methods=['POST'])
def login():
username = escape(request.form.get('username'))
password = escape(request.form.get('password'))
# Process login
9. 보안 감사 및 로그
9.1 보안 로그
로그인 시도, 실패, 비밀번호 변경 등의 보안 관련 이벤트를 로깅하여 나중에 분석할 수 있도록 합니다.
import logging
logging.basicConfig(filename='security.log', level=logging.INFO)
def log_security_event(event):
logging.info(event)
# 예시 사용법
log_security_event("User login attempt")
9.2 감사 로그
의심스러운 활동을 감지하고 대응할 수 있도록 보안 감사 로그를 유지합니다.
def log_suspicious_activity(user_id, activity):
logging.warning(f"Suspicious activity detected for user {user_id}: {activity}")
# 예시 사용법
log_suspicious_activity(123, "Multiple failed login attempts")
오늘은 안전한 로그인 기능을 위한 보안 설정을 알아봤습니다.
오늘 설정한 내용 아래에서 한번 더 볼까요?
- 비밀번호 보호: 비밀번호를 해시 함수와 솔트를 사용하여 안전하게 저장하고, 비밀번호 복잡성 규칙을 설정하여 강력한 비밀번호를 요구합니다.
- 로그인 시도 제한: 일정 횟수 이상 잘못된 비밀번호 입력 시 계정을 잠금 처리하고, 봇 공격을 방지하기 위해 캡차(CAPTCHA)를 도입합니다.
- CSRF 토큰 사용: CSRF 토큰을 로그인 폼에 포함시켜 CSRF 공격을 방지합니다.
- 2단계 인증(2FA): 비밀번호 외에도 SMS, 이메일, 인증 앱을 통한 추가 인증 요소를 요구하여 보안을 강화합니다.
- 세션 관리: 세션 타임아웃 설정과 세션 고정 공격 방지 등을 통해 세션을 안전하게 관리합니다.
- SSL/TLS를 통한 데이터 암호화: SSL/TLS를 사용하여 전송되는 데이터를 암호화하여 중간자 공격(MITM)을 방지합니다.
- 계정 잠금 및 경고: 여러 번 로그인 실패 시 계정을 잠그고, 이메일로 경고 메시지를 발송하며, 새로운 디바이스나 IP 주소에서 로그인 시 알림을 보냅니다.
- 입력 데이터 유효성 검사: 모든 사용자 입력 데이터에 대해 유효성 검사를 수행하여 SQL 인젝션, XSS 등의 공격을 방지합니다.
- 보안 감사 및 로그: 로그인 시도, 실패, 비밀번호 변경 등의 보안 관련 이벤트를 로깅하고, 의심스러운 활동을 감지하여 대응합니다.
|
이러한 보안 설정을 통해 로그인 기능의 보안을 강화하고,
사용자 계정 및 시스템을 보다 안전하게 보호할 수 있습니다.
최신 보안 권고사항을 참고하고,
자동화된 보안 도구를 적극 활용하여 시스템의 안전성을 높여주세요
보안은 한 번에 완성되는 것이 아니라 지속적으로 관리하고 업데이트해야 하는 부분입니다.
따라서 정기적인 보안 점검과 최신 보안 패치 적용을 통해 안전한 웹 애플리케이션을 유지하시기 바랍니다.
이 글이 안전한 로그인 기능을 구현하는 데 도움이 되었기를 바랍니다.
추가적인 질문이나 도움이 필요하다면 언제든지 댓글로 남겨주세요.
감사합니다!
궁금하신 사항은 댓글에 남겨주세요
댓글에 남겨주신 내용은
추후 정리해서 올려드리겠습니다
구독 신청하시면 업로드 시 알려드릴게요!
-
조금이라도 도움이 되셨다면
공감&댓글 부탁드리겠습니다
감사합니다!