쟝이의 세상
시큐어 코딩이 적용된 게시판 만들기 Window (HTTP, PHP, SQL Server) 본문
"보안을 강화하기 위한 코드 수정" 에서 대부분의 코드가 아래와 같이 수정되었다.
- SQL Injection을 방지하고자 prepare 메서드로 SQL 코드를 정의하고, 입력 값은 바인딩 변수로 받는다.
파라미터 바인딩 후 쿼리를 실행하는 execute 메서드를 사용한다.
- header( ) 함수 사용 후에 코드 실행 방지를 위하여 exit( ); 를 한다.
<< 보안 강화한 게시판 소스 리스트 >>
1) dbconn2.php (데이터베이스 연결)
2) register2.php (회원가입)
3) login2.php (로그인 화면)
4) logout2.php (로그아웃)
5) notice_list2.php (게시판 리스트 보는 화면)
6) notice_add_page2.php (게시판 글 추가하는 화면)
7) notice_add2.php (게시판 글 추가하는 부분을 데이터베이스에 저장)
8) notice_edit_page2.php (게시판 글 수정하는 페이지)
9) notice_edit2.php (게시판 글 수정한 부분을 데이터베이스에 반영)
10) delete2.php (게시글 삭제)
데이터베이스 생성
create database testDB2;
use testDB2;
create table dbo.Users(
UserID char(10) not null primary key,
Username nvarchar(50) not null,
Password nvarchar(255) not null
);
create table dbo.Posts(
PostID int identity(1,1) not null primary key,
Title nvarchar(100) null,
Content nvarchar(max) null,
CreatedDate datetime null,
UserID char(10) null foreign key references Users(UserID)
);

데이터베이스 연결하는 PHP
(dbconn2.php)
-> 데이터베이스와 PHP를 연결하는 코드 작성
<?php
if(session_status() == PHP_SESSION_NONE){
session_start();
}
$current_file = basename($_SERVER['PHP_SELF']);
if(($current_file != 'login2.php' && $current_file != 'register2.php') && !isset($_SESSION['UserID'])){
echo "<script>alert('로그인이 필요합니다');</script>";
echo "<script>location.href='login2.php';</script>";
exit;
}
?>
<?php
$serverName = "(local)";
$database = "testDB2";
$uid = "sa";
$pwd = "p@ssw0rd";
$table = "Posts";
try{
$conn = new PDO("sqlsrv:server=$serverName;Database=$database", $uid, $pwd);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Error connecting to SQL Server");
}
?>
<실행화면>로그인 화면, 회원가입 화면 둘 다 아니고 -> 로그인, 회원가입이 아니면서 세션값이 없으면
alert('로그인이 필요합니다')
메시지 창을 출력
회원가입 PHP
(register2.php)
-> ID, 이름, 비밀번호 입력하여 회원가입을 누르면 DB에 저장되도록 코드를 작성
<?php
include 'dbconn2.php';
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$userid = $_POST['userid'];
$username = $_POST['username'];
$password = $_POST['password']; // 비밀번호 입력값 (평문으로 저장)
// 비밀번호를 해시 처리 (bcrypt 알고리즘 사용)
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
try {
//SQL 쿼리: prepared statement 사용하여 SQL 인젝션 방지
$sql="INSERT INTO Users(UserID, Username, Password) VALUES(:userid, :username, :password)";
$stmt=$conn->prepare($sql);
//파라미터 바인딩
$stmt->bindParam(':userid', $userid);
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $hashed_password);
//쿼리 실행
$stmt->execute();
echo "회원가입이 완료되었습니다.";
header('Location: login2.php');
exit(); //header 후 코드 실행 방지
} catch(PDOException $e) {
die("회원가입 중 오류가 발생했습니다: " . $e->getMessage());
}
}
?>
<form method="POST">
사용자 ID: <input type="text" name="userid" maxlength="10" required><br>
사용자 이름: <input type="text" name="username" required><br>
비밀번호: <input type="password" name="password" required><br>
<input type="submit" value="회원가입">
</form>
보안 강화 수정 부분
- SQL Injection을 방지하고자 prepare 메서드로 SQL 코드를 정의하고, 입력 값은 바인딩 변수로 받는다.
파라미터 바인딩 후 쿼리를 실행하는 execute 메서드를 사용한다.
- 비밀번호는 해시값으로 변환하여 입력한다.
- header( ) 함수 사용 후에 코드 실행 방지를 위하여 exit( ); 를 한다.
<실행 화면>입력받은 값은 데이터베이스에 입력된다. 입력받은 값이 DB에 입력됨을 확인하고, 비밀번호 값은 해시값으로 변환하여 입력해준다.
로그인 PHP
(login2.php)
-> 회원가입을 하면 로그인 창으로 연결되게 regist.php 작성하였으므로 회원가입 버튼을 누를 시에 로그인 창으로 넘어가는지 확인
<?php
session_start();
include "dbconn2.php";
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$userid = $_POST['userid'];
$password = $_POST['password'];
try {
//SQL 쿼리: prepared statement 사용하여 SQL 인젝션 방지
$sql = "SELECT * FROM Users WHERE UserID = :userid";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':userid', $userid);
$stmt->execute(); //쿼리 실행
$user = $stmt->fetch(PDO::FETCH_ASSOC); //사용자 정보 조회
//비밀번호가 해시된 비밀번호와 일치하는지 확인
if($user && password_verify($password, $user['Password'])) {
$_SESSION['UserID'] = $user['UserID']; //세션에 사용자 ID 저장
$_SESSION['Username'] = $user['Username']; //세션에 사용자 이름 저장
echo "<script>alert('로그인 성공');</script>";
echo "<script>location.href='notice_list2.php';</script>";
exit(); // 리다이렉트 후 코드 실행 방지
}
else {
echo "<script>alert('로그인 실패: 사용자 ID 또는 비밀번호가 잘못되었습니다.');</script>";
}
} catch (PDOException $e) {
die("로그인 중 오류가 발생했습니다: " . $e->getMessage());
}
}
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>로그인</title>
</head>
<body>
<h2>로그인</h2>
<form method="POST" action="login2.php">
<label>사용자 ID:</label>
<input type="text" name="userid" required>
<br>
<label>비밀번호:</label>
<input type="password" name="password" required>
<br>
<button type="submit">로그인</button>
<a href="register2.php">회원가입</a>
</form>
</body>
</html>
보안 강화 수정 부분
- ID, 비밀번호의 경우 primary key 이므로 <input> 태그에 required 속성을 입력해준다.
<실행 화면>사용자의 ID와 비밀번호를 행단위로 변수에 가져온 후 아이디와 비밀번호가 일치하면
세션에 해당 아이디와 비밀번호를 저장한다.입력한 아이디와 비밀번호가 일치하면 로그인 성공 메시지 창이 뜬다.
<보안 강화 실행 부분>ID와 비밀번호는 <input> 태그의 required 속성으로 입력하지 않으면 로그인이 되지 않는다.
로그아웃 PHP
(logout2.php)
<?php
session_start();
session_destroy();
header('Location: login2.php');
exit;
?>
로그아웃하면 세션 값이 삭제되고, 로그인 화면으로 이동한다.
게시판 리스트 화면 PHP
(notice_list2.php)
-> 로그인 화면에서 로그인 버튼을 누르면 게시판 리스트 화면으로 이동하도록 코드를 작성하였으므로 로그인 성공 후 게시판 화면으로 이동하는지 확인
<?php
session_start();
if (!isset($_SESSION['UserID']) || !isset($_SESSION['Username'])) {
echo "<script>alert('로그인이 필요합니다');</script>";
echo "<script>location.href='login2.php';</script>";
exit;
}
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>공지사항 리스트</title>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script defer src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
p{
margin: 0;
}
main{
width: 100%;
height: 100%;
}
.top_header{
position: fixed;
top: 0;
width: 100%;
background-color: black;
color: white;
padding: 20px 0;
text-align: right;
z-index: 9999;
}
.logout_btn{
cursor: pointer;
background-color: white;
color: red;
border: none;
border-radius: 15px;
outline: none;
margin: 0 20px;
}
.excel_header{
width: 80%;
margin-top: calc(5% + 50px);
margin-left: 10%;
border: solid gray 1px;
background-color: white;
display: flex;
}
.excel_header div:nth-child(1){
width: 40%;
padding: 30px 20px;
}
.excel_header h3{
margin: 0;
font-size: 20px;
}
.excel_header div:nth-child(2){
width: 80%;
text-align: right;
margin-right: 50px;
padding-top: 30px;
border-radius: 5px;
}
.excel_header div:nth-child(2) button{
width: 100px;
padding: 10px 0;
border: solid black 1px;
color: black;
cursor:pointer;
}
.excel_header div:nth-child(2) button:hover{
background-color: orange;
}
.excel_wrapper{
width: 80%;
margin-left: 10%;
margin-top: 3%;
}
.excel_wrapper table{
width: 100%;
border-collapse: separate;
border-spacing: 0 10px;
}
.excel_wrapper thead, .excel_wrapper tbody{
width: 100%;
}
.excel_wrapper th{
padding: 5px 20px;
border-bottom: solid black 2px;
border-radius: 5px 5px 0 0;
font-size: 20px;
text-align: left;
}
.excel_wrapper td:nth-child(1){
width: 5%;
}
.excel_wrapper td:nth-child(2){
width: 20%;
}
.excel_wrapper td:nth-child(3){
width: 45%;
text-align: left;
}
.excel_wrapper td:nth-child(4){
width: 20%;
text-align: left;
}
.excel_wrapper td{
padding: 7px 5px 17px 20px;
border-bottom: solid gray 1px;
font-size: 18px;
}
.excel_wrapper td:nth-child(3) button{
padding: 5px 10px;
border: solid gray 1px;
border-radius: 5px;
background-color: white;
outline: none;
cursor: pointer;
}
.excel_wrapper td:nth-child(3) button:hover{
border: solid black 1px;
background-color: orange;
}
/* 엑셀 버튼 */
.excel_button{
width: 100%;
text-align: center;
margin-top: 2%;
/* margin-left: -2%; */
}
.excel_button button{
padding: 15px;
background-color: white;
color: black;
font-size: 15px;
border: solid black 2px;
cursor: pointer;
}
.excel_button button:nth-child(1), .excel_button button:nth-child(5){
margin: 0 20px;
}
.excel_button button:nth-child(2), .excel_button button:nth-child(3), .excel_button button:nth-child(4){
margin: 0 5px;
}
a{
color: red;
}
</style>
</head>
<body>
<div class="top_header">
<p>
<?php echo htmlspecialchars($_SESSION['Username'], ENT_QUOTES, 'UTF-8'); ?>님
<a href='logout2.php'>
<button class="logout_btn">로그아웃</button>
</a>
</p>
</div>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<main>
<div class="excel_header">
<div>
<h3>공지사항 관리</h3>
</div>
<div>
<button onclick="location.href='notice_add_page2.php'">추가하기</button>
</div>
</div> <!-- excel_header -->
<div class="excel_wrapper">
<table>
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>내용</th>
<th>업데이트날짜</th>
<th>수정/삭제</th>
</tr>
</thead>
<tbody>
<?php
include "dbconn2.php";
$query = "SELECT * FROM Posts ORDER BY PostID DESC";
$stmt = $conn->query($query);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
?>
<tr>
<td><?php echo htmlspecialchars($row['PostID'], ENT_QUOTES, 'UTF-8');?></td>
<td><?php echo htmlspecialchars($row['Title'], ENT_QUOTES, 'UTF-8');?></td>
<td><?php echo htmlspecialchars($row['Content'], ENT_QUOTES, 'UTF-8');?></td>
<td><?php echo htmlspecialchars($row['CreatedDate'], ENT_QUOTES, 'UTF-8');?></td>
<td>
<?php
if ($_SESSION['UserID'] == $row['UserID']) {
?>
<a href="notice_edit_page2.php?PostID=
<?php
echo htmlspecialchars($row['PostID'], ENT_QUOTES, 'UTF-8');
?>">수정/삭제</a>
<?php
} else {
?>
<span>수정/삭제 불가</span>
<?php
}
?>
</td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
</main>
</div>
</body>
</html>
보안 강화 수정 부분
- htmlspecialchars( ) 함수를 사용하여 문자열에서 특정한 특수 문자를 HTML 엔티티로 변환한다.
데이터베이스에서 가져온 데이터를 HTML로 출력할 때 발생할 수 있는 XSS 공격을 방지
<실행 화면>로그인 성공 시 해당 게시판 메인 화면으로 이동한다.

게시판 글 추가 PHP
(notice_add_page2.php)
-> 게시판 리스트 화면에서 "추가하기" 버튼을 누르면 게시판 글 추가 화면으로 이동하도록 설정하였으므로
버튼 클릭 후 글 추가 화면으로 이동하는지 확인
<?php
session_start();
if(!isset($_SESSION['UserID'])) {
echo "<script>alert ('로그인이 필요합니다.');</script>";
echo "<script>location.href='login2.php';</script>";
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script defer src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<style>
body{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: whitesmoke;
}
main{
width: 100%;
height: 100%;
}
.content_wrapper{
width: 80%;
margin-left: 20%;
}
.content_text{
margin-top: 10%;
font-size: 30px;
}
.add_title h5, .add_content h5{
font-size: 30px;
}
.add_title input, .add_content input{
font-size: 20px;
width: 40%;
padding: 20px 10px;
}
.button_content{
margin-left: 35%;
margin-top: 3%;
}
.button_content button:hover{
background-color: orange;
}
.button_content button{
width: 100px;
padding: 15px 0;
border: solid black 1px;
border-radius: 5px;
background-color: white;
}
.orange:focus{
background-color: orange;
}
</style>
</head>
<body>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<main>
<div class="content_wrapper">
<div class="content_text">
<h2>공지사항 추가</h2>
</div>
<form action="notice_add2.php" method="POST" onsubmit="return validateForm()">
<div class="add_title">
<h5>제목</h5>
<input type="text" maxlength="20" placeholder="20자까지 입력 가능~!" class="orange" name="title" required>
</div>
<div class="add_content">
<h5>내용</h5>
<input type="text" maxlength="100" placeholder="100자까지 입력 가능~!" class="orange" name="content" required>
</div>
<div class="button_content">
<button type="submit" id="add">추가하기</button>
</div>
</form>
</div><!--content_wrapper-->
</main>
</div>
<script>
//클라이언트 측 입력 검증 추가
function validateForm() {
const title = document.querySelector('input[name="title"]').value;
const content = document.querySelector('input[name="content"]').value;
if(title.trim()==="" || content.trim()==="") {
alert("모든 필드를 채워주세요.");
return false;
}
if(title.length>20 || content.length>100) {
alert("입력된 값이 너무 깁니다.");
return false;
}
return true;
}
</script>
</body>
</html>
<실행 화면><input> 태그에 required 속성이 있으므로 입력하지 않을 때에 추가하기가 되지 않는다. <input> 태그에 required 속성이 있으므로 입력하지 않을 때에 추가하기가 되지 않는다. 제목과 내용이 입력되지 않은 상태로 폼이 전송되면 자바스크립트 함수를 통해 메시지 창을 띄워준다.
게시판 추가 시 데이터베이스 반영 PHP
(notice_add2.php)
-> 추가하기 버튼을 눌러 받은 데이터 값을 데이터베이스에 INSERT 한다.
<?php
session_start();
//로그인 여부 확인
if(!isset($_SESSION['UserID'])) {
echo "<script>alert ('로그인이 필요합니다.');</script>";
echo "<script>location.href='login2.php';</script>";
exit;
}
if($_SERVER['REQUEST_METHOD'] !=='POST'){
echo "<script>alert('잘못된 접근입니다.');</script>";
echo "<script>location.href='notice_list2.php';</script>";
exit;
}
?>
<?php
$title = trim($_POST['title']);
$content = trim($_POST['content']);
$now = date('Y-m-d H:i:s');
include "dbconn2.php"; //데이터베이스 연결 설정 파일 포함
if(empty($title) || empty($content)) {
echo "<script>alert('제목과 내용을 모두 입력해주세요');</script>";
echo "<script>history.back();</script>";
exit;
}
try {
//SQL 쿼리 준비
$query = "INSERT INTO $table(Title, Content, CreatedDate, UserID) VALUES(:Title, :Content, :CreatedDate, :UserID)";
$stmt = $conn->prepare($query); //쿼리 준비
//바인드 파라미터 설정
$stmt->bindParam(':Title', $title, PDO::PARAM_STR);
$stmt->bindParam(':Content', $content, PDO::PARAM_STR);
$stmt->bindParam(':CreatedDate', $now, PDO::PARAM_STR);
$stmt->bindParam(':UserID', $_SESSION['UserID'], PDO::PARAM_STR);
$stmt->execute();
echo "<script>alert ('추가되었습니다');</script>";
echo "<script>location.href='notice_list2.php';</script>";
} catch (PDOException $e) {
//오류 메시지 출력
echo "<script>alert('데이터베이스 오류가 발생했습니다.');</script>";
error_log("Database errpr: ".$e->getMessage()); //서버의 오류 로그에 기록
echo "<script>history.back();</script>";
}
?>
보안 강화 수정 부분
- 받은 <form> 태그의 method가 POST가 아닐 경우 "잘못된 접근입니다" 메시지 창을 띄우고, 게시판 화면으로 이동한다.
- 양쪽의 공백을 제거한 제목이나 내용이 비어있다면 이전 페이지로 이동한다.
<실행 화면>값이 정상적으로 입력되면 "추가되었습니다." 메시지 창이 뜬다. 입력한 값이 Posts 테이블에 삽입되는 것을 확인할 수 있고,
게시판 글 추가가 완료되면 Posts 테이블에서 각각의 내용을 불러온다.
게시판 글 수정 PHP
(notice_edit_page2.php)
-> 게시판 올라온 글의 수정을 누르면 글 수정하는 화면으로 이동
<?php
session_start();
if(!isset($_SESSION['UserID'])) {
echo "<script>alert ('로그인이 필요합니다');</script>";
echo "<script>location.href='login2.php';</script>";
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script defer src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>공지사항 수정</title>
<style>
body{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: whitesmoke;
}
main{
width: 100%;
height: 100%;
}
.content_wrapper{
width: 80%;
margin-left: 20%;
}
.content_text{
margin-top: 10%;
font-size: 30px;
}
.edit_title h5, .edit_content h5{
font-size: 30px;
}
.edit_title input, .edit_content input{
font-size: 20px;
width: 40%;
padding: 20px 10px;
}
.orange:focus{
background-color: orange;
}
.button_content{
margin-left: 35%;
margin-top: 3%;
}
.button_content button{
width: 100px;
padding: 15px 0;
border: solid black 1px;
border-radius: 5px;
background-color: white;
}
.button_content button:hover{
background-color: orange;
}
</style>
</head>
<body>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<main>
<div class="content_wrapper">
<div class="content_text">
<h2>공지사항 수정</h2>
</div>
<?php //해당 글 번호의 행 데이터값 읽어오기
include "dbconn2.php";
//입력값 검증
if(isset($_GET['PostID']) && is_numeric($_GET['PostID'])){
$PostID = $_GET['PostID'];
//Prepared Statement 사용
$stmt = $conn->prepare("SELECT * FROM $table WHERE PostID=?");
$stmt->execute([$PostID]);
if($row=$stmt->fetch(PDO::FETCH_ASSOC)){
//XSS 방지를 위해 htmlspecialchars 사용
$title = htmlspecialchars($row['Title'], ENT_QUOTES, 'UTF-8');
$content = htmlspecialchars($row['Content'], ENT_QUOTES, 'UTF-8');
?>
<form action="notice_edit2.php" method="POST" onsubmit="return confirmEdit()">
<div class="edit_title">
<h5>제목</h5>
<input type="text" class="orange"
value="<?=$title;?>" name="title">
</div>
<div class="edit_content">
<h5>내용</h5>
<input type="text" class="orange"
value="<?=$content;?>" name="content">
<input type="hidden" value="<?=$PostID;?>" name="PostID">
<div class="button_content">
<button type="submit">수정완료</button>
</div>
<a href="delete2.php?PostID=<?=$PostID;?>">삭제</a>
</div>
</form>
<?php
} else {
echo "<p>해당 공지사항을 찾을 수 없습니다.</p>";
}
} else {
echo "<p>잘못된 요청입니다.</p>";
}
$conn = null;
?>
</div>
</main>
<script>
function confirmEdit(){
return confirm('수정하시겠습니까?');
}
</script>
</div>
</body>
</html>
보안 강화 수정 부분
- 입력값을 검증한다.
(입력받은 값이 null이 아니고, PostID의 값이 숫자일 경우 해당 PostID 값의 데이터들을 모두 불러온다.)
- <form> 태그를 전송할 때 자바스크립트의 함수 confirmEdit( )가 동작한다.
<실행 화면>수정완료 버튼을 누르면 자바스크립트의 함수가 동작한다.
(onsubmit : 양식 제출 이벤트가 발생할 때의 동작을 지정한다.)
onsubmit이 처리되면 그 다음에 action으로 이동한다.
<보안 강화 수정 부분>Prepared Statement 사용 전 기존의 시큐어 코딩을 적용하기 전에는 PostID의 값을 그대로 받아왔지만, Prepared Statement 사용 후
시큐어 코딩을 적용한 후에는 PostID의 값을 그대로 받아오지 않는다.
게시판 글 수정한 데이터를 데이터베이스에 반영 PHP
(notice_edit2.php)
-> "수정하시겠습니까?" 에서 확인 버튼을 누르면 해당 php로 데이터 값을 넘겨준다.
넘겨받은 값이 정상적으로 수정되었는지 확인
<?php
session_start();
if(!isset($_SESSION['UserID'])) {
echo "<script>alert ('로그인이 필요합니다');</script>";
echo "<script>location.href='login2.php';</script>";
exit;
}
?>
<?php
include "dbconn2.php";
//입력값 검증
if(isset($_POST['PostID'], $_POST['title'], $_POST['content']) && is_numeric($_POST['PostID'])){
$PostID = $_POST['PostID'];
$title = $_POST['title'];
$content = $_POST['content'];
$now = date('Y-m-d H:i:s');
//데이터 필터링(XSS 방지)
$title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
$content = htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
//prepared statement 사용
try{
$stmt = $conn->prepare("UPDATE $table SET Title=?, Content=?, CreatedDate=? WHERE PostID=?");
$stmt->execute([$title, $content, $now, $PostID]);
//업데이트 성공 시
if($stmt->rowCount()>0) {
echo "<script>alert('변경되었습니다.');</script>";
} else {
echo "<script>alert('변경된 내용이 없습니다.');</script>";
}
} catch(PDOException $e) {
//SQL 오류처리
echo "<sctipt>alert('오류 발생: ".htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8')."');</script>";
}
echo "<script>location.href='notice_list2.php';</script>";
} else {
echo "<script>alert('잘못된 요청입니다.');</script>";
echo "<script>location.href='notice_list2.php';</script>";
}
$conn = null;
?>
보안 강화 수정 부분
- htmlspecialchars( ) 함수를 사용하여 문자열에서 특정한 특수 문자를 HTML 엔티티로 변환한다.
데이터베이스에서 가져온 데이터를 HTML로 출력할 때 발생할 수 있는 XSS 공격을 방지
<실행 결과>수정된 내용(제목, 내용, 시간, 글 번호)이 있으면 "변경되었습니다." 메시지 창을 띄우고
수정된 내용이 없으면 "변경된 내용이 없습니다." 메시지 창을 띄운다.수정된 내용을 게시판 메인 화면에서 확인하고, 데이터베이스에서도 확인한다.
게시글 삭제 PHP
(delete2.php)
<?php
session_start();
if(!isset($_SESSION['UserID'])) {
echo "<script>alert ('로그인이 필요합니다');</script>";
echo "<script>location.href='login2.php';</script>";
exit;
}
?>
<?php
include "dbconn2.php";
if(isset($_GET['PostID']) && is_numeric($_GET['PostID'])) {
$PostID = $_GET['PostID'];
//prepared statement 사용
try{
$stmt = $conn->prepare("delete from $table where PostID=?");
$stmt->execute([$PostID]);
//삭제 성공 시
if($stmt->rowCount()>0){
echo "<script>alert('삭제되었습니다.');</script>";
} else {
echo "<script>alert('삭제할 항목이 없습니다.');</script>";
}
} catch(PDOException $e) {
//SQL 오류 처리
echo "<script>alert('오류 발생: ".htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8')."');</script>";
}
} else {
//입력값이 없거나 유효하지 않은 경우
echo "<script>alert('잘못된 요청입니다.');</script>";
}
echo "<script>location.href='notice_list2.php';</script>";
$conn = null;
?>
보안 강화 수정 부분
- if문과 try~catch문을 활용하여 오류 처리 작업을 하였다.
<실행 결과>삭제 버튼을 누르면
alert('삭제되었습니다.')
메시지 창이 뜬다.해당 게시글이 삭제된 것을 확인할 수 있다.
'자료' 카테고리의 다른 글
kubenetes 서비스 노출과 버전 업데이트 (0) | 2024.10.04 |
---|---|
추가 보안 적용 (0) | 2024.09.20 |
추가 보안 적용 (Ubuntu) (0) | 2024.09.17 |
<추가자료>시큐어 코딩이 적용되지 않은 회원가입 페이지 Ubuntu (Apache, PHP, MySQL) (0) | 2024.09.05 |
시큐어 코딩이 적용되지 않은 게시판 만들기 Window (HTTP, PHP, SQL Server) (0) | 2024.09.04 |