이번주 과제는
2024.10.31 - [모의해킹/모의해킹 스터디] - 모의해킹 스터디 3주차 정리
여기서 정리했던 로그인 케이스를 코드로 구현하는 것이다.
개발
먼저 간단한 로그인 화면을 만들어주었다.
<!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>
<form method="post" action="각 파일명.php">
<div class="form-group">
<input type="text" class="form-control" name="id" 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>
그다음 DB에 다음과 같은 데이터를 삽입해 놓았다.
아래 순서로 진행할 것이며 로그인 페이지의 `action="각 파일명.php"` 에 넣어 해당 코드를 출력해 보려고 한다.
1. 식별과 인증을 동시에 실행(identi_auth_simul.php)
2. 식별과 인증을 분리하여 실행(identi_auth_sep.php)
3. 식별과 해시값을 적용시킨 인증을 동시에 실행(identi_auth_simul_hash.php)
4. 식별과 해시값을 적용시킨 인증을 분리하여 실행(identi_auth_sep_hash.php)
1. 식별과 인증을 동시에 실행
개발(identi_auth_simul.php)
<?php
require_once 'db_info.php';// 데이터베이스 연결
$id = $_POST['id'];
$password = $_POST['password'];
var_dump($id);
var_dump($password);
$sql = "select * from login_test where user_id = ? and user_pw = ?";
//stmt 세팅
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $id, $password);
$stmt->execute();
$stmt_result = $stmt->get_result();
$result = $stmt_result->fetch_assoc();
if($result){
//로그인 성공
echo "로그인에 성공하였습니다.";
}else{
//로그인 실패
echo "로그인에 실패하였습니다.";
}
$stmt->close();
?>
결과
- 로그인 실패
- 로그인 성공
2. 식별과 인증을 분리하여 실행
개발(identi_auth_sep.php)
<?php
require_once 'db_info.php';// 데이터베이스 연결
$id = $_POST['id'];
$password = $_POST['password'];
var_dump($id);
var_dump($password);
$sql = "select * from login_test where user_id = ?";
//stmt 세팅
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$stmt_result = $stmt->get_result();
$result = $stmt_result->fetch_assoc();
if($result){
if($result['user_pw'] == $password){
//로그인 성공
echo "로그인에 성공하였습니다.";
}else{
//로그인 실패
echo "로그인에 실패하였습니다.";
}
}else{
//로그인 실패
echo "로그인에 실패하였습니다.";
}
$stmt->close();
?>
결과
- 로그인 실패
- 로그인 성공
3. 식별과 해시값을 적용시킨 인증을 동시에 실행
개발(identi_auth_simul_hash.php)
<?php
require_once 'db_info.php';// 데이터베이스 연결
$id = $_POST['id'];
$password = $_POST['password'];
$hashed_pw = hash('sha256', $password); // 비밀번호 해시 적용
var_dump($id);
var_dump('해시값 적용 전 비밀번호 : ' . $password);
var_dump('해시값 적용 후 비밀번호 : ' . $hashed_pw);
$sql = "select * from login_test where user_id = ? and user_pw = ?";
//stmt 세팅
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $id, $hashed_pw);
$stmt->execute();
$stmt_result = $stmt->get_result();
$result = $stmt_result->fetch_assoc();
if($result){
//로그인 성공
echo "로그인에 성공하였습니다.";
}else{
//로그인 실패
echo "로그인에 실패하였습니다.";
}
$stmt->close();
?>
결과
- 로그인 실패
- 로그인 성공
4. 식별과 해시값을 적용시킨 인증을 분리하여 실행
개발(identi_auth_sep_hash.php)
<?php
require_once 'db_info.php';// 데이터베이스 연결
$id = $_POST['id'];
$password = $_POST['password'];
$hashed_pw = hash('sha256', $password); // 비밀번호 해시 적용
var_dump($id);
var_dump('해시값 적용 전 비밀번호 : ' . $password);
var_dump('해시값 적용 후 비밀번호 : ' . $hashed_pw);
$sql = "select * from login_test where user_id = ?";
//stmt 세팅
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$stmt_result = $stmt->get_result();
$result = $stmt_result->fetch_assoc();
if($result){
if($result['user_pw'] == $hashed_pw){
//로그인 성공
echo "로그인에 성공하였습니다.";
}else{
//로그인 실패
echo "로그인에 실패하였습니다.";
}
}else{
//로그인 실패
echo "로그인에 실패하였습니다.";
}
$stmt->close();
?>
결과
- 로그인 실패
- 로그인 성공
후기
다양한 로그인 케이스들을 구현해 봤다.
- 식별과 인증을 동시에 실행
- 코드가 아이디와 비밀번호를 동시에 확인할 수 있어 간단하고 직관적이다
- 비밀번호가 평문으로 데이터베이스에 저장되어 있어 데이터베이스가 해킹당할 경우 모든 비밀번호가 유출되므로 보안이 취약하다.
- 식별과 인증을 분리하여 실행
- 아이디가 존재하는지 먼저 확인한 후 비밀번호를 확인하므로, 관련한 로직을 추가로 개발한다면 로그인 시도가 실패하는 경우의 수를 줄일 수 있다.
- 두 개의 로직이 필요하므로 첫 번째 코드보단 성능이 떨어질 수 있다.
- 식별과 해시값을 적용시킨 인증을 동시에 실행
- 비밀번호를 해시 알고리즘을 사용하여 저장하므로 데이터베이스가 해킹되더라도 비밀번호가 안전하다.
- 해시를 사용하여 비밀번호를 비교하므로 보안성이 높다.
- 비밀번호 해시를 확인하기 위해 아이디와 비밀번호를 동시에 확인해야 하므로, 여전히 SQL 쿼리에서 비밀번호가 노출될 수 있다.
- 식별과 해시값을 적용시킨 인증을 분리하여 실행
- 비밀번호를 해시 알고리즘을 사용하여 저장하므로 데이터베이스가 해킹되더라도 비밀번호가 안전하다.
- 아이디가 존재하는지 먼저 확인한 후 비밀번호를 확인하므로, 관련한 로직을 추가로 개발한다면 로그인 시도가 실패하는 경우의 수를 줄일 수 있다.
- 해시를 사용하여 비밀번호를 비교하므로 보안성이 높다.
- 비밀번호를 별도로 비교하기 때문에 해시 된 비밀번호를 비교하는 과정이 추가되어 약간의 성능 저하가 있을 수 있다.
- 비밀번호 해시를 검증하는 과정이 추가되므로 코드가 다소 복잡해질 수 있다.
- 결론적으로 네 번째 로직이 개발 시에 가장 안전하고 바람직하며 첫 번째 로직, 두 번째 로직은 해시를 사용하지 않아 보안에 취약하므로 해당 로직처럼 개발하지 않도록 주의해야 한다.
- 이번에는 SHA-256 알고리즘을 활용하였으나, bcrypt 및 Argon2와 같은 다양한 해시 알고리즘을 사용하여 개발을 진행하고, 각각의 특징들을 비교해 봐야겠다.
728x90
반응형
'모의해킹 > 모의해킹 스터디' 카테고리의 다른 글
모의해킹 스터디 4주차 정리 (0) | 2024.11.08 |
---|---|
모의해킹 스터디 3주차 과제(2) - 리눅스 환경에서 PHP로 JWT 구현 (0) | 2024.11.06 |
모의해킹 스터디 3주차 정리 (0) | 2024.10.31 |
모의해킹 스터디 2주차 과제(2) - 로그인 (0) | 2024.10.28 |
모의해킹 스터디 2주차 과제(1) - 회원가입 (0) | 2024.10.27 |