본 글은 보안 스터디 교육 목적으로, 본인이 만든 사이트에서만 점검·수정한 기록입니다.
PHP와 MySQL로 간단한 회원 게시판 웹사이트를 만들어줘.
-회원가입, 로그인/로그아웃
-게시글 목록, 글쓰기, 글 상세보기
-프로필 사진 업로드(마이페이지)
조건:
-InfinityFree 무료 호스팅에서 동작해야 해 (PHP 8, MySQL, mysqli 사용)
-DB 접속 정보는 config.php 한 파일에 모아줘 (host, user, password, dbname)
-각 파일이 htdocs에 올리면 바로 되게, 설치 절차도 알려줘
-테이블 생성용 SQL도 같이 줘 (phpMyAdmin에 붙여넣게)

| # | 관점 | 확인 결과 | 조치 |
|---|---|---|---|
| 1 | 입력검증 (SQLi/XSS) | 패치 | |
| 2 | 인증/세션 | 패치 | |
| 3 | 접근제어 | ||
| 4 | 파일업로드 | ||
| 5 | 설정/노출 |
공방전이 끝날 때까지 미패치 항목은 비워 두고, S4 이후 업데이트합니다.
문제: secure 속성 설정 X
Before
if (session_status() === PHP_SESSION_NONE) {
session_start();
After
if (session_status() === PHP_SESSION_NONE) {
session_set_cookie_params([
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
session_start();
}
확인: 
문제: 새로운 글 입력 시 토큰 미사용
Before
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = trim($_POST['title'] ?? '');
$content = trim($_POST['content'] ?? '');
(중략)
<form method="post" class="form-box">
<label>제목</label>
<input type="text" name="title" value="<?php echo h($title); ?>" required>
<label>내용</label>
<textarea name="content" rows="10" required><?php echo h($content); ?></textarea>
<button type="submit">등록</button>
</form>
After
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!hash_equals(
$_SESSION['csrf'] ?? '',
$_POST['csrf'] ?? ''
)) {
http_response_code(403);
exit('CSRF 검증 실패');
}
$title = trim($_POST['title'] ?? '');
$content = trim($_POST['content'] ?? '');
(중략)
session_start();
$_SESSION['csrf'] ?? = bin2hex(random_bytes(32))
?>
<form method="post" class="form-box">
<input type="hidden"
name="csrf"
value="<?= htmlspecialchars($_SESSION['csrf'], ENT_QUOTES, 'UTF-8') ?>">
<label>제목</label>
<input type="text" name="title" value="<?= h($title) ?>" required>
<label>내용</label>
<textarea name="content" rows="10" required><?= h($content) ?></textarea>
<button type="submit">등록</button>
</form>
확인: 메모장에 새로운 글을 강제로 추가하는 코드를 만들어 열어도 새로운 글 추가X
문제: 게시글 삭제 요청을 GET방식으로 처리
Before
if (isset($_GET['delete']) && is_logged_in() && (int)$_SESSION['user_id'] === (int)$post['user_id']) {
$del = mysqli_prepare($conn, "DELETE FROM posts WHERE id = ? AND user_id = ?");
mysqli_stmt_bind_param($del, "ii", $id, $_SESSION['user_id']);
mysqli_stmt_execute($del);
mysqli_stmt_close($del);
header("Location: index.php");
exit;
}
(중략)
<?php if (is_logged_in() && (int)$_SESSION['user_id'] === (int)$post['user_id']): ?>
<p>
<a href="view.php?id=<?php echo $id; ?>&delete=1"
onclick="return confirm('정말 삭제하시겠습니까?');">삭제</a>
</p>
<?php endif; ?>
After
if (isset($_POST['delete']) && is_logged_in() &&
(int)$_SESSION['user_id'] === (int)$post['user_id']) {
if (!hash_equals(
$_SESSION['csrf'] ?? '',
$_POST['csrf'] ?? ''
)) {
http_response_code(403);
exit('CSRF 검증 실패');
}
$del = mysqli_prepare(
$conn,
"DELETE FROM posts WHERE id = ? AND user_id = ?"
);
mysqli_stmt_bind_param(
$del,
"ii",
$id,
$_SESSION['user_id']
);
mysqli_stmt_execute($del);
mysqli_stmt_close($del);
header("Location: index.php");
exit;
}
(중략)
<form method="post"
action="view.php?id=<?php echo $id; ?>"
onsubmit="return confirm('정말 삭제하시겠습니까?');">
<input type="hidden"
name="csrf"
value="<?= htmlspecialchars($_SESSION['csrf'], ENT_QUOTES, 'UTF-8') ?>">
<button type="submit" name="delete" value="1">삭제</button>
GET 방식으로만 삭제하던 것을 POST 방식으로 삭제.
삭제 전 CSRF 토큰 검증 추가
실제 본인 맞는지 확인
burp suit를 이용해 삭제 요청을 잡아 확인해보면 아래와 같이 csrf 토큰이 추가된것을 알 수 있다
