안녕하세요! 저는 이태까지 GET방식이든 POST 방식이든 일단 받으면 mysqli escape 시켜서
SQL Injection을 피하려고 했습니다! 근데 이제 스크립트 인젝션을 방지하기 위해 filter_var() 함수을 이용하겠습니다.
숫자값이 들어와야 하는데 숫자 이외의 값이 들어오는 것을 걸러내는 필터링 작업해 주는 함수도 있습니다
filter_var() 함수 입니다.
예시 보겠습니다
이렇게 악의적으로 쓸 수 있습니다. 이제 output에는 filter_var 함수로 걸러지고 나오게 해 보았습니다.
이렇게 자바 스크립트가 아예 실행 안 되는 것을 볼 수 있습니다.
실제로 저렇게 html 구문인 <,>,'," 등 html에 쓰이는 특수기호를 전부 무시합니다.
근데 또 불안하죠 호출은 안전하지만 내부에서 말썽을 피울 수 있기 때문입니다!
그야 < > 이런 특수 기호는 사라져도 script라는 클라이언트에 실행 가능한 자바 스크립트는 남아있기 때문이죠
그때! 같이 쓰는 함수가 있습니다 자바 스크립트 관련 태그를 없애주는 함수 strip_tags() 입니다!
여기서 또 주의할 게 있습니다.
이러면 뭐가 나올까요? 그저 순서만 바뀌었는데 말이죠
이번엔 script가 나왔습니다! 이 차이는 filter_var에서는 특수 기호만 인코딩을 하여 다른 값으로 바꿉니다.
그리고 호출할 땐 그 인코딩의 특수기호가 그대로 나오죠 근데! strip는 인코딩을 한 값을 그대로 받아들여서
<script> 태그를 확인 못하고 그대로 표출하게 됩니다.
이걸 방지하기 위해 일반적으로 strip_tags 함수 먼저 이용하고 난 뒤에 filter 함수를 적용한다고 합니다!
특수기호만 바뀌어도 대부분의 악의적인 스크립트는 막히지만 행여나 불안해서 이 strip_tags 함수 쓴다고 보시면 돼요.
저는 strip_tags() 와 filter_var() 함수 이용해 모든 GET방식, POST로 받은 값들을 보호하겠습니다!
.
.
.
.
.
.
.
.
조금.. 고된 작업이 되겠네요.. 그래도 보안을 위해서 차차 해봅시다.
우선 로그인 페이지 먼저 가겠습니다.
-login.php
딱히 고칠 게 없네요 패스
다음은 회원가입입니다
-join.php
에도 딱히 없네요 패스
아! id란에 placeholder 적겠습니다
-process_login.php
비밀번호는 어차피 해쉬로 저장을 해서 이러한 특수 기호를 작성해도 상관없습니다.
근데 ID는 손 보겠습니다.
만약 ID가 이메일 형식으로 적으시라고 하셨으면
// 변수 정의 및 초기화
$email = "john.doe@example.com";
// FILTER_VALIDATE_EMAIL 필터 사용하여 이메일 유효성 검사
if (filter_var(strip_tags($email), FILTER_VALIDATE_EMAIL)) {
echo "유효한 이메일입니다.";
} else {
echo "유효하지 않은 이메일입니다.";
}
이 형식으로 하시면 돼요!
근데 저는 이메일 작성란이 딱히 없기에 이렇게 작성하면 되는구나라고만 알고 있겠습니다.
어쨌든 총코드 입니다.
<?php
include 'DB_INFO.php'; //데이터 베이스 정보
//데이터베이스 연결
$conn = mysqli_connect($host,$username,$password,$dbname);
session_start(); //세션 시작
//오류시 종료
if(mysqli_connect_errno()) {
die("데이터 베이스 오류: ". mysqli_connect_error());
}
//POST로 전달된 정보 받기
$login_id = mysqli_real_escape_string($conn,filter_var(strip_tags($_POST['id']),FILTER_SANITIZE_SPECIAL_CHARS));
$login_pw = mysqli_real_escape_string($conn,$_POST['pw']);
//ID 찾는 쿼리문
$sql = "SELECT * FROM LOGIN_INFO WHERE id='$login_id'";
//쿼리 실행
$result = mysqli_query($conn, $sql);
//쿼리 실행 결과 확인
if(mysqli_num_rows($result) > 0 ) {
//ID있으니 비밀번호 검증
$row = mysqli_fetch_array($result) ;
$hashed_pw = $row['pw']; //결과 배열 중 pw을 가져온다
if(password_verify($login_pw,$hashed_pw)) {
//로그인 성공
session_regenerate_id(); //ID 자동 갱신
$_SESSION['login_id'] = $row['id'];
header("Location: only_login.php");
} else {
//로그인 실패
$_SESSION['login_error'] = "비밀번호가 일치하지 않습니다.";
header("Location: login.php");
}
}
else {
//로그인 실패
$_SESSION['login_error'] = '아이디 또는 비밀번호가 일치 하지 않습니다.';
header("Location: login.php");
}
?>
-process_join.php
주소는 어차피 입력 불가하죠? 비밀번호는 해쉬로 저장하니 상관없고요
역시 ID만 손보겠습니다
<?php
include 'DB_INFO.php'; //데이터 베이스 정보
session_start(); //세션 시작
//데이터베이스 연결
$conn = mysqli_connect($host,$username,$password,$dbname);
//데이터베이스 오류시 종료
if(mysqli_connect_errno()) {
die("데이터 베이스 오류: ". mysqli_connect_error());
}
//POST로 전달된 정보 받기
$login_id = mysqli_real_escape_string($conn,filter_var(strip_tags($_POST['id']),FILTER_SANITIZE_SPECIAL_CHARS));
$login_pw = mysqli_real_escape_string($conn,$_POST['pw']);
$adr = trim(mysqli_real_escape_string($conn,$_POST['address']));
//비밀번호는 해싱
$hashed_pw = password_hash($login_pw, PASSWORD_DEFAULT);
//암호화 키
$encryption_key = 'my_secret_key';
//주소는 암호화
$encrypted_address = openssl_encrypt($adr, 'aes-256-cbc', $encryption_key, OPENSSL_ZERO_PADDING, '1234567890123456');
//ID 중복 검사용 sql문
$check_id = "SELECT id FROM LOGIN_INFO WHERE id='$login_id' ";
//중복 검사 sql문 실행
$result_id = mysqli_query($conn, $check_id);
if(mysqli_num_rows($result_id) > 0 ) {
//중복이 있을때
$_SESSION['join_error'] = '아이디가 중복입니다!';
header("Location: join.php");
} else {
//중복이 아닐때
//새로운 사용자를 데이터베이스에 삽입문
$sql = "INSERT INTO $dbname (id, pw, adr)
VALUES ('$login_id','$hashed_pw','$encrypted_address')";
//sql문 실행
if(mysqli_query($conn,$sql)) {
$_SESSION['join_error'] = '회원가입이 완료되었습니다!';
header("Location: join.php");
} else {
$_SESSION['join_error'] = '회원가입 오류가 발생하였습니다.';
header("Location: join.php");
}
}
//회원가입 후 닫기
exit();
?>
-only_login.php
딱히 없네요 패스
-process_logout.php
여기도 없네요! 바로 header로 이동하고 session 종료시키니 문제가 없을 겁니다.
-board.php
page랑 search는 그대로 하는데 날짜가 말썽이죠! YYYY-MM-DD 이 사이에 있는 - 때문이죠
그러니 format 함수를 이용해 날짜 값으로 바꾸겠습니다
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Welcome!</title>
</head>
<body>
<h1>MENU</h1>
<form method ="GET" action="board.php">
<input type = "text" name="search" placeholder="검색">
<input type="submit" value="검색">
<label for="date">날짜 선택:</label>
<input type="date" id="date_value" name="date_value">
</form>
<p>
<?php
include 'DB_INFO.php'; //데이터 베이스 정보
//데이터베이스 연결
$conn = mysqli_connect($host,$username,$password,$db_board);
//데이터베이스 오류시 종료
if(mysqli_connect_errno()) {
die("데이터 베이스 오류: ". mysqli_connect_error());
}
session_start(); //세션 시작
if(!isset($_SESSION['login_id'])) {
//로그인하지 않은 사용자
header("Location: login.php"); //login 화면으로 바꾼다
exit(); //이 페이지를 바로 닫는다
}
//한 페이지에 보여줄 게시물 수
$num_per_page = 5;
//현재 페이지 번호
if(isset($_GET['page'])) {
$page = mysqli_real_escape_string($conn,filter_var(strip_tags(intval($_GET['page'])),FILTER_SANITIZE_SPECIAL_CHARS));
} else {
$page = 1;
}
//전체 게시물 수 조회
$total_sql = "SELECT count(*) AS cnt FROM $db_board";
//작성된 게시물들 조회 문
$sql = "SELECT board_id,id,title,views FROM $db_board";
//검색이 입력된 경우
if(isset($_GET['search'])) {
$search = mysqli_real_escape_string($conn, filter_var(strip_tags($_GET['search']),FILTER_SANITIZE_SPECIAL_CHARS));
$date_value = mysqli_real_escape_string($conn, $_GET['date_value']);
$date_value = DateTime::createFromFormat('Y-m-d', $_GET['date_value'])->format('Y-m-d'); //날짜 값으로 다시 바꾼다
if(isset($_GET['date_value'])) {
//날짜 선택한 경우
$sql = "SELECT board_id,id,title,date_value,views FROM $db_board WHERE title LIKE '%$search%' AND date_value LIKE '%$date_value%'";
$total_sql = "SELECT count(*) AS cnt FROM $db_board WHERE title LIKE '%$search%' AND date_value LIKE '%$date_value%'";
}
else {
//날짜가 선택이 안된 경우
$sql = "SELECT board_id,id,title,views FROM $db_board WHERE title LIKE '%$search%'";
$total_sql = "SELECT count(*) AS cnt FROM $db_board WHERE title LIKE '%$search%'";
}
}
$total_result = mysqli_query($conn,$total_sql); //sql문 실행
$total_row = mysqli_fetch_assoc($total_result); //결과를 배열로 가져온다
$total_posts = $total_row['cnt']; //배열 중 cnt의 값을 가져온다
//전체 페이지 수
$total_pages = ceil($total_posts / $num_per_page);
//각 페이지 시작 인덱스
$start = ($page - 1) * $num_per_page;
//sql문에 추가로 작성하고 LIMIT 설정하고 DESC 즉 내림차순으로 정렬
$sql .= " ORDER BY board_id DESC LIMIT $start, $num_per_page";
//쿼리문 실행
$result = mysqli_query($conn, $sql);
if(mysqli_num_rows($result) > 0) {
//게시물 출력
while($row = mysqli_fetch_assoc($result)) {
$index = $row['board_id'];
$id = $row['id'];
$title = $row['title'];
echo '<p><a href="view_board.php?index='.$index.'">'.$title.'</a> : '.$id.'작성함 조회수: '.$row['views'].'</p>';
}
} else {
echo "게시물이 없습니다!";
}
echo '<p> [ ';
// 현재 페이지를 10으로 나눈 몫에 10을 곱한 값에서 1을 빼면
// 현재 페이지가 몇 번째 페이지 블록에 있는지 알 수 있습니다.
$block_start = floor(($page-1)/10)*10;
if ($block_start > 1) {
// 이전 페이지 블록이 있다면, 다음 버튼을 출력합니다.
$next_block_start = $block_start - 10;
if($next_block_start == 0) {
$next_block_start += 1; //0페이지는 존재 하지 않기에 1더한다
}
echo '<a href="?page=' . $next_block_start .'"><< </a>';
}
// 이전 버튼 출력
if ($page > 1) {
echo '<a href="?page=' . ($page-1) .'">< </a> ';
}
// 페이지 링크 출력
for ($i = $block_start+1; $i <= min($block_start+10, $total_pages); $i++) {
if($i == $page) {
echo '<strong>'.$i.' </strong>';
} else {
echo '<a href="?page=' . $i .'">'.$i. '</a> ';
}
echo ' ';
}
// 다음 버튼 출력
if ($page < $total_pages) {
echo '<a href="?page=' . ($page+1) .'">> </a> ';
}
if ($block_start+10 < $total_pages) {
// 다음 페이지 블록이 있다면, 다음 버튼을 출력합니다.
$next_block_start = $block_start + 11;
echo '<a href="?page=' . $next_block_start .'">>></a>';
}
echo ' ]</p>';
?>
</p>
<p></p>
<form action="write_board.php" method="POST">
<p><input type="submit" name="write" value="게시판 작성"></p>
</form>
<form action="only_login.php">
<p><input type="submit" value="메인페이지로"></p>
</form>
</body>
</html>
-view_board.php
GET으로 index을 받고 있네요! 고치겠습니다.
그리고 fix_board.php로 갈 때 GET방식으로 주게 하겠습니다.
또한 파일명이 1_1_happy.txt 일 때 1만 나오는 에러를 해결하기 위해
array_slice 이용해 _기준을 나누고 맨 앞이 저희가 중복 이름 피하기 위해 작성한 날짜 값을 제외시키겠습니다.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>게시물 보는중</title>
</head>
<body>
<p>
<?php
include 'DB_INFO.php'; //데이터 베이스 정보
//데이터베이스 연결
$conn = mysqli_connect($host,$username,$password,$db_board);
//데이터베이스 오류시 종료
if(mysqli_connect_errno()) {
die("데이터 베이스 오류: ". mysqli_connect_error());
}
session_start(); //세션 시작
if(!isset($_SESSION['login_id'])) {
//로그인하지 않은 사용자
header("Location: login.php"); //login 화면으로 바꾼다
exit(); //이 페이지를 바로 닫는다
}
//GET방식으로 전달된 index 받는다
$board_id = mysqli_real_escape_string($conn,filter_var(strip_tags($_GET['index']),FILTER_SANITIZE_SPECIAL_CHARS));
//가독성 위해 다른 변수에 저장
$last_viewed_time_for_board_id = 'last_view_time_'.$board_id;
// 세션에 마지막 조회 시간 정보가 있는지 확인
if (!isset($_SESSION[$last_viewed_time_for_board_id])) {
// 세션에 마지막 조회 시간 정보가 없으면 현재 시간을 저장
$_SESSION[$last_viewed_time_for_board_id] = time();
} else {
// 세션에 마지막 조회 시간 정보가 있으면 일정 시간이 지났는지 확인
$last_view_time = $_SESSION[$last_viewed_time_for_board_id];
$current_time = time();
$time_diff = $current_time - $last_view_time;
if ($time_diff >= 60) { // 60초(1분) 이상 지났으면 조회수 증가
//조회수 증가하는 sql문
$sql_view = "UPDATE $db_board SET views = views + 1 WHERE board_id = '$board_id'";
//실행
$result_view = mysqli_query($conn, $sql_view);
// 세션에 현재 조회 시간을 저장
$_SESSION[$last_viewed_time_for_board_id] = $current_time;
}
}
//작성된 게시물들 조회 문
$sql = "SELECT * FROM $db_board WHERE board_id = '$board_id' ";
//쿼리문 실행
$result = mysqli_query($conn, $sql);
//게시물 출력
while($row = mysqli_fetch_assoc($result)) {
echo '<p>조회수: '.$row['views'].'</p>';
echo '<p>ID: '.$row['id'].'</p>';
echo '<p>Title: '.$row['title'].'</p>';
echo '<p>Detail: '.$row['detail'].'</p>';
echo '<p>Date: '.$row['date_value'].'</p>';
if (isset($row['file_name'])) {
$file_name = implode('_', array_slice(explode('_', $row['file_name']), 1)); // '_' 문자를 기준으로 분리 후 첫 번째 요소를 제외한 나머지 요소를 모두 합쳐서 파일명을 구성합니다.
$download_url = 'download_process.php?filename='.$row['file_name'];
echo '<p>FILE: <a href="'.$download_url.'">'.$file_name.'</a></p>';
}
//로그인한 사용자의 정보 가져온다
$user_id = $_SESSION['login_id'];
//게시물 작성자와 로그인한 ID와 일치한 경우
if($row['id'] == $user_id) {
//게시물 수정 버튼을 보여준다
echo "<form method='GET' action='fix_board.php'>
<input type='hidden' name='board_id' value='".$row['board_id']."'>
<p><button type='submit'>게시물 수정</button></p>
</form>";
//게시물 삭제 버튼을 보여준다
echo "<form method='POST' action='delete_board.php'>
<input type='hidden' name='board_id' value='".$row['board_id']."'>
<p><button type='submit'>삭제</button></p>
</form>";
}
}
?>
</p>
<p>
<?php session_start();
if (isset($_SESSION['write_error'])) {
echo $_SESSION['write_error'];
unset($_SESSION['write_error']);
}
?>
</p>
<p>
<?php session_start();
if (isset($_SESSION['file_error'])) {
echo $_SESSION['file_error'];
unset($_SESSION['file_error']);
}
?>
</p>
<p></p>
<form action="write_board.php" method="POST">
<p><input type="submit" name="write" value="게시판 작성"></p>
</form>
<form action="board.php">
<p><input type="submit" value="메인페이지로"></p>
</form>
</body>
</html>
-write_board.php
여기도 딱히 없네요!
-write_process_board.php
POST로 board_id,title,detail을 받는 것을 수정하겠습니다.
<?php
include 'DB_INFO.php'; //데이터 베이스 정보
session_start(); //세션 시작
if(!isset($_SESSION['login_id'])) {
//로그인하지 않은 사용자
header("Location: login.php"); //login 화면으로 바꾼다
exit(); //이 페이지를 바로 닫는다
}
//게시판 데이터베이스 연결
$conn = mysqli_connect($host,$username,$password, $db_board);
//데이터베이스 오류시 종료
if(mysqli_connect_errno()) {
die("데이터 베이스 오류: ". mysqli_connect_error());
}
//POST로 전달된 정보 받기
if(isset($_POST['board_id'])){
$board_id = mysqli_real_escape_string($conn,filter_var(strip_tags($_POST['board_id']),FILTER_SANITIZE_SPECIAL_CHARS));
} else {
$board_id = null;
}
$title = mysqli_real_escape_string($conn,filter_var(strip_tags($_POST['title']),FILTER_SANITIZE_SPECIAL_CHARS));
$detail = mysqli_real_escape_string($conn,filter_var(strip_tags($_POST['detail']),FILTER_SANITIZE_SPECIAL_CHARS));
if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_FILES['file'])) {
// 업로드된 파일 정보 가져오기
$file_name = $_FILES['file']['name'];
$timestamp = time(); // 현재 시간을 초로 반환
$new_file_name = $timestamp . '_' . $file_name; // 현재 시간과 원래 파일 이름을 합쳐 새로운 파일 이름 생성
$file_tmp_name = $_FILES['file']['tmp_name'];
$file_size = $_FILES['file']['size'];
$file_error = $_FILES['file']['error'];
$allowed_mime_types = ['image/jpeg', 'image/png', 'image/gif','text/plain','application/zip','application/x-hwp','application/msword','application/vnd.ms-excel','application/pdf']; //MIME 허락 된 것
//확장자 허락 된 것
$allowed_extensions = array("jpg","png","gif","txt","zip","hwp","word","xls","xlsx","pdf");
//sql공격 방지용
$new_file_name = mysqli_real_escape_string($conn,$new_file_name);
// 파일 업로드가 정상적으로 처리되었는지 확인
if ($file_error === UPLOAD_ERR_OK) {
// 파일 MIME 타입 확인, 조작됬는지 확인
$file_mime_type = mime_content_type($file_tmp_name);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$file_mime_type = finfo_file($finfo, $file_tmp_name);
finfo_close($finfo);
if (in_array($file_mime_type, $allowed_mime_types)) {
//파일 확장자 확인
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if(in_array($file_ext, $allowed_extensions)) {
// 파일 저장 경로
$upload_path = '/path/to/upload/directory/' . $new_file_name;
// 파일 이동 및 저장
if (move_uploaded_file($file_tmp_name, $upload_path)) {
$_SESSION['file_error'] = '파일 업로드 성공';
} else {
$_SESSION['file_error'] = '파일 업로드 실패';
}
} else {
$_SESSION['file_error'] = '잘못된 파일 형식입니다';
}
} else {
$_SESSION['file_error'] = '잘못된 파일 형식입니다';
}
}
}
//session으로 유저 이름 받기
$user_id = $_SESSION['login_id'];
echo $board_id;
if(isset($board_id)) {
//board_id가 있다는 것은 수정을 의미
$sql = "UPDATE $db_board SET title = '$title', detail='$detail', file_name='$new_file_name' WHERE board_id='$board_id' ";
}
else {
//board_id가 없으니 새로 만드는 sql문
$sql = "INSERT INTO $db_board (id, title, detail,file_name) VALUES ('$user_id', '$title', '$detail','$new_file_name')";
}
//sql문 실행
if(mysqli_query($conn,$sql)) {
//수정인 경우 바로 게시판 보이게 함
if(isset($board_id)) {
$_SESSION['write_error'] = '수정되었습니다!';
header("Location: view_board.php?index=$board_id");
}
else {
$board_id = mysqli_insert_id($conn); // 새로 생성한 게시물의 id를 가져옴
$_SESSION['write_error'] = '작성되었습니다!';
header("Location: view_board.php?index=$board_id");
}
} else {
$_SESSION['write_error'] = '작성 중 오류가 발생하였습니다.';
header("Location: view_board.php");
}
exit();
?>
-delete_board.php
여기서도 POST로 받는 board_id을 수정하겠습니다.
<?php
include 'DB_INFO.php'; //데이터 베이스 정보
session_start(); //세션 시작
if(!isset($_SESSION['login_id'])) {
//로그인하지 않은 사용자
header("Location: login.php"); //login 화면으로 바꾼다
exit(); //이 페이지를 바로 닫는다
}
//게시판 데이터베이스 연결
$conn = mysqli_connect($host,$username,$password, $db_board);
//데이터베이스 오류시 종료
if(mysqli_connect_errno()) {
die("데이터 베이스 오류: ". mysqli_connect_error());
}
//POST로 전달된 정보 받기
$board_id = mysqli_real_escape_string($conn,filter_var(strip_tags($_POST['board_id']),FILTER_SANITIZE_SPECIAL_CHARS));
//session으로 유저 이름 받기
$user_id = $_SESSION['login_id'];
//삭제용 sql문 작성
$sql = "DELETE FROM $db_board WHERE board_id=$board_id";
//실행
if(mysqli_query($conn,$sql)) {
//실행 후 게시판으로 이동
header("Location: board.php");
} else {
//오류 발생 시 메시지 호출
$_SESSION['write_error'] = '삭제하는데 실패했습니다! 조금 있다 하십시오';
header("Location: view_board.php");
}
exit();
?>
-download_process.php
filename을 손 보겠습니다
<?php
if(isset($_GET['filename'])) {
// 파일 이름 및 경로 가져오기
$filename = filter_var(strip_tags($_GET['filename']),FILTER_SANITIZE_SPECIAL_CHARS);
$filepath = '/path/to/upload/directory/'.$filename;
// 파일이 존재하는지 확인
if(file_exists($filepath)) {
// 다운로드 헤더 설정
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filepath));
readfile($filepath);
exit;
} else {
echo '파일이 존재하지 않습니다.';
}
} else {
echo '파일 이름이 전달되지 않았습니다.';
}
?>
그리고.. zip형식 안에 exe파일이 들어가 있는 상태로 게시물을 올릴 수가 있습니다.
그러니 클라이언트는 exe파일을 함부로 누르면 안 되며 패치가 안된 소프트웨어도 조심해야만 합니다!
그러니 서버에는 zip형식이라 서버 측에는 아무런 피해가 없지만
다운로드한 zip안에 바이러스 같은 것은 막을 수가 없습니다.
그 형식은 오로지 서버가 아닌 클라이언트를 노리고 하는 것이니깐요.
그러니 이 현상을 피하는 것은 클라이언트들의 숙제이자 조심해야만 하는 겁니다!
넘어가겠습니다.제가 어렸을 때 함부로 블로그에 있는 스타크래프트 파일 받다가 된통 맞았거든요
-fix_board.php
GET방식으로 오는 board_id 만 수정하면 되겠네요!
그리고 업로드된 파일도 수정가능하게 코드 추가 하겠습니다!
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>게시판 수정 중</title>
</head>
<body>
<?php
include 'DB_INFO.php'; //데이터 베이스 정보
//데이터베이스 연결
$conn = mysqli_connect($host,$username,$password,$db_board);
//데이터베이스 오류시 종료
if(mysqli_connect_errno()) {
die("데이터 베이스 오류: ". mysqli_connect_error());
}
session_start(); //세션 시작
if(!isset($_SESSION['login_id'])) {
//로그인하지 않은 사용자
header("Location: login.php"); //login 화면으로 바꾼다
exit(); //이 페이지를 바로 닫는다
}
//GET방식으로 board_id 받기
$board_id = mysqli_real_escape_string($conn,filter_var(strip_tags($_GET['board_id']),FILTER_SANITIZE_SPECIAL_CHARS));
//작성된 게시물들 조회 문
$sql = "SELECT * FROM $db_board WHERE board_id = '$board_id' ";
//쿼리문 실행
$result = mysqli_query($conn, $sql);
//결과값 가져오기
$row = mysqli_fetch_assoc($result);
?>
<form action="write_process_board.php" method="POST" enctype="multipart/form-data">
<p><input type="text" name="title" maxlength="44" value="<?php echo $row['title']; ?>" placeholder="제목 입력, 최대 44자까지 가능합니다"></p>
<p><textarea name="detail" rows="20" cols="20" maxlength="254" placeholder="내용 작성,최대 254자 가능합니다"><?php echo $row['detail']; ?></textarea></p>
<p><input type="file" name="file" id="fileToUpload"></p>
<?php
if (isset($row['file_name'])) {
$file_name = implode('_', array_slice(explode('_', $row['file_name']), 1)); // '_' 문자를 기준으로 분리 후 첫 번째 요소를 제외한 나머지 요소를 모두 합쳐서 파일명을 구성합니다.
echo '<p>FILE: '.$file_name.'</p>';
}
?>
<p><input type="submit" value="수정하기"></p>
<input type="hidden" name='board_id' value="<?php echo $row['board_id']; ?>">
</form>
<p>
<?php session_start();
if (isset($_SESSION['write_error'])) {
echo $_SESSION['write_error'];
unset($_SESSION['write_error']);
}
?>
</p>
</body>
</html>
끝입니다!
좋아요.. XSS 공격이라 하죠. 이걸 방지하기 위해 보안 함수 2개를 이용했고
mysqli escape 함수 이용해 sql인젝션 공격을 방지했습니다!
누락된 게 있을 수 있습니다.
만약 에러나 보안 문제가 생기면 그때 고치도록 하죠!
.
.
.
.
파일 업로드 보안, SQL 인젝션 보안, 스크립트 인젝션 보안 좋아요!
이제 나중에는 세션 하이재킹 보안을 해보도록 하겠습니다!
'개발과제 > 보안추가' 카테고리의 다른 글
[노말틱 모의 해킹 취업반 추가 개발과제 ] XSS 방지 (0) | 2023.05.13 |
---|---|
[노말틱 모의 해킹 취업반 추가 개발과제 ] PreparedStatement 적용하기 -2 (0) | 2023.05.03 |
[노말틱 모의 해킹 취업반 추가 개발과제 ] PreparedStatement 적용하기 -1 (0) | 2023.05.02 |
[노말틱 모의 해킹 취업반 개발과제 (2)] 보안 관련해서 보완 하기 (2) | 2023.04.20 |
[노말틱 모의 해킹 취업반 개발과제 (1)] 보안 관련해서 보완 하기 (3) | 2023.04.05 |