From 873839add7c8e1647ab6c67143467642d9e06344 Mon Sep 17 00:00:00 2001 From: whitedot Date: Tue, 8 Sep 2026 08:32:53 +0000 Subject: [PATCH] =?UTF-8?q?security:=20KVE-2026-2329=20XHTML=20=EB=93=B1?= =?UTF-8?q?=20=EC=8B=A4=ED=96=89=ED=98=95=20=EC=B2=A8=EB=B6=80=EB=A5=BC=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EC=A0=84=EC=97=90=20=EC=B0=A8=EB=8B=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 게시판·1:1문의·폼메일·쇼핑몰 로고의 PHP 업로드 검사에서 위험 확장자를 거부한다. 대소문자와 다중 확장자 등 파일명 변형을 검사하고 클라이언트 검사도 일치시킨다. 검증: 위험 파일 및 정상 이미지·문서 파일명 격리 검증, 저장 전 차단 검증, PHP·JavaScript 문법 검사 통과. --- adm/shop_admin/configformupdate.php | 4 ++-- bbs/formmail_send.php | 4 ++-- bbs/qawrite_update.php | 4 ++-- bbs/write_update.php | 4 ++-- js/common.js | 17 +++++++++++++---- lib/common.lib.php | 13 ++++++++++++- 6 files changed, 33 insertions(+), 13 deletions(-) diff --git a/adm/shop_admin/configformupdate.php b/adm/shop_admin/configformupdate.php index 9d404ef3a..682675220 100644 --- a/adm/shop_admin/configformupdate.php +++ b/adm/shop_admin/configformupdate.php @@ -19,8 +19,8 @@ $logo_img_fields = array('logo_img', 'logo_img2', 'mobile_logo_img', 'mobile_log foreach ($logo_img_fields as $logo_img_field) { if (isset($_FILES[$logo_img_field]['name']) && $_FILES[$logo_img_field]['name']) { $filename = get_safe_filename($_FILES[$logo_img_field]['name']); - if (is_disallowed_svg_filename($filename)) { - alert('허용되지 않는 파일 확장자입니다. (svg, svgz)'); + if (is_disallowed_active_filename($filename)) { + alert('허용되지 않는 파일 확장자입니다.'); } } } diff --git a/bbs/formmail_send.php b/bbs/formmail_send.php index 355524f35..927afe3e1 100644 --- a/bbs/formmail_send.php +++ b/bbs/formmail_send.php @@ -34,8 +34,8 @@ for ($i=1; $i<=$attach; $i++) { $file_key = 'file'.$i; if (isset($_FILES[$file_key]['name']) && $_FILES[$file_key]['name']) { $filename = get_safe_filename($_FILES[$file_key]['name']); - if (is_disallowed_svg_filename($filename)) { - alert_close('허용되지 않는 파일 확장자입니다. (svg, svgz)'); + if (is_disallowed_active_filename($filename)) { + alert_close('허용되지 않는 파일 확장자입니다.'); } } } diff --git a/bbs/qawrite_update.php b/bbs/qawrite_update.php index 35d63cfef..be5c81481 100644 --- a/bbs/qawrite_update.php +++ b/bbs/qawrite_update.php @@ -136,8 +136,8 @@ if($w == 'u' || $w == 'a' || $w == 'r') { if (isset($_FILES['bf_file']['name']) && is_array($_FILES['bf_file']['name'])) { foreach ($_FILES['bf_file']['name'] as $filename) { $filename = get_safe_filename($filename); - if (is_disallowed_svg_filename($filename)) { - alert('허용되지 않는 파일 확장자입니다. (svg, svgz)'); + if (is_disallowed_active_filename($filename)) { + alert('허용되지 않는 파일 확장자입니다.'); } } } diff --git a/bbs/write_update.php b/bbs/write_update.php index 6020f283a..0d63e2d47 100644 --- a/bbs/write_update.php +++ b/bbs/write_update.php @@ -173,8 +173,8 @@ for ($i=1; $i<=10; $i++) { if (isset($_FILES['bf_file']['name']) && is_array($_FILES['bf_file']['name'])) { foreach ($_FILES['bf_file']['name'] as $filename) { $filename = get_safe_filename($filename); - if (is_disallowed_svg_filename($filename)) { - alert('허용되지 않는 파일 확장자입니다. (svg, svgz)'); + if (is_disallowed_active_filename($filename)) { + alert('허용되지 않는 파일 확장자입니다.'); } } } diff --git a/js/common.js b/js/common.js index 644ee11ad..d46f3586c 100644 --- a/js/common.js +++ b/js/common.js @@ -70,6 +70,15 @@ function is_disallowed_svg_filename(filename) return /\.(svg|svgz)$/i.test(filename); } +function is_disallowed_active_filename(filename) +{ + filename = filename || ""; + if (/[\x00-\x1f\x7f]/.test(filename)) return true; + filename = filename.replace(/["'<>=#&!%\\()*+?]/g, ""); + filename = filename.substring(filename.lastIndexOf("/") + 1).replace(/[ .]+$/, ""); + return /\.(svgz?|xhtml|xht|xml|xsl|xslt|mht|mhtml|htc)([. :]|$)/i.test(filename); +} + function is_svg_upload_target(input) { var name = input.name || ""; @@ -92,7 +101,7 @@ function has_disallowed_svg_file(input) if (input.files && input.files.length) { for (i=0; i