[7. 불충분한 인가]

Minseok Jo·2026년 8월 25일

웹 시큐어코딩

목록 보기
7/11
post-thumbnail

웹취약점 점검에서 개발한 웹에 대하여 점검을 진행하였고, 여러 취약점들을 발견하였다.
발견한 취약점들을 대상으로 시큐어 코딩을 진행하고자 한다.

이번 대상은 주요정보통신기반시설 분석·평가 가이드 17번 항목 - 불충분한 인가 이다.

불충분한 인가 취약점이 발견된 항목은 다음과 같다.

URL파라미터메뉴
http://jmseok.com/web/board/freeedit_proc.phpnum자유게시판 >
게시글 수정
http://jmseok.com/web/board/free_edit.phpnum자유게시판 >
게시글 삭제
http://jmseok.com/web/board/memedit_proc.phpnum회원게시판 >
게시글 수정
http://jmseok.com/web/board/mem_edit.phpnum회원게시판 >
게시글 삭제
http://jmseok.com/web/board/comment_delete.phpcomment_id회원게시판 >
댓글 삭제

0. 불충분한 인가 대응방안

서버 측 인가 검증 수행
▷ 접근 제어가 필요한 모든 요청에 대하여, 사용자의 인증 상태 및 권한을 서버 측에서 검증


1. 시큐어 코딩

[1. 자유게시판 - 게시글 수정]

흐름 정리
1. free_edit.php 에서 게시글 수정 요청 → 해당 게시글의 비밀번호를 함께 전송하도록 로직 추가
2. freeedit_proc.php → 전달받은 비밀번호와, 게시글 작성시 설정된 비밀번호를 비교하는 로직 추가


① 게시글 수정 페이지 - 게시글 비밀번호 전송 추가

// free_edit.php

<form class="edit-form" method="post" action="freeedit_proc.php">
    <input type="hidden" id="num" name="num" value="<?php echo $num?>">
    <input type="hidden" name="input_pass" value="<?php echo $input_pass?>">

    <div class="edit-row">
        <label for="input_title">제목 <i class="fa-solid fa-pen-to-square"></i></label>
        <input id="input_title" name="input_title" type="text" value="<?php echo $title ?>">
    </div>

    <div class="edit-row">
        <label>작성자명</label>
        <input type="text" value="<?php echo $writer ?>" disabled>
    </div>

    <label for="input_cont">본문 <i class="fa-solid fa-pen-to-square"></i></label>
    <textarea id="input_cont" name="input_cont"><?php echo $content ?></textarea>

    <div class="edit-actions">
        <input type="submit" value="수정 완료">
        <input type="button" onclick="location.href='free_view.php?num=<?php echo $num?>'" value="뒤로가기">
    </div>
</form>
  • 사용자가 입력한 비밀번호를, hidden 태그에 포함시켜 처리 페이지로 전달

② 게시글 수정 처리 페이지 - 비밀번호 검증 로직 추가

// freeedit_proc.php (일부)

$num = $_POST["num"];
$input_pass = $_POST["input_pass"];
$input_title = $_POST["input_title"];
$input_cont = $_POST["input_cont"];

$sql = "SELECT password FROM freeboard WHERE num = ?";
$stmt = mysqli_prepare($con, $sql);
mysqli_stmt_bind_param($stmt, "i", $num);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
$row = mysqli_fetch_assoc($result);
mysqli_stmt_close($stmt);

if (!$row) {
    echo "<script>
        alert('잘못된 요청입니다.');
        history.go(-1);
    </script>";
    exit;
}

$db_pass = $row["password"];
if ($db_pass != $input_pass) {
    echo "<script>
        alert('비밀번호가 일치하지 않습니다.');
        history.go(-1);
    </script>";
    exit;
}
  • 게시글 수정 처리 페이지에서, 전달받은 비밀번호와 게시글 작성시 입력된 비밀번호를 비교
  • num 파라미터를 변하여도, 비밀번호를 추가로 검증하기 때문에 타 게시물 삭제 불가능

[2. 자유게시판 - 게시글 삭제]

"자유게시판 - 게시글 삭제" 에서의 불충분한 인가 취약점은, IDOR + SQL Injection을 통해 수행되었다.
따라서 SQL Injection이 불가능하도록 Prepared Statement를 적용함으로써 불충분한 인가 취약점을 제거하였다.
▷ 해당 코드의 경우, 코드 구성상 SQL Injection을 막는 것만으로도 인가 취약점이 제거되었다.
  만약 [자유게시판 - 게시글 수정]과 같이 게시글 삭제 페이지를 별도로 구성한 경우, 바로 앞서 작성한 것처럼 똑같이 비밀번호 검증로직을 추가해주면 된다.

// free_edit.php (일부)

<?php
  $num = $_POST["num"];
  $input_pass = $_POST["input_pass"];
  $type = $_POST["type"];

  if (empty($input_pass) or !ctype_digit($input_pass) or strlen($input_pass)!=4) {
      echo "<script>
          alert('비밀번호 숫자 4자리를 입력해주세요');
          history.go(-1);
      </script>";
      exit;
  }

  include "../db/db_con.php";

  $sql = "select * from freeboard where num= ? and password= ?";
  $stmt = mysqli_prepare($con, $sql);
  mysqli_stmt_bind_param($stmt, "ii", $num, $input_pass);
  mysqli_stmt_execute($stmt);
  $result = mysqli_stmt_get_result($stmt);
  $row = mysqli_fetch_assoc($result);
  mysqli_stmt_close($stmt);

  if (!$row) {
      echo "<script>
          alert('비밀번호가 일치하지 않습니다');
          history.go(-1);
      </script>";
      exit;
  }
?>
  • Prepared Statement 를 적용하여 SQL Injection을 막음으로써, 불충분한 인가 취약점도 조치 완료

[3. 회원게시판 - 게시글 수정]

// memedit_proc.php (일부)
$num = $_POST["num"];
$sql = "delete from memboard where num = ? and user_id = ?";
$stmt = mysqli_prepare($con, $sql);

mysqli_stmt_bind_param($stmt, "is", $num, $_SESSION["user_id"]);
mysqli_stmt_execute($stmt);

if (mysqli_stmt_affected_rows($stmt) === 0) {
    echo "<script>
        alert('권한이 없습니다.');
        history.go(-1);
    </script>";
    exit;
}
  • 전달받은 게시글 번호 파라미터(num)를 조회하여, 해당 게시글의 작성자와 현재 세션의 사용자를 비교하는 로직 추가


[4. 회원게시판 - 게시글 삭제]

(기존)

// mem_edit.php (일부)

if ($type == "delete") {
    if (!empty($file_copy)) {
        $filepath = "../uploads/".$file_copy;
        unlink($filepath);
    }

    $sql = "delete from memboard where num = $num";
    mysqli_query($con, $sql);
    echo "<script>
        alert('게시글이 삭제되었습니다');
        location.href='./mem_list.php';
    </script>";
    exit;
}
  • 권한 검사 없이, 전달받은 num 파라미터만으로 게시글 삭제 수행

(수정 후)

if ($type == "delete") {
    if (!empty($file_copy)) {
        $filepath = "../uploads/".$file_copy;
        unlink($filepath);
    }

    $sql = "delete from memboard where num = ? and user_id = ?";
    $stmt = mysqli_prepare($con, $sql);
    mysqli_stmt_bind_param($stmt, "is", $num, $_SESSION["user_id"]);
    mysqli_stmt_execute($stmt);

    if (mysqli_stmt_affected_rows($stmt) === 0) {
        echo "<script>
            alert('권한이 없습니다.');
            history.go(-1);
        </script>";
        exit;
    }

    mysqli_stmt_close($stmt);

    echo "<script>
        alert('게시글이 삭제되었습니다');
        location.href='./mem_list.php';
    </script>";
    exit;
}
  • 사용자 id를 기반으로, 권한 검사 로직 추가

[5. 회원게시판 - 댓글 삭제]

(기존)

// comment_delete.php (일부)

$comment_id = $_GET["comment_id"];
$board_num = $_GET["board_num"];

$sql = "delete from comment where id = $comment_id and board_num = $board_num";
mysqli_query($con, $sql);
  • 댓글을 삭제하는 사용자에 대한, 권한 로직 부재

(수정 후)

$comment_id = $_GET["comment_id"];
$board_num = $_GET["board_num"];

$sql = "select * from comment where id = $comment_id and board_num = $board_num";
$result = mysqli_query($con, $sql);
$row = mysqli_fetch_assoc($result);
$user_id = $row["user_id"];

if ($user_id != $_SESSION["user_id"]) {
    echo "<script>
        alert('권한이 없습니다.');
        history.go(-1);
    </script>";
    exit;
}

$sql = "delete from comment where id = $comment_id and board_num = $board_num";
mysqli_query($con, $sql);
  • 댓글을 작성한 사용자와 현재 사용자 간의 일치 여부 검증 로직 추가

2. 보안 조치 결과

불충분한 인가
num 파라미터를 변조하여도, 권한 여부를 검사하여 요청 거부


0개의 댓글