SW/서버보안

웹페이지 공격 방어용 연습용 홈페이지 만들기 귀찮아서 작성해두자

bigju 2025. 7. 22. 10:49
반응형

1. 홈페이지 구조

 

/var/www/html/bigju/
├── index.php         (메인 화면: BIGJU 공부 페이지 + 회원가입/로그인/게시판 버튼)
├── register.php      (회원가입)
├── login.php         (로그인)

├── logout.php         (로그아웃)
├── board.php         (게시판 목록)
├── write.php         (글쓰기 + 파일 업로드 + 글 비밀번호)
├── view.php          (게시글 보기)
├── uploads/          (업로드 파일 저장 폴더)
├── db.php            (DB 연결 파일)
└── table.sql         (DB 테이블 생성 스크립트)

 

2.DB 정보

 

  • DB: bigju
  • 계정: root
  • 비밀번호: 1234
  • 테이블: users, posts

3. DB 생성 및 테이블 만들기

 

mysql -u root -p

 

CREATE DATABASE bigju;
USE bigju;

-- users 테이블
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) UNIQUE,
    password VARCHAR(255),
    email VARCHAR(100)
);

-- posts 테이블
CREATE TABLE posts (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255),
    content TEXT,
    filename VARCHAR(255),
    password VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);


------

외부 접속 허용
ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('1234');
FLUSH PRIVILEGES;

 

 

4.PHP파일 코드

 

db.php

<?php
$host = "localhost";
$user = "root";
$pass = "1234";
$dbname = "bigju";

$conn = new mysqli($host, $user, $pass, $dbname);

if ($conn->connect_error) {
    die("DB 연결 실패: " . $conn->connect_error);
}
?>

 

 

5. index.php

<?php
session_start();
// 세션 유지 시간 (초) ? 예: 30분 = 1800초
$timeout = 180; 

// 마지막 활동 시간 저장 또는 갱신
if (isset($_SESSION['LAST_ACTIVITY'])) {
    // 현재 시간과 마지막 활동 시간 차이 계산
    if (time() - $_SESSION['LAST_ACTIVITY'] > $timeout) {
        // 타임아웃 시 세션 종료 및 강제 로그아웃
        session_unset();
        session_destroy();
        header("Location: login.php?timeout=1"); // 원하는 페이지로 리다이렉트
        exit;
    }
}
// 마지막 활동 시간 업데이트
$_SESSION['LAST_ACTIVITY'] = time();

?>


<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>BIGJU 공부 페이지</title>
    <style>
        body { text-align: center; margin-top: 100px; font-size: 20px; }
        h1 { font-size: 40px; }
        a { display: block; margin: 20px; font-size: 24px; }
    </style>
</head>
<body>
    <h1>BIGJU 공부 페이지</h1>

    <?php if(isset($_SESSION['user'])): ?>
        <p><strong><?= htmlspecialchars($_SESSION['user']) ?></strong> 님 환영합니다!</p>
        <a href="board.php">게시판</a>
        <a href="logout.php">로그아웃</a>
    <?php else: ?>
        <a href="register.php">회원가입</a>
        <a href="login.php">로그인</a>
    <?php endif; ?>

</body>
</html>

 

6. register.php

include 'db.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $username = $_POST['username'];
                $password = password_hash($_POST['password'], PASSWORD_DEFAULT);
                $email = $_POST['email'];

                    $stmt = $conn->prepare("INSERT INTO users (username, password, email) VALUES (?, ?, ?)");
                    $stmt->bind_param("sss", $username, $password, $email);
                        $stmt->execute();

                        echo "<script>alert('회원가입 완료!'); location.href='index.php';</script>";
}
?>

<form method="post">
    <h2>회원가입</h2>
    아이디: <input type="text" name="username" required><br>
    비밀번호: <input type="password" name="password" required><br>
    이메일: <input type="email" name="email" required><br>
    <button type="submit">가입하기</button>
</form>

 

7. login.php

<?php
include 'db.php';
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $username = $_POST['username'];
                $password = $_POST['password'];

                $stmt = $conn->prepare("SELECT * FROM users WHERE username=?");
                    $stmt->bind_param("s", $username);
                    $stmt->execute();
                        $result = $stmt->get_result();
                        $user = $result->fetch_assoc();

                            if ($user && password_verify($password, $user['password'])) {
                                            $_SESSION['user'] = $username;
                                                    echo "<script>alert('로그인 성공!'); location.href='index.php';</script>";
                                                } else {
                                                                echo "<script>alert('로그인 실패!'); history.back();</script>";
                                                                    }
}
?>

<form method="post">
    <h2>로그인</h2>
    아이디: <input type="text" name="username" required><br>
    비밀번호: <input type="password" name="password" required><br>
    <button type="submit">로그인</button>
</form>

 

8.logout.php 

<?php
session_start();
session_destroy();
echo "<script>alert('로그아웃되었습니다.'); location.href='index.php';</script>";

 

9. board.php (게시판 목록)

<?php
session_start();

if (!isset($_SESSION['user'])) {
            echo "<script>alert('로그인 후 이용하세요.'); location.href='login.php';</script>";
                exit;
}

include 'db.php';
$result = $conn->query("SELECT * FROM posts ORDER BY id DESC");
?>

<h2>게시판</h2>
<a href="write.php">글쓰기</a>
<table border="1" width="600">
    <tr><th>번호</th><th>제목</th><th>작성일</th></tr>
    <?php while($row = $result->fetch_assoc()): ?>
    <tr>
        <td><?= $row['id'] ?></td>
        <td><a href="view.php?id=<?= $row['id'] ?>"><?= htmlspecialchars($row['title']) ?></a></td>
        <td><?= $row['created_at'] ?></td>
    </tr>
    <?php endwhile; ?>
</table>

 

10. write.php (글쓰기)

<?php
include 'db.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $title = $_POST['title'];
    $content = $_POST['content'];
    $password = password_hash($_POST['post_password'], PASSWORD_DEFAULT);

    $upload_dir = "uploads/";
    if (!is_dir($upload_dir)) mkdir($upload_dir);

    $file_to_save = '';

    if (isset($_FILES['file']) && $_FILES['file']['error'] === 0) {
        $ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
        $new_file_name = uniqid('file_', true) . '.' . $ext;

        if (move_uploaded_file($_FILES['file']['tmp_name'], $upload_dir . $new_file_name)) {
            $file_to_save = $new_file_name;
        } else {
            echo "<script>alert('파일 업로드 실패! 폴더 권한 및 파일명을 확인하세요.'); history.back();</script>";
            exit;
        }
    }

    $stmt = $conn->prepare("INSERT INTO posts (title, content, filename, password) VALUES (?, ?, ?, ?)");
    $stmt->bind_param("ssss", $title, $content, $file_to_save, $password);
    $stmt->execute();

    echo "<script>alert('글 작성 완료!'); location.href='board.php';</script>";
}
?>

<form method="post" enctype="multipart/form-data">
    제목: <input type="text" name="title" required><br>
    내용: <textarea name="content" required></textarea><br>
    파일업로드: <input type="file" name="file"><br>
    글 비밀번호: <input type="password" name="post_password" required><br>
    <button type="submit">작성하기</button>
</form>

 

11. view.php (게시글 보기)

<?php
include 'db.php';

$id = (int)$_GET['id'];  // 보안: int형으로 강제 캐스팅
$post = $conn->query("SELECT * FROM posts WHERE id=$id")->fetch_assoc();

echo "<h2>" . htmlspecialchars($post['title']) . "</h2>";
echo "<p>" . nl2br(htmlspecialchars($post['content'])) . "</p>";

if ($post['filename']) {
    $file = htmlspecialchars($post['filename']);
    $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
    $img_types = ['jpg', 'jpeg', 'png', 'gif', 'webp'];

    if (in_array($ext, $img_types)) {
        // 이미지 파일이면 썸네일과 링크
        echo "<p><a href='uploads/$file' target='_blank' rel='noopener noreferrer'>
                <img src='uploads/$file' style='max-width:300px; height:auto;'></a></p>";
    }
    // 다운로드 링크는 공통으로 표시
    echo "<p>첨부파일: <a href='uploads/$file' download>$file</a></p>";
}
?>

12. delete.php ( 게시글 삭제 가능)

<?php
session_start();

if (!isset($_SESSION['user']) || $_SESSION['user'] !== 'bigju') {
    echo "<script>alert('권한이 없습니다.'); location.href='index.php';</script>";
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    include 'db.php';

    $id = (int)$_POST['id'];

    // 삭제할 게시물 정보 조회 (첨부파일 있으면 삭제 위해)
    $stmt = $conn->prepare("SELECT filename FROM posts WHERE id = ?");
    $stmt->bind_param("i", $id);
    $stmt->execute();
    $result = $stmt->get_result();
    $post = $result->fetch_assoc();

    if ($post) {
        // 첨부파일이 있으면 파일 삭제
        if ($post['filename'] && file_exists("uploads/" . $post['filename'])) {
            unlink("uploads/" . $post['filename']);
        }

        // 게시물 삭제
        $del = $conn->prepare("DELETE FROM posts WHERE id = ?");
        $del->bind_param("i", $id);
        $del->execute();

        echo "<script>alert('게시물이 삭제되었습니다.'); location.href='board.php';</script>";
        exit;
    } else {
        echo "<script>alert('게시물을 찾을 수 없습니다.'); location.href='board.php';</script>";
        exit;
    }
} else {
    header("Location: board.php");
    exit;
}

12. 폴더 권한 설정

sudo mkdir /var/www/html/bigju/uploads
sudo chmod 777 /var/www/html/bigju/uploads
sudo chown -R www-data:www-data /var/www/html/bigju

sudo mkdir /var/www/html/bigju
sudo chown -R www-data:www-data /var/www/html/bigju
sudo chmod -R 755 /var/www/html/bigju

 

 

반응형