본문 바로가기
개념 노트장

[Flask] session 구조

by jwcs 2024. 4. 11.
728x90

https://dreamhack.io/wargame/challenges/566

 

Login Page

Python으로 작성된 로그인 페이지입니다. admin으로 로그인하여 플래그를 획득하세요. 플래그 형식은 DH{...}입니다.

dreamhack.io

이 문제를 풀며, flask에서 제공하는 session 구조에 대해 정리해보겠다.

 

from flask import Flask, request, redirect, url_for, render_template, session
import os
app = Flask(__name__)
app.secret_key = 'your_secret_key_here'

# 간단한 사용자 데이터베이스를 대신할 딕셔너리
users = {'user1': 'password1', 'admin': 'admin'}

@app.route('/')
def home():
    if not session.get('logged_in'):
        return redirect(url_for('login'))
    else:
        return '로그인 성공! 홈페이지 내용'

@app.route('/login', methods=['GET', 'POST'])
def login():
    # 로그인 시도 카운트를 세션에서 가져오거나 초기값 설정
    session['login_attempts'] = session.get('login_attempts', 0) + 1
    session['id'] = os.urandom(16)
    print(session['id'])
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        if username in users and users[username] == password:
            session['logged_in'] = True
            session['login_attempts'] = 0  # 로그인 성공시 시도 횟수 초기화
            return redirect(url_for('home'))
        else:
            return render_template('login.html', message='로그인 실패! 다시 시도하세요.', attempts=session['login_attempts'])
    
    # GET 요청시 로그인 폼 렌더링, 실패 횟수도 함께 전달
    return render_template('login.html', attempts=session['login_attempts'])

if __name__ == '__main__':
    app.run(debug=True)

app.py

 

<!DOCTYPE html>
<html>
<head>
    <title>로그인 페이지</title>
</head>
<body>
    <h2>로그인</h2>
    {% if message %}
    <p>{{ message }}</p>
    {% endif %}
    <p>로그인 시도 횟수: {{ attempts }}</p>
    <form method="post">
        사용자 이름: <input type="text" name="username"><br>
        비밀번호: <input type="password" name="password"><br>
        <input type="submit" value="로그인">
    </form>
</body>
</html>

templates/login.html

 

간단하게 실습해볼 수 있는 코드다.

session

접속하면 볼 수 있는 session의 값이다. 자세히 보면 두 개의 `.`으로 구분되어 있다. 마치 jwt와 같이 말이다.

디코딩

실제로 base64로 인코딩 되어 있는 구조라서 jwt 디코딩 사이트에서 디코딩이 가능하다.

 

각각 데이터 부분, 타임 스탬프 부분, 서명 부분으로 나눌 수 있다. 서명 부분은 세션이 수정되지 않았다는 것을 증명하기위해 쓰이며, ` itsdangerous `라이브러리와 서버에서 설정한 secret 키를 이용해 직렬화와 서명을 수행한다.

 

여기서 id 부분에 객체로 값이 들어가는 것을 볼 수 있는데, `session['id'] = os.urandom(16)`의 결과로 보인다. 한 번 실행해서 확인해보자.

 

실행 결과

바이너리 들어가면서 위와 같이 형태가 변형된 것으로 보인다. 자세한 내용은 더 찾아봐야 할 것 같다.

 

 

flask-session은 flask에서 제공하는 session을 커스터마이징할 수 있는 기능을 제공한다고 한다.

flask session architecture

 

728x90
반응형