2024.10.27 - [모의해킹/모의해킹 스터디] - 모의해킹 스터디 2주차 과제(1) - 회원가입
에 이어서 로그인 기능을 개발한 것에 대하여 정리해 보겠다.
개발
우선 해당 코드는 중복으로 사용되어서 한 파일로 묶고 require_once를 사용하여 각 파일에 불러올것이다.
<?php
session_start(); // 세션 시작
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
if (isset($_SESSION['error_message'])) {
echo '<div class="alert alert-danger">' . htmlspecialchars($_SESSION['error_message']) . '</div>';
unset($_SESSION['error_message']);
}
?>
2024.10.21 - [모의해킹/모의해킹 스터디] - 모의해킹 스터디 1주차 과제
해당 게시물에서 작성한 코드에서 로그인 뼈대를 수정하여 작성했다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>로그인 페이지</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<style>
.text-center {
margin-bottom: 30px;
}
.form-group {
margin-bottom: 10px;
}
.form-group .form-control {
height: 45px;
}
.submit-btn {
width: 100%;
background-color: #70a2ee;
border-color: #c2d7f7;
}
</style>
</head>
<body class="bg-light">
<?php include 'header.php'; ?> <!-- 헤더 포함 -->
<main class="container">
<div class="row justify-content-center" style="height: 100vh;">
<div class="col-md-4 my-auto">
<h2 class="text-center">로그인</h2>
<?php
require_once 'csrf_error_message.php';// csrf, 에러 메시지
?>
<form method="post" action="login_proc.php">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
<div class="form-group">
<input type="text" class="form-control" name="email" placeholder="이메일" autocomplete="off">
</div>
<div class="form-group">
<input type="password" class="form-control" name="password" placeholder="비밀번호" autocomplete="current-password">
</div>
<button type="submit" class="submit-btn btn btn-primary btn-block">로그인</button>
</form>
</div>
</div>
</main>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
그 다음 로그인 로직을 작성하였다.
<?php
require_once 'db_session_info.php';// 데이터베이스 연결
// CSRF 토큰 검증
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
$_SESSION['error_message'] = "CSRF 토큰이 유효하지 않습니다.";
header("Location: login.php");
exit();
}
// POST 데이터 가져오기 및 검증
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$_SESSION['error_message'] = "유효한 이메일 주소를 입력하세요.";
header("Location: login.php");
exit();
}
$password = $_POST['password'];
if (empty($password)) {
$_SESSION['error_message'] = "비밀번호를 입력하세요.";
header("Location: login.php");
exit();
}
// 쿼리 실행
$sql = "SELECT l.id, l.password, u.nickname
FROM login l
JOIN user u ON l.user_id = u.id
WHERE l.email = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $email);
if ($stmt->execute()) {
$result = $stmt->get_result();
} else {
$_SESSION['error_message'] = "데이터베이스 오류 발생.";
header("Location: login.php");
exit();
}
if ($result->num_rows > 0) {
$user = $result->fetch_assoc();
if (password_verify($password, $user['password'])) {
session_regenerate_id(true); // 세션 ID 변경
$_SESSION['user_id'] = $user['id'];
$_SESSION['nickname'] = $user['nickname'];
header("Location: index.php");
exit();
} else {
$_SESSION['error_message'] = "이메일 또는 비밀번호가 잘못되었습니다.";
header("Location: login.php");
exit();
}
} else {
$_SESSION['error_message'] = "이메일 또는 비밀번호가 잘못되었습니다.";
header("Location: login.php");
exit();
}
// 연결 종료
$stmt->close();
$conn->close();
?>
로그인 성공 시 이동해야하는 index.php를 만들었다.
<?php
session_start(); // 세션 시작
if (!isset($_SESSION['user_id'])) {
// 사용자가 로그인하지 않은 경우 login.php로 리다이렉션
header("Location: login.php");
exit();
}
$nickname = $_SESSION['nickname']; // 사용자 닉네임
?>
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, 그리고 Bootstrap 기여자들">
<meta name="generator" content="Hugo 0.88.1">
<title>환영합니다.</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<meta name="theme-color" content="#7952b3">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
</head>
<body>
<?php include 'header.php'; ?> <!-- 헤더 포함 -->
<main class="container">
<div class="bg-light p-5 rounded">
<h1>안녕하세요!</h1>
<p><?php echo htmlspecialchars($nickname); ?>님 어서오세요!</p>
</div>
</main>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
마지막으로 로그아웃 로직을 만들었다.
<?php
session_start();
session_unset(); // 세션 배열 비우기
session_destroy(); // 세션 종료
header("Location: login.php"); // 로그인 페이지로 리다이렉션
exit();
?>
결과
- 이메일(@)을 작성 안할 시
- 이메일, 비밀번호 틀릴 시
- 로그인 성공(메인 페이지)
후기
로그인 뼈대는 이미 갖춰있던 상태였고 회원가입 기능을 개발하고 나서 로그인 기능을 개발하니 회원가입 기능을 개발할 때보다 쉽게 해결하였다. 보안 부분에 대해선 자세하게 공부해 봐야겠다.
728x90
반응형
'모의해킹 > 모의해킹 스터디' 카테고리의 다른 글
모의해킹 스터디 3주차 과제(1) - 로그인 케이스 구현 (0) | 2024.11.01 |
---|---|
모의해킹 스터디 3주차 정리 (0) | 2024.10.31 |
모의해킹 스터디 2주차 과제(1) - 회원가입 (0) | 2024.10.27 |
모의해킹 스터디 2주차 과제 - Mini Mission (0) | 2024.10.26 |
모의해킹 스터디 2주차 정리 (0) | 2024.10.24 |