작성
·
26
0
action.php
<?
@session_start();
header("Content-Type: text/html; charset=UTF-8");
include ( './common.php' );
# CSRF Token 검증 로직
$csrf_token_session = $_SESSION["csrf_token"];
$csrf_token_param = $_REQUEST["csrf_token"];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$csrf_token_session = $_SESSION["csrf_token"];
$csrf_token_param = $_REQUEST["csrf_token"];
// CSRF 토큰 검증
if (empty($csrf_token_session) && empty($csrf_token_param) || $csrf_token_param != $csrf_token_session) {
echo "<script>alert('정상적인 접근이 아닙니다.');history.back(-1);</script>";
exit();
}
}
$mode = $_REQUEST["mode"];
$db_conn = mysql_conn();
if($mode == "write") {
$title = xss_html_entity($db_conn->real_escape_string($_POST["title"]));
$id = $db_conn->real_escape_string($_SESSION["id"]);
$writer = xss_html_entity($db_conn->real_escape_string($_SESSION["name"]));
$password = $db_conn->real_escape_string($_POST["password"]);
$content = $db_conn->real_escape_string($_POST["content"]);
$secret = $_POST["secret"];
$uploadFile = "";
if(empty($title) || empty($password) || empty($content)) {
echo "<script>alert('빈칸이 존재합니다.');history.back(-1);</script>";
exit();
}
if(!empty($_FILES["userfile"]["name"])) {
$uploadFile = $_FILES["userfile"]["name"];
$uploadPath = "{$upload_path}/{$uploadFile}";
if(!(@move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadPath))) {
echo("<script>alert('파일 업로드를 실패 하셨습니다.');history.back(-1);</script>");
exit;
}
}
if($secret == "on") {
$secret = "y";
} else {
$secret = "n";
}
$uploadfile = $db_conn->real_escape_string($uploadFile);
$content = str_replace("\\r\\n", "<br>", $content);
$query = "insert into {$tb_name}(title, id, writer, password, content, file, secret, regdate) values('{$title}', '{$id}', '{$writer}', '{$password}', '{$content}', '{$uploadFile}', '{$secret}', now())";
$db_conn->query($query);
} else if($mode == "modify") {
$idx = $_POST["idx"];
$title = xss_html_entity($db_conn->real_escape_string($_POST["title"]));
$password = $db_conn->real_escape_string($_POST["password"]);
$content = xss_html($db_conn->real_escape_string($_POST["content"]));
$secret = $_POST["secret"];
$uploadFile = xss_html_entity($_POST["oldfile"]);
if(!is_numeric($idx)){
echo "<script>alert('숫자 값만 가능합니당.');history.back(-1);</script>";
exit();
}
if(empty($idx) || empty($title) || empty($password) || empty($content)) {
echo "<script>alert('빈칸이 존재합니다.');history.back(-1);</script>";
exit();
}
# Password Check Logic
#$query = "select * from {$tb_name} where idx={$idx} and password='{$password}'";
$query = "select * from {$tb_name} where idx={$idx} and id='{$_SESSION["id"]}'";
$result = $db_conn->query($query);
$num = $result->num_rows;
if($num == 0) {
#echo "<script>alert('패스워드가 일치하지 않습니다.');history.back(-1);</script>";
echo "<script>alert('잘못된 요청입니다.');history.back(-1);</script>";
exit();
}
if(!empty($_FILES["userfile"]["name"])) {
$uploadFile = $_FILES["userfile"]["name"];
$uploadPath = "{$upload_path}/{$uploadFile}";
if(!(@move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadPath))) {
echo("<script>alert('파일 업로드를 실패 하셨습니다.');history.back(-1);</script>");
exit;
}
}
if($secret == "on") {
$secret = "y";
} else {
$secret = "n";
}
$content = str_replace("\\r\\n", "<br>", $content);
$uploadFile = $db_conn->real_escape_string($uploadFile);
$query = "update {$tb_name} set title='{$title}', content='{$content}', file='{$uploadFile}', secret='{$secret}', regdate=now() where idx={$idx}";
$db_conn->query($query);
} else if($mode == "delete") {
$idx = $_GET["idx"];
$password = $db_conn->real_escape_string($_POST["password"]);
if(!is_numeric($idx)){
echo "<script>alert('숫자 값만 가능합니당.');history.back(-1);</script>";
exit();
}
# Password Check Logic
#$query = "select * from {$tb_name} where idx={$idx} and password='{$password}'";
$query = "select * from {$tb_name} where idx={$idx} and id='{$_SESSION["id"]}'";
$result = $db_conn->query($query);
$num = $result->num_rows;
if($num == 0) {
#echo "<script>alert('패스워드가 일치하지 않습니다.');history.back(-1);</script>";
echo "<script>alert('잘못된 요청입니다.');history.back(-1);</script>";
exit();
}
$query = "delete from {$tb_name} where idx={$idx}";
$db_conn->query($query);
}
echo "<script>location.href='index.php';</script>";
$db_conn->close();
?>
write.php
<div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-4">Write Page</h1>
<hr>
</div>
<div class="container">
<form action="action.php" method="POST" enctype="multipart/form-data">
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" name="title" placeholder="Title Input">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" class="form-control" name="password" placeholder="Password Input">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Contents</label>
<textarea class="form-control" name="content" rows="5" placeholder="Contents Input"></textarea>
</div>
<div class="form-group">
<label for="exampleInputPassword1">File</label>
<input type="file" class="form-control" name="userfile">
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="customCheck1" name="secret">
<label class="custom-control-label" for="customCheck1">Secret Post</label>
</div>
<div class="text-right">
<input type="hidden" name="csrf_token" value="<?=$csrf_token?>">
<input type="hidden" name="mode" value="write">
<button type="submit" class="btn btn-outline-secondary">Write</button>
<button type="button" class="btn btn-outline-danger" onclick="history.back(-1);">Back</button>
</div>
</form>
</div>
해커 계정으로 게시물 작성하려고 하는데
정상적인 접근이 아니라는 팝업이 뜹니다.
강의대로 코드 작성해도 그렇고 위처럼 수정했을 때도 그렇습니다.
답변 1
0
안녕하세요, 인프런 AI 인턴입니다.
hsoing00님께서 올려주신 PHP 코드를 살펴본 결과, “정상적인 접근이 아닙니다”라는 경고 창이 표시되는 이유로는 CSRF 토큰 검증 로직에서 주로 발생할 수 있습니다. 다음과 같은 부분을 확인해보시는 것이 좋을 것 같습니다:
세션에 저장된 CSRF 토큰: $_SESSION["csrf_token"]
값이 실제로 세션에 잘 저장되고 있는지 확인해주세요. write.php
에서 세션에 설정하고, action.php
에서 해당 값을 호출하기 때문에 작성 및 실행 환경에서 세션이 잘 설정되었는지를 우선 확인해야 합니다.
CSRF 토큰 전송: <input type="hidden" name="csrf_token" value="<?=$csrf_token?>">
부분에서 <?php echo $_SESSION["csrf_token"]; ?>
로 설정한 CSRF 토큰이 write.php
에 정상적으로 표시 및 전송되고 있는지 확인해주세요. 이는 PHP 세션에서 토큰 값을 가져와 출력하는 것이기 때문에 소스 파악이 필요합니다.
POST 요청: action.php
에서 CSRFTOKEN
관련 검증은 POST 요청일 경우에만 수행됩니다. 실제로 write.php
에서 요청이 POST로 잘 이뤄지는지도 확인해야 합니다.
세션 시작: @session_start();
부분이 모든 페이지에 적절하게 적용되고 있는지 확인해주세요. 세션이 효율적으로 초기화되지 않으면 CSRF 토큰 검증에 실패할 수 있습니다.
위와 같은 사항들을 확인 후에도 문제가 지속된다면, 코드 전체 흐름에 맞게 세션 및 요청 처리를 다시 검토할 필요가 있을 것 같습니다.
추가로, CSRF 관련 보다 자세한 보안 정보를 확인하고 싶으시면 Spring Security Reference Guide에서 관련 내용을 찾아보실 수 있습니다.
계속해서 문제가 발생된다면 추가적인 환경 정보나 테스트 결과를 공유해 주시면 보다 상세히 도움을 드리도록 하겠습니다.