security: SVG 및 SVGZ 파일 업로드 차단
게시판, 1:1문의, 폼메일 및 쇼핑몰 설정의 클라이언트와 서버 검증에서 SVG 계열 파일 업로드를 거부한다.
This commit is contained in:
@@ -15,6 +15,16 @@ if(! (isset($_POST['de_admin_company_tel']) && check_vaild_callback($_POST['de_a
|
||||
// 로그인을 바로 이 주소로 하는 경우 쇼핑몰설정값이 사라지는 현상을 방지
|
||||
if (!$_POST['de_admin_company_owner']) goto_url("./configform.php");
|
||||
|
||||
$logo_img_fields = array('logo_img', 'logo_img2', 'mobile_logo_img', 'mobile_logo_img2');
|
||||
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 (! empty($_POST['logo_img_del'])) @unlink(G5_DATA_PATH."/common/logo_img");
|
||||
if (! empty($_POST['logo_img_del2'])) @unlink(G5_DATA_PATH."/common/logo_img2");
|
||||
if (! empty($_POST['mobile_logo_img_del'])) @unlink(G5_DATA_PATH."/common/mobile_logo_img");
|
||||
|
||||
+16
-3
@@ -28,9 +28,22 @@ if (!preg_match("/([0-9a-zA-Z_-]+)@([0-9a-zA-Z_-]+)\.([0-9a-zA-Z_-]+)/", $to)){
|
||||
}
|
||||
|
||||
$file = array();
|
||||
|
||||
// 첨부파일을 이동하기 전에 모든 파일명을 먼저 확인한다.
|
||||
for ($i=1; $i<=$attach; $i++) {
|
||||
if ($_FILES['file'.$i]['name'])
|
||||
$file[] = attach_file($_FILES['file'.$i]['name'], $_FILES['file'.$i]['tmp_name']);
|
||||
$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)');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ($i=1; $i<=$attach; $i++) {
|
||||
$file_key = 'file'.$i;
|
||||
if (isset($_FILES[$file_key]['name']) && $_FILES[$file_key]['name'])
|
||||
$file[] = attach_file($_FILES[$file_key]['name'], $_FILES[$file_key]['tmp_name']);
|
||||
}
|
||||
|
||||
$content = stripslashes($content);
|
||||
@@ -78,4 +91,4 @@ include_once(G5_PATH.'/head.sub.php');
|
||||
|
||||
alert_close('메일을 정상적으로 발송하였습니다.');
|
||||
|
||||
include_once(G5_PATH.'/tail.sub.php');
|
||||
include_once(G5_PATH.'/tail.sub.php');
|
||||
|
||||
@@ -133,6 +133,15 @@ 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)');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 파일개수 체크
|
||||
$file_count = 0;
|
||||
$upload_count = isset($_FILES['bf_file']['name']) ? count($_FILES['bf_file']['name']) : 0;
|
||||
|
||||
@@ -137,6 +137,15 @@ 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)');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include_once($board_skin_path.'/write_update.head.skin.php');
|
||||
|
||||
run_event('write_update_before', $board, $wr_id, $w, $qstr);
|
||||
|
||||
@@ -5,4 +5,4 @@ if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
// 예) https://도메인/css/default.css?ver=220620
|
||||
// 예) https://도메인/js/common.js?ver=220620
|
||||
define('G5_CSS_VER', '2303229');
|
||||
define('G5_JS_VER', '2605291');
|
||||
define('G5_JS_VER', '2608311');
|
||||
|
||||
+91
-1
@@ -59,6 +59,72 @@ function trim(s)
|
||||
return t;
|
||||
}
|
||||
|
||||
// SVG/SVGZ 업로드 파일 차단
|
||||
function is_disallowed_svg_filename(filename)
|
||||
{
|
||||
// 서버의 파일명 정규화와 동일하게 특수문자를 제거
|
||||
filename = (filename || "").replace(/[\0"'<>=#&!%\\()*+?]/g, "");
|
||||
filename = filename.substring(filename.lastIndexOf("/") + 1);
|
||||
filename = filename.replace(/[ .\t\n\r\v]+$/, "");
|
||||
|
||||
return /\.(svg|svgz)$/i.test(filename);
|
||||
}
|
||||
|
||||
function is_svg_upload_target(input)
|
||||
{
|
||||
var name = input.name || "";
|
||||
|
||||
if (name.indexOf("bf_file[") === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (input.form && input.form.name == "fformmail" && (name == "file1" || name == "file2")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return input.form && input.form.name == "fconfig" &&
|
||||
(name == "logo_img" || name == "logo_img2" || name == "mobile_logo_img" || name == "mobile_logo_img2");
|
||||
}
|
||||
|
||||
function has_disallowed_svg_file(input)
|
||||
{
|
||||
var i;
|
||||
|
||||
if (input.files && input.files.length) {
|
||||
for (i=0; i<input.files.length; i++) {
|
||||
if (is_disallowed_svg_filename(input.files[i].name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_disallowed_svg_filename(input.value);
|
||||
}
|
||||
|
||||
function check_disallowed_svg_upload(form)
|
||||
{
|
||||
var invalid_file = null;
|
||||
|
||||
$(form).find("input[type=file]").each(function() {
|
||||
if (is_svg_upload_target(this) && has_disallowed_svg_file(this)) {
|
||||
invalid_file = this;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (!invalid_file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
alert("허용되지 않는 파일 확장자입니다. (svg, svgz)");
|
||||
$(form).find("input:submit, button:submit, input:image").prop("disabled", false);
|
||||
invalid_file.focus();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 자바스크립트로 PHP의 number_format 흉내를 냄
|
||||
// 숫자에 , 를 출력
|
||||
function number_format(data)
|
||||
@@ -728,6 +794,30 @@ function get_write_token(bo_table)
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$(document).on("change", "input[type=file]", function() {
|
||||
if (!is_svg_upload_target(this) || !has_disallowed_svg_file(this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
alert("허용되지 않는 파일 확장자입니다. (svg, svgz)");
|
||||
this.value = "";
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (document.addEventListener) {
|
||||
document.addEventListener("submit", function(event) {
|
||||
if (!check_disallowed_svg_upload(event.target)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}, true);
|
||||
} else {
|
||||
$(document).on("submit", "form", function() {
|
||||
return check_disallowed_svg_upload(this);
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on("click", "form[name=fwrite] input:submit, form[name=fwrite] button:submit, form[name=fwrite] input:image", function() {
|
||||
var f = this.form;
|
||||
|
||||
@@ -752,4 +842,4 @@ $(function() {
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4011,6 +4011,26 @@ function get_safe_filename($name)
|
||||
return $name;
|
||||
}
|
||||
|
||||
// 업로드 파일명이 SVG 또는 SVGZ 확장자인지 확인
|
||||
function is_disallowed_svg_filename($filename)
|
||||
{
|
||||
if (!is_string($filename) || $filename === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$filename = str_replace(array("\0", '\\'), array('', '/'), $filename);
|
||||
$filename = basename($filename);
|
||||
$filename = rtrim($filename, " .\t\n\r\0\x0B");
|
||||
|
||||
if ($filename === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
|
||||
return in_array($extension, array('svg', 'svgz'), true);
|
||||
}
|
||||
|
||||
// 파일명 치환
|
||||
function replace_filename($name)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user