반응형

로그인 기능은 웹 애플리케이션에서
사용자 인증을 담당하는 중요한 부분입니다.
보안을 강화하지 않으면 사용자의 계정이 탈취되거나
시스템에 무단 접근이 발생할 수 있습니다.
이번 글에서는 안전한 로그인 기능을 구현하기 위해
필수적으로 적용해야 할 보안 설정과
방법을 세세하게 살펴보겠습니다.
 
오늘은 프로그래밍 언어
파이썬(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")

오늘은 안전한 로그인 기능을 위한 보안 설정을 알아봤습니다.
오늘 설정한 내용 아래에서 한번 더 볼까요?

  1. 비밀번호 보호: 비밀번호를 해시 함수와 솔트를 사용하여 안전하게 저장하고, 비밀번호 복잡성 규칙을 설정하여 강력한 비밀번호를 요구합니다.
  2. 로그인 시도 제한: 일정 횟수 이상 잘못된 비밀번호 입력 시 계정을 잠금 처리하고, 봇 공격을 방지하기 위해 캡차(CAPTCHA)를 도입합니다.
  3. CSRF 토큰 사용: CSRF 토큰을 로그인 폼에 포함시켜 CSRF 공격을 방지합니다.
  4. 2단계 인증(2FA): 비밀번호 외에도 SMS, 이메일, 인증 앱을 통한 추가 인증 요소를 요구하여 보안을 강화합니다.
  5. 세션 관리: 세션 타임아웃 설정과 세션 고정 공격 방지 등을 통해 세션을 안전하게 관리합니다.
  6. SSL/TLS를 통한 데이터 암호화: SSL/TLS를 사용하여 전송되는 데이터를 암호화하여 중간자 공격(MITM)을 방지합니다.
  7. 계정 잠금 및 경고: 여러 번 로그인 실패 시 계정을 잠그고, 이메일로 경고 메시지를 발송하며, 새로운 디바이스나 IP 주소에서 로그인 시 알림을 보냅니다.
  8. 입력 데이터 유효성 검사: 모든 사용자 입력 데이터에 대해 유효성 검사를 수행하여 SQL 인젝션, XSS 등의 공격을 방지합니다.
  9. 보안 감사 및 로그: 로그인 시도, 실패, 비밀번호 변경 등의 보안 관련 이벤트를 로깅하고, 의심스러운 활동을 감지하여 대응합니다.

이러한 보안 설정을 통해 로그인 기능의 보안을 강화하고,
사용자 계정 및 시스템을 보다 안전하게 보호할 수 있습니다.
최신 보안 권고사항을 참고하고,
자동화된 보안 도구를 적극 활용하여 시스템의 안전성을 높여주세요
 
보안은 한 번에 완성되는 것이 아니라 지속적으로 관리하고 업데이트해야 하는 부분입니다.
따라서 정기적인 보안 점검과 최신 보안 패치 적용을 통해 안전한 웹 애플리케이션을 유지하시기 바랍니다.
이 글이 안전한 로그인 기능을 구현하는 데 도움이 되었기를 바랍니다.
추가적인 질문이나 도움이 필요하다면 언제든지 댓글로 남겨주세요.
감사합니다!


궁금하신 사항은 댓글에 남겨주세요

댓글에 남겨주신 내용

추후 정리해서 올려드리겠습니다

구독 신청하시면 업로드 시 알려드릴게요!

-

조금이라도 도움이 되셨다면

공감&댓글 부탁드리겠습니다

감사합니다!

반응형
반응형

HTTP
(HyperText Transfer Protocol)

 

HTTP는 HyperText Transfer Protocol의 약자로,

인터넷에서 데이터를 주고받을 수 있는 프로토콜입니다.

웹 서버와 클라이언트(웹 브라우저) 간에 통신을 가능하게 합니다.

웹브라우저를 사용하거나 개발할 때 클라이언트와 서버가 정보를 교환하는

가장 기본적인 프로토콜입니다.

HTTP (HyperText Transfer Protocol)는 웹 상에서 정보를 주고받을 때 사용하는 규칙인데,
'무상태(Stateless) 프로토콜'이라고 불립니다.
이 말은 HTTP를 사용할 때, 웹 서버가 사용자의 이전 활동이나 상태를 기억하지 않는다는 것을 의미합니다.
간단히 말해서, 서버는 각 요청을 완전히 새로운 것으로 처리하고, 이전 요청과의 연결을 유지하지 않습니다.

하지만, 웹사이트가 사용자의 정보나 선호도를 기억하는 것이 필요할 때가 있습니다. 
예를 들어, 온라인 쇼핑을 하면서 장바구니에 상품을 담거나, 로그인을 유지하는 경우 등이 이에 해당합니다. 
이런 경우, HTTP '쿠키(Cookies)' '세션(Sessions)'이라는 방법을 사용합니다. 
쿠키는 사용자의 컴퓨터에 작은 정보를 저장하는 것이고, 세션은 서버 측에서 사용자의 정보를 일정 시간 동안 유지하는 방법입니다. 
이를 통해 웹사이트는 사용자의 정보를 일시적으로 기억하고,  개인화된 사용자 경험을 제공할  있게 됩니다.

 

HTTPS
(HyperText Transfer Protocol Secure)

 

HTTPS는 HyperText Transfer Protocol Secure의 약자로,

HTTP에 데이터 암호화 기능을 추가한 보안 프로토콜입니다.

쉽게 말해,

SSL을 사용하는 HTTP 프로토콜의 보안 버전입니다.

HTTPS 프로토콜을 사용하면 웹 사이트 사용자가 인터넷을 통해 신용 카드 번호,

은행 정보 및 로그인 자격 증명과 같은 중요한 데이터를 안전하게 전송 있습니다.


HTTP와 HTTPS의 주요 차이점

1. HTTPS는 SSL/TLS를 통해 전송되는 데이터를 암호화하여 보안을 강화하는 반면, HTTP는 이러한 보안 조치가 없습니다.

2. 일반적으로 HTTP는 80번 포트를 사용하고, HTTPS는 443번 포트를 사용합니다.

3. 초기에는 HTTPS가 HTTP보다 느리다고 여겨졌으나, 현대의 기술 발전으로 이러한 차이는 크게 줄어들었습니다.

4. HTTPS는 웹사이트의 신뢰성을 높여주며, 많은 브라우저에서는 HTTPS를 사용하지 않는 사이트에 대해 경고를 표시합니다.

궁금하신 사항은 댓글에 남겨주세요

댓글에 남겨주신 내용

추후 정리해서 올려드리겠습니다

이웃 신청하시면 업로드 시 알려드릴게요!

-

조금이라도 도움이 되셨다면

공감&댓글 부탁드리겠습니다

감사합니다!

반응형

+ Recent posts