일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- sql injection
- cors
- 모의해킹
- CTF
- 로그인페이지
- XSS
- JWT
- 로그인
- css
- Python
- Reflected Xss
- sql injection point
- php
- file upload
- csrf
- 과제
- 게시판 만들기
- cookie 탈취
- blind sql injection
- Error based sql injection
- 웹개발
- Cross Site Request Forgery
- Los
- MySQL
- union sql injection
- lord of sqli
- lord of sql injection
- 쿠키
- 세션
- JS
- Today
- Total
Almon Dev
게시판 만들기 #7 (아이디 비밀번호 찾기) 본문
추가한 기능
아이디 찾기
이름과 이메일을 이용해 아이디를 찾는 기능입니다.
forget_id.php
<?php
if(isset($_POST['name']) && isset($_POST['email'])) {
require_once('mysql.php');
$name = addslashes($_POST['name']);
$email = addslashes($_POST['email']);
$sql = "select user_id from users where name='$name' and email='$email'";
$result = runSQL($sql);
if($result->num_rows == 1) {
$id = $result->fetch_array()['user_id'];
$find_message = "<h1>아이디를 찾았습니다.<br>ID : $id</h1>";
}else {
$find_message = "<h1>아이디를 찾지 못했습니다.</h1>";
}
}
?>
<!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="/css/forget_id.css">
</head>
<body>
<container class="find-id-container">
<form action="" method="post" class="find-id-form">
<div class="logo-container">
<a href="/login2.php"><img src="/imgs/almond.png" alt="logo" class="logo"></a>
</div>
<h2>Almond</h2>
<h2>아이디 찾기</h2>
<?= isset($find_message) ? $find_message : '' ?>
<input type="text" name="name" placeholder="이름" class="find-id-input name-input" required>
<input type="email" name="email" placeholder="이메일" class="find-id-input email-input" required>
<button type="submit" class="find-id-submit">아이디 찾기</button>
</form>
</container>
</body>
</html>
if(isset($_POST['name']) && isset($_POST['email'])) {
$name = addslashes($_POST['name']);
$email = addslashes($_POST['email']);
이름과 이메일이 포함된 POST 요청이 왔을 때 $name과 $email변수에 저장합니다.
addslashes() 함수는 sql문에 포함되었을 때 문제가 될만한 특수문자에 \를 붙여서 문자로 취급하도록 만듭니다.
$sql = "select user_id from users where name='$name' and email='$email'";
$result = runSQL($sql);
if($result->num_rows == 1) {
이메일과 이름이 동일한 sql문의 결과가 한 개인 경우만 if문을 실행합니다.
결과가 하나인 경우만 실행하는 이유는 혹시라도 sql injection을 통해 결과가 여러 개일 경우 출력하지 않기 위함입니다.
=> prepared statement를 사용하는 것이 sql injection에 가장 안전합니다.
Prepared Statement
SQL 질의문을 유저의 입력값 부분만 비워둔 채 미리 컴파일해서 쿼리문의 구조 변환이 불가능하게 만듭니다.
if($result->num_rows == 1) {
$id = $result->fetch_array()['user_id'];
$find_message = "<h1>아이디를 찾았습니다.<br>ID : $id</h1>";
}else {
$find_message = "<h1>아이디를 찾지 못했습니다.</h1>";
}
$find_message에 결과를 출력한 문자열을 삽입합니다.
<?= isset($find_message) ? $find_message : '' ?>
$find_message가 있을 경우 html에 $find_message를 삽입합니다.
비밀번호 찾기
이름과 아이디 이메일을 이용해 아이디를 찾는 기능입니다.
forget_pw.php
<?php
session_start();
if(isset($_POST['name']) && isset($_POST['email']) && isset($_POST['id'])) {
require_once('mysql.php');
$name = addslashes($_POST['name']);
$id = addslashes($_POST['id']);
$email = addslashes($_POST['email']);
$sql = "select user_id from users where name='$name' and email='$email' and user_id='$id'";
$result = runSQL($sql);
if($result->num_rows == 1) {
$id = $result->fetch_array()['user_id'];
$_SESSION['id'] = $id;
header('location: forget_pw_proc.php');
exit;
}else {
$find_message = "<h1>계정정보를 찾지 못했습니다.</h1>";
}
}
?>
<!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="/css/forget_pw.css">
</head>
<body>
<container class="find-pw-container">
<form action="" method="post" class="find-pw-form">
<div class="logo-container">
<a href="/login2.php"><img src="/imgs/almond.png" alt="logo" class="logo"></a>
</div>
<h2>Almond</h2>
<h2>비밀번호 찾기</h2>
<?= isset($find_message) ? $find_message : '' ?>
<input type="text" name="name" placeholder="이름" class="find-pw-input name-input" required>
<input type="text" name="id" placeholder="아이디" class="find-pw-input id-input" required>
<input type="email" name="email" placeholder="이메일" class="find-pw-input email-input" required>
<button type="submit" class="find-pw-submit">비밀번호 찾기</button>
</form>
</container>
</body>
</html>
이름과 이메일 아이디를 입력하면 sql 질의를 통해 해당하는 아이디를 찾고 세션에 저장하는 코드입니다.
세션을 사용하는 이유는 해당하는 서버에서 저장하고 사용하기 위함입니다.
=> GET이나 POST 등을 이용해서 요청받으면 클라이언트에서 변조 위험이 있습니다.
=> 비밀번호를 변경하는 기능을 세션을 가진 이용자만 사용하게 하기 위함입니다.
session_start();
if(isset($_POST['name']) && isset($_POST['email']) && isset($_POST['id'])) {
require_once('mysql.php');
session_start()로 세션을 생성합니다.
name, email, id가 POST 요청으로 온 경우만 if문을 실행합니다.
$name = addslashes($_POST['name']);
$id = addslashes($_POST['id']);
$email = addslashes($_POST['email']);
addslashes 함수를 이용해서 sql 문에 방해되는 특수문자의 앞에 \를 붙여줍니다.
=> sql injection 혹은 sql문 에러를 방지
$sql = "select user_id from users where name='$name' and email='$email' and user_id='$id'";
$result = runSQL($sql);
if($result->num_rows == 1) {
$id = $result->fetch_array()['user_id'];
$_SESSION['id'] = $id;
sql 질의문을 통해 이름, 이메일, 아이디가 동일한 계정의 user_id가 하나인 경우 user_id를 세션에 저장합니다.
header('location: forget_pw_proc.php');
exit;
Location 헤더를 이용해 forget_pw_proc.php로 리다이렉트 시킵니다.
}else {
$find_message = "<h1>계정정보를 찾지 못했습니다.</h1>";
}
user_id가 하나가 아닐 경우 $find_message에 실패 메시지를 삽입합니다.
forget_pw_proc.php
<?php
require_once('mysql.php');
session_start();
if (isset($_SESSION['id'])) {
$id = $_SESSION['id'];
if (isset($_POST['pass']) && isset(($_POST['passCheck']))) {
$pass = $_POST['pass'];
$pass_check = $_POST['passCheck'];
$pass_filtered = preg_replace("/\s+/", "", $pass);
// var_dump($pass);
// var_dump($pass_filtered === $pass);
if ($pass === $pass_check && $pass_filtered === $pass) {
$pass_hash = password_hash($pass, PASSWORD_ARGON2ID);
$sql = "update users set password='$pass_hash' where user_id='$id'";
// echo "$sql";
$result = runSQL($sql);
if($result) {
unset($_SESSION['id']);
session_destroy();
header('location: login2.php');
}else {
$fail_message = '<h1>비밀번호 변경에 실패했습니다.</h1>';
}
}else {
$fail_message = '<h1>비밀번호에 공백은 불가능합니다.</h1>';
}
}
}else {
die('잘못된 접근입니다.');
}
?>
<!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="/css/forget_pw.css">
<script src="/script/pw_check.js"></script>
</head>
<body>
<container class="find-pw-container">
<form action="" method="post" class="find-pw-form">
<div class="logo-container">
<a href="/login2.php"><img src="/imgs/almond.png" alt="logo" class="logo"></a>
</div>
<h2>Almond</h2>
<h2>비밀번호 변경</h2>
<?= isset($fail_message) ? $fail_message : '' ?>
<input type="password" name="pass" placeholder="비밀번호" class="find-pw-input pass-input" required>
<input type="password" name="passCheck" placeholder="비밀번호 확인" class="find-pw-input pass-input-check" required>
<button type="submit" class="find-pw-submit">비밀번호 변경</button>
</form>
</container>
</body>
</html>
세션에 id가 있을경우 비밀번호를 변경하고, 없을 경우 에러 메시지를 출력하는 코드입니다.
session_start();
if (isset($_SESSION['id'])) {
$id = $_SESSION['id'];
세션에 id가 있을 경우 $id 변수에 세션의 id를 저장합니다.
if (isset($_POST['pass']) && isset(($_POST['passCheck']))) {
$pass = $_POST['pass'];
$pass_check = $_POST['passCheck'];
$pass_filtered = preg_replace("/\s+/", "", $pass);
pass와 passCheck가 post로 요청이 오면 $pass, $pass_check 변수에 저장합니다.
preg_replace함수로 공백을 빈칸으로 치환한 뒤 $pass_filtered 변수에 저장합니다.
preg_replace 함수는 정규식을 통해 문자열을 검색하고 일치하는 패턴을 다른 문자로 변경해 줍니다.
preg_replace(정규식(검색), 변경할 문자, 변경할 문자열)
/\s+/ 정규식
/ / : / 사이의 문자열을 정규식으로 해석합니다.
\s : 공백을 뜻합니다. ex) \t \n \r space 등
if ($pass === $pass_check && $pass_filtered === $pass) {
$pass_hash = password_hash($pass, PASSWORD_ARGON2ID);
비밀번호와 비밀번호 확인, 비밀번호와 공백을 제거한 비밀번호가 일치한다면 if문을 실행합니다.
db에서 사용 중인 ARGON2ID 해시 알고리즘을 적용한 비밀번호를 $pass_hash에 저장합니다.
$sql = "update users set password='$pass_hash' where user_id='$id'";
// echo "$sql";
$result = runSQL($sql);
update sql문을 이용해서 비밀번호를 수정합니다.
if($result) {
unset($_SESSION['id']);
session_destroy();
header('location: login2.php');
}else {
$fail_message = '<h1>비밀번호 변경에 실패했습니다.</h1>';
}
비밀번호 변경에 성공하면 세션을 삭제하고 로그인페이지로 리다이렉트 시킵니다.
실패한 경우에는 실패메시지를 $fail_message에 저장합니다.
세션을 삭제하는 이유는 더이상 사용자를 식별할 필요가 없기 때문입니다.
사용자가 다시 비밀번호를 찾을 경우 다시 인증을 해야합니다.
'모의해킹 > 웹 개발' 카테고리의 다른 글
게시판 만들기 #10 (게시글 내부에 이미지 추가) (0) | 2025.02.13 |
---|---|
게시판 만들기 #9 (게시글 검색과 정렬) (0) | 2025.01.31 |
게시판 만들기 #6 (게시글 삭제하기) (0) | 2024.11.12 |
게시판 만들기 #5 (게시글 수정하기) (0) | 2024.11.12 |
게시판 만들기 #4 (게시글 읽기) (0) | 2024.11.12 |