security: KVE-2026-2345 장바구니 옵션 검증으로 상품대금 누락 차단
공통·기본 테마 AJAX와 일반 장바구니 요청에 동일한 상품·옵션 검증을 적용한다. 주문 준비 및 PC·모바일 주문 제출에서도 기존 행의 종류·가격·구성을 확인한다. 공통 규칙 46개와 격리 MySQL의 MyISAM·InnoDB HTTP/DB 검증 126개를 통과했다. 주문 검증은 PG·주문 저장 이전 경계까지이며 전체 결제 및 동시성 검증은 별도로 필요하다.
This commit is contained in:
+13
-33
@@ -78,35 +78,20 @@ switch ($action) {
|
||||
if ($count < 1)
|
||||
die(json_encode(array('error' => '장바구니에 담을 상품을 선택하여 주십시오.')));
|
||||
|
||||
$cart_validation = shop_validate_cart_request($_POST);
|
||||
if ($cart_validation['error'] !== '')
|
||||
die(json_encode(array('error' => $cart_validation['error'])));
|
||||
|
||||
$ct_count = 0;
|
||||
for($i=0; $i<$count; $i++) {
|
||||
$it_id = isset($_POST['it_id'][$i]) ? safe_replace_regex($_POST['it_id'][$i], 'it_id') : '';
|
||||
$opt_count = (isset($_POST['io_id'][$it_id]) && is_array($_POST['io_id'][$it_id])) ? count($_POST['io_id'][$it_id]) : 0;
|
||||
|
||||
// 상품정보
|
||||
$it = get_shop_item($it_id, false);
|
||||
$it = $cart_validation['products'][$it_id]['item'];
|
||||
if(!$it['it_id'])
|
||||
die(json_encode(array('error' => '상품정보가 존재하지 않습니다.')));
|
||||
|
||||
// 옵션정보를 얻어서 배열에 저장
|
||||
$opt_list = array();
|
||||
$sql = " select * from {$g5['g5_shop_item_option_table']} where it_id = '$it_id' order by io_no asc ";
|
||||
$result = sql_query($sql);
|
||||
$lst_count = 0;
|
||||
for($k=0; $row=sql_fetch_array($result); $k++) {
|
||||
$opt_list[$row['io_type']][$row['io_id']]['id'] = $row['io_id'];
|
||||
$opt_list[$row['io_type']][$row['io_id']]['use'] = $row['io_use'];
|
||||
$opt_list[$row['io_type']][$row['io_id']]['price'] = $row['io_price'];
|
||||
$opt_list[$row['io_type']][$row['io_id']]['stock'] = $row['io_stock_qty'];
|
||||
|
||||
// 선택옵션 개수
|
||||
if(!$row['io_type'])
|
||||
$lst_count++;
|
||||
}
|
||||
|
||||
if($lst_count > 0 && !trim($_POST['io_id'][$it_id][$i]) && $_POST['io_type'][$it_id][$i] == 0)
|
||||
die(json_encode(array('error' => '상품의 선택옵션을 선택해 주십시오.')));
|
||||
|
||||
for($k=0; $k<$opt_count; $k++) {
|
||||
$post_ct_qty = isset($_POST['ct_qty'][$it_id][$k]) ? (int) $_POST['ct_qty'][$it_id][$k] : 0;
|
||||
if ($post_ct_qty < 1)
|
||||
@@ -155,25 +140,17 @@ switch ($action) {
|
||||
|
||||
// 장바구니에 Insert
|
||||
$comma = '';
|
||||
$ct_count = 0;
|
||||
$sql = " INSERT INTO {$g5['g5_shop_cart_table']}
|
||||
( od_id, mb_id, it_id, it_name, it_sc_type, it_sc_method, it_sc_price, it_sc_minimum, it_sc_qty, ct_status, ct_price, ct_point, ct_point_use, ct_stock_use, ct_option, ct_qty, ct_notax, io_id, io_type, io_price, ct_time, ct_ip, ct_send_cost, ct_direct, ct_select, ct_select_time )
|
||||
VALUES ";
|
||||
|
||||
for($k=0; $k<$opt_count; $k++) {
|
||||
$io_id = isset($_POST['io_id'][$it_id][$k]) ? preg_replace(G5_OPTION_ID_FILTER, '', $_POST['io_id'][$it_id][$k]) : '';
|
||||
$io_type = isset($_POST['io_type'][$it_id][$k]) ? preg_replace('#[^01]#', '', $_POST['io_type'][$it_id][$k]) : '';
|
||||
$io_id = $cart_validation['products'][$it_id]['rows'][$k]['io_id'];
|
||||
$io_type = $cart_validation['products'][$it_id]['rows'][$k]['io_type'];
|
||||
$io_value = isset($_POST['io_value'][$it_id][$k]) ? $_POST['io_value'][$it_id][$k] : '';
|
||||
|
||||
// 선택옵션정보가 존재하는데 선택된 옵션이 없으면 건너뜀
|
||||
if($lst_count && $io_id == '')
|
||||
continue;
|
||||
|
||||
$opt_list_type_id_use = isset($opt_list[$io_type][$io_id]['use']) ? $opt_list[$io_type][$io_id]['use'] : '';
|
||||
// 구매할 수 없는 옵션은 건너뜀
|
||||
if($io_id && ! $opt_list_type_id_use)
|
||||
continue;
|
||||
|
||||
$io_price = isset($opt_list[$io_type][$io_id]['price']) ? $opt_list[$io_type][$io_id]['price'] : 0;
|
||||
$io_price = $cart_validation['products'][$it_id]['rows'][$k]['io_price'];
|
||||
$ct_qty = isset($_POST['ct_qty'][$it_id][$k]) ? (int) $_POST['ct_qty'][$it_id][$k] : 0;
|
||||
|
||||
// 구매가격이 음수인지 체크
|
||||
@@ -186,14 +163,17 @@ switch ($action) {
|
||||
}
|
||||
|
||||
// 동일옵션의 상품이 있으면 수량 더함
|
||||
$sql2 = " select ct_id, io_type, ct_qty
|
||||
$sql2 = " select ct_id, io_type, ct_qty, ct_price, io_price
|
||||
from {$g5['g5_shop_cart_table']}
|
||||
where od_id = '$tmp_cart_id'
|
||||
and it_id = '$it_id'
|
||||
and io_id = '$io_id'
|
||||
and io_type = '$io_type'
|
||||
and ct_status = '쇼핑' ";
|
||||
$row2 = sql_fetch($sql2);
|
||||
if(isset($row2['ct_id']) && $row2['ct_id']) {
|
||||
if ((int) $row2['ct_price'] !== (int) $it['it_price'] || (int) $row2['io_price'] !== $io_price)
|
||||
die(json_encode(array('error' => '기존 장바구니의 상품 정보가 변경되었습니다. 삭제한 뒤 다시 담아 주십시오.')));
|
||||
// 재고체크
|
||||
$tmp_ct_qty = $row2['ct_qty'];
|
||||
if(!$io_id)
|
||||
|
||||
+15
-31
@@ -146,6 +146,10 @@ else // 장바구니에 담기
|
||||
if ($count < 1)
|
||||
alert('장바구니에 담을 상품을 선택하여 주십시오.');
|
||||
|
||||
$cart_validation = shop_validate_cart_request($_POST, $act === 'multi');
|
||||
if ($cart_validation['error'] !== '')
|
||||
alert($cart_validation['error']);
|
||||
|
||||
$ct_count = 0;
|
||||
$post_chk_it_id = (isset($_POST['chk_it_id']) && is_array($_POST['chk_it_id'])) ? $_POST['chk_it_id'] : array();
|
||||
$post_io_ids = (isset($_POST['io_id']) && is_array($_POST['io_id'])) ? $_POST['io_id'] : array();
|
||||
@@ -184,7 +188,7 @@ else // 장바구니에 담기
|
||||
}
|
||||
|
||||
// 상품정보
|
||||
$it = get_shop_item($it_id, false);
|
||||
$it = $cart_validation['products'][$it_id]['item'];
|
||||
if(!$it['it_id'])
|
||||
alert('상품정보가 존재하지 않습니다.');
|
||||
|
||||
@@ -219,30 +223,14 @@ else // 장바구니에 담기
|
||||
}
|
||||
}
|
||||
|
||||
// 옵션정보를 얻어서 배열에 저장
|
||||
$opt_list = array();
|
||||
$sql = " select * from {$g5['g5_shop_item_option_table']} where it_id = '$it_id' and io_use = 1 order by io_no asc ";
|
||||
$result = sql_query($sql);
|
||||
$lst_count = 0;
|
||||
for($k=0; $row=sql_fetch_array($result); $k++) {
|
||||
$opt_list[$row['io_type']][$row['io_id']]['id'] = $row['io_id'];
|
||||
$opt_list[$row['io_type']][$row['io_id']]['use'] = $row['io_use'];
|
||||
$opt_list[$row['io_type']][$row['io_id']]['price'] = $row['io_price'];
|
||||
$opt_list[$row['io_type']][$row['io_id']]['stock'] = $row['io_stock_qty'];
|
||||
|
||||
// 선택옵션 개수
|
||||
if(!$row['io_type'])
|
||||
$lst_count++;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// 재고 검사, 바로구매일 때만 체크
|
||||
//--------------------------------------------------------
|
||||
// 이미 주문폼에 있는 같은 상품의 수량합계를 구한다.
|
||||
if($sw_direct) {
|
||||
for($k=0; $k<$opt_count; $k++) {
|
||||
$io_id = isset($_POST['io_id'][$it_id][$k]) ? preg_replace(G5_OPTION_ID_FILTER, '', $_POST['io_id'][$it_id][$k]) : '';
|
||||
$io_type = isset($_POST['io_type'][$it_id][$k]) ? preg_replace('#[^01]#', '', $_POST['io_type'][$it_id][$k]) : '';
|
||||
$io_id = $cart_validation['products'][$it_id]['rows'][$k]['io_id'];
|
||||
$io_type = $cart_validation['products'][$it_id]['rows'][$k]['io_type'];
|
||||
$io_value = isset($_POST['io_value'][$it_id][$k]) ? $_POST['io_value'][$it_id][$k] : '';
|
||||
|
||||
$sql = " select SUM(ct_qty) as cnt from {$g5['g5_shop_cart_table']}
|
||||
@@ -287,24 +275,17 @@ else // 장바구니에 담기
|
||||
|
||||
// 장바구니에 Insert
|
||||
$comma = '';
|
||||
$ct_count = 0;
|
||||
$sql = " INSERT INTO {$g5['g5_shop_cart_table']}
|
||||
( od_id, mb_id, it_id, it_name, it_sc_type, it_sc_method, it_sc_price, it_sc_minimum, it_sc_qty, ct_status, ct_price, ct_point, ct_point_use, ct_stock_use, ct_option, ct_qty, ct_notax, io_id, io_type, io_price, ct_time, ct_ip, ct_send_cost, ct_direct, ct_select, ct_select_time )
|
||||
VALUES ";
|
||||
|
||||
for($k=0; $k<$opt_count; $k++) {
|
||||
$io_id = isset($_POST['io_id'][$it_id][$k]) ? preg_replace(G5_OPTION_ID_FILTER, '', $_POST['io_id'][$it_id][$k]) : '';
|
||||
$io_type = isset($_POST['io_type'][$it_id][$k]) ? preg_replace('#[^01]#', '', $_POST['io_type'][$it_id][$k]) : '';
|
||||
$io_id = $cart_validation['products'][$it_id]['rows'][$k]['io_id'];
|
||||
$io_type = $cart_validation['products'][$it_id]['rows'][$k]['io_type'];
|
||||
$io_value = isset($_POST['io_value'][$it_id][$k]) ? $_POST['io_value'][$it_id][$k] : '';
|
||||
|
||||
// 선택옵션정보가 존재하는데 선택된 옵션이 없으면 건너뜀
|
||||
if($lst_count && $io_id == '')
|
||||
continue;
|
||||
|
||||
// 구매할 수 없는 옵션은 건너뜀
|
||||
if($io_id && !$opt_list[$io_type][$io_id]['use'])
|
||||
continue;
|
||||
|
||||
$io_price = isset($opt_list[$io_type][$io_id]['price']) ? $opt_list[$io_type][$io_id]['price'] : 0;
|
||||
$io_price = $cart_validation['products'][$it_id]['rows'][$k]['io_price'];
|
||||
$ct_qty = isset($_POST['ct_qty'][$it_id][$k]) ? (int) $_POST['ct_qty'][$it_id][$k] : 0;
|
||||
|
||||
// 구매가격이 음수인지 체크
|
||||
@@ -317,14 +298,17 @@ else // 장바구니에 담기
|
||||
}
|
||||
|
||||
// 동일옵션의 상품이 있으면 수량 더함
|
||||
$sql2 = " select ct_id, io_type, ct_qty
|
||||
$sql2 = " select ct_id, io_type, ct_qty, ct_price, io_price
|
||||
from {$g5['g5_shop_cart_table']}
|
||||
where od_id = '$tmp_cart_id'
|
||||
and it_id = '$it_id'
|
||||
and io_id = '$io_id'
|
||||
and io_type = '$io_type'
|
||||
and ct_status = '쇼핑' ";
|
||||
$row2 = sql_fetch($sql2);
|
||||
if(isset($row2['ct_id']) && $row2['ct_id']) {
|
||||
if ((int) $row2['ct_price'] !== (int) $it['it_price'] || (int) $row2['io_price'] !== $io_price)
|
||||
alert('기존 장바구니의 상품 정보가 변경되었습니다. 삭제한 뒤 다시 담아 주십시오.');
|
||||
// 재고체크
|
||||
$tmp_ct_qty = $row2['ct_qty'];
|
||||
if(!$io_id)
|
||||
|
||||
@@ -24,6 +24,12 @@ else {
|
||||
if (get_cart_count($tmp_cart_id) == 0)
|
||||
alert('장바구니가 비어 있습니다.', G5_SHOP_URL.'/cart.php');
|
||||
|
||||
// KVE-2026-2345: 과거 장바구니의 옵션 종류와 가격도 주문 전에 다시 검증한다.
|
||||
$cart_validation_error = shop_validate_order_cart($tmp_cart_id);
|
||||
if ($cart_validation_error !== '') {
|
||||
alert($cart_validation_error, G5_SHOP_URL.'/cart.php');
|
||||
}
|
||||
|
||||
if (function_exists('before_check_cart_price')) {
|
||||
if(! before_check_cart_price($tmp_cart_id) ) alert('장바구니 금액에 변동사항이 있습니다.\n장바구니를 다시 확인해 주세요.', G5_SHOP_URL.'/cart.php');
|
||||
}
|
||||
|
||||
@@ -47,6 +47,12 @@ if (get_cart_count($tmp_cart_id) == 0) { // 장바구니에 담기
|
||||
alert('장바구니가 비어 있습니다.\\n\\n이미 주문하셨거나 장바구니에 담긴 상품이 없는 경우입니다.', G5_SHOP_URL.'/cart.php');
|
||||
}
|
||||
|
||||
// KVE-2026-2345: 과거 장바구니의 옵션 종류와 가격도 주문 전에 다시 검증한다.
|
||||
$cart_validation_error = shop_validate_order_cart($tmp_cart_id);
|
||||
if ($cart_validation_error !== '') {
|
||||
alert($cart_validation_error, G5_SHOP_URL.'/cart.php');
|
||||
}
|
||||
|
||||
// 변수 초기화
|
||||
$od_other_pay_type = '';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user