security: KVE-2026-2345 장바구니 옵션 검증으로 상품대금 누락 차단

공통·기본 테마 AJAX와 일반 장바구니 요청에 동일한 상품·옵션 검증을 적용한다. 주문 준비 및 PC·모바일 주문 제출에서도 기존 행의 종류·가격·구성을 확인한다.

공통 규칙 46개와 격리 MySQL의 MyISAM·InnoDB HTTP/DB 검증 126개를 통과했다. 주문 검증은 PG·주문 저장 이전 경계까지이며 전체 결제 및 동시성 검증은 별도로 필요하다.
This commit is contained in:
whitedot committed 2026-09-10 05:17:59 +00:00
1 parent 77e0cda39b
commit 6d4e75e1c9
11 files changed
+507 -98

No files matched your search

+15 -31
View File
@@ -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)