이번 과제는 이전에
2024.10.28 - [모의해킹/모의해킹 스터디] - 모의해킹 스터디 2주차 과제(2) - 로그인
개발한 로그인 로직을 JWT를 적용시키는 과제였다.
우선 PHP에서 JWT를 사용하려면 먼저 JWT 라이브러리를 설치해야 한다. 여러 가지 JWT 라이브러리가 있지만, firebase/php-jwt 라이브러리를 사용해보려고 한다.
개발
firebase/php-jwt 라이브러리를 설치하기 위해선 아래의 명령어로 Composer를 우선적으로 설치 해야한다.
curl -sS https://getcomposer.org/installer | php
그 다음 Composer를 전역에서 사용할 수 있도록 설정하려면 다음 명령어를 실행한다.
sudo mv composer.phar /usr/local/bin/composer
프로젝트 경로로 이동한 후 firebase/php-jwt 라이브러리를 설치하기 위해 아래 명령어를 작성한다.
composer require firebase/php-jwt
명령어가 잘 동작하면 JWT를 사용하기 위한 준비는 모두 마쳤다.
JWT를 본격적으로 사용하기 전에 보안적 요소를 고려하고자 .env파일을 생성하여 관리하고자 한다. 그러기 위해선 아래의 명령어를 작성 후 실행해주면 된다.
composer require vlucas/phpdotenv
이제 위에 과제에서 개발했던 login_proc.php를
<?php
require_once 'db_session_info.php'; // 데이터베이스 연결
require 'vendor/autoload.php'; // JWT 라이브러리 로드
use Dotenv\Dotenv; // env 사용
use \Firebase\JWT\JWT; // Firebase JWT를 사용
// .env 파일 로드
$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();
// 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'])) {
// JWT 생성
$key = $_ENV['SECRET_KEY'];
$payload = [
'iat' => time(), // 발행 시간
'exp' => time() + (60 * 60), // 만료 시간 (1시간)
'user_id' => $user['id'],
'nickname' => $user['nickname']
];
$jwt = JWT::encode($payload, $key, 'HS256'); // 알고리즘을 명시적으로 추가
// JWT를 클라이언트에 전달 (예: 쿠키 또는 HTTP 헤더)
setcookie("jwt", $jwt, time() + (60 * 60), "/webDev", "", false, true); // http를 사용하여 Secure 플래그를 false로 설정
$_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();
?>
해당 코드로 변경해주면 된다.
결과
이처럼 로그인이 성공하고 쿠키에 jwt토큰이 생성된걸 볼 수 있다. 해당 토큰을 디코딩해 보면
작성했던 내용이 잘 나오는걸 볼 수 있다.
후기
JWT를 적용하는 방법은 간단하였다. 하지만 주의해야 할 점이 몇 가지 있다.
첫째, set cookie path는 현 도메인으로 주어야 한다.
- set cookie를 작성할 때 무의식적으로 path를 '/'로 설정했다. 하지만 현재 개발하고 있는 경로는 "/webDev"이다. 만약 "/"로 작성 후 배포를 하였으면 해당 도메인 아래의 모든 경로에서 쿠키에 접근할 수 있게 되어 보안 측면에서 문제가 될 수 있다.
둘째, JWT키는 .env 파일에 작성한다.
- JWT는 세션과 달리 클라이언트에서 관리된다. 그러므로 직접적으로 접근이 가능하여 키가 노출될 가능성이 있어 보안 측면에서 불리하게 적용될 수 있다. 이를 방지하기 위해서는 .env 파일에 JWT 키를 저장하여 사용하는 것이 더 안전하다.
- .env 파일은 애플리케이션의 환경 변수를 관리하는 파일로, 미리 정의된 값이나 보안 정보를 포함할 수 있다. .env 파일에 JWT 키를 저장함으로써 key를 노출하지 않고 필요할 때 꺼내올 수 있어 보안을 강화할 수 있다.
해당 내용을 잘 숙지하고 있다면 JWT는 보안 측면에서 안전하고 쉽게 개발할 수 있는 인증 방식이 될 것이다.
'모의해킹 > 모의해킹 스터디' 카테고리의 다른 글
모의해킹 스터디 4주차 과제(1) - 게시판 만들기 (0) | 2024.11.12 |
---|---|
모의해킹 스터디 4주차 정리 (0) | 2024.11.08 |
모의해킹 스터디 3주차 과제(1) - 로그인 케이스 구현 (0) | 2024.11.01 |
모의해킹 스터디 3주차 정리 (0) | 2024.10.31 |
모의해킹 스터디 2주차 과제(2) - 로그인 (0) | 2024.10.28 |