락키 스터디 2주차

gyeong·2026년 9월 23일

lockey_study

목록 보기
2/3

[락키 스터디 2주차] AI로 PHP 사이트 만들고 스스로 보안 점검해보기

본 글은 보안 스터디 교육 목적으로, 본인이 만든 사이트에서만 점검·수정한 기록입니다.

TL;DR

  • claude AI로 php+MySQL (로그인/게시판/업로드) 사이트를 만들어 무료 호스팅에 배포했다.
  • 보안 점검 5대 관점으로 스스로 훑어 3를 찾았고, 그중 3개를 패치했다.
  • 느낀 점 한 줄: 대부분의 취약점이 생각보다 잘 막혀있어서 좋으면서도 당황스러웠다. 그래도 몇개정도는 남아있을줄 알았는제 거의 막혀있어서 정말 막막했다.

1. 무엇을 만들었나

  • 사이트 주제 / 기능
    : 게시판 사이트. / 로그인, 글(작성,수정,삭제),프로필(사진업로드포함),관리자페이지
  • 스택: PHP + MySQL (mysqli), InfinityFree
  • 사용한 AI와 핵심 프롬프트:
  PHP와 MySQL로 간단한 회원 게시판 웹사이트를 만들어줘.
-회원가입, 로그인/로그아웃
-게시글 목록, 글쓰기, 글 상세보기
-프로필 사진 업로드(마이페이지)
조건:
-InfinityFree 무료 호스팅에서 동작해야 해 (PHP 8, MySQL, mysqli 사용)
-DB 접속 정보는 config.php 한 파일에 모아줘 (host, user, password, dbname)
-각 파일이 htdocs에 올리면 바로 되게, 설치 절차도 알려줘
-테이블 생성용 SQL도 같이 줘 (phpMyAdmin에 붙여넣게)
  • 화면 캡처 (URL 표시줄은 가리기)

2. 배포하면서 막힌 점

  • 문제 → 해결:
    AI가 설명하는데로 따라갔더니 크게 막히는 부분은 없이 배포가 가능했습니다.

3. 5대 관점 셀프 점검

#관점확인 결과조치
1입력검증 (SQLi/XSS)패치
2인증/세션패치
3접근제어
4파일업로드
5설정/노출

공방전이 끝날 때까지 미패치 항목은 비워 두고, S4 이후 업데이트합니다.

4. 패치 기록 (3개)

4-1. secure 속성

  • 문제: 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();
    }
    
  • 확인:

4-2.

  • 문제: 새로운 글 입력 시 토큰 미사용

  • 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

4-3.

  • 문제: 게시글 삭제 요청을 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>
`` - 확인:
  1. GET 방식으로만 삭제하던 것을 POST 방식으로 삭제.

  2. 삭제 전 CSRF 토큰 검증 추가

  3. 실제 본인 맞는지 확인

  4. burp suit를 이용해 삭제 요청을 잡아 확인해보면 아래와 같이 csrf 토큰이 추가된것을 알 수 있다

5. AI가 짠 코드에서 느낀 점

  • AI가 기본으로 놓친 것 / 잘한 것:
    CSRF 토큰을 사용하지 않아 CSRF 공격이 가능했다.
    일반적으로 알려진 대부분의 취약점은 모두 적절하게 방어되어 있었다.
    예상보다 보안 설정이 잘 되어있어 취약점을 추가로 발견하는 과정이 어려웠다.
  • 다음에 AI에게 요청할 때 바꿀 점:
    코드의 어느 부분에서 취약점 발생 가능성이 있는지와 해당 코드를 어떻게 수정하여 방어할 수 있는지를 초보자도 이해하기 쉬운 방식으로 설명해 달라고 요청하고 싶다.

6. 다음 주

  • 공방전 1차(공격) — 남의 사이트에서 무엇을 찾아볼지

0개의 댓글