security: KVE-2026-2345 승인 후 검증 실패 취소와 장바구니 병합 사전 검사

모바일 이니시스 승인 전 장바구니를 검증하고 승인 후 실패는 서버 세션으로 확인한 거래의 취소 결과를 기록한다. 기존 장바구니와 병합할 가격·수량 및 구매 자격도 변경 전에 확인한다.

공통 규칙 46개, SQLite 및 모의 PG 후속 회귀 25개와 PHP 문법 검사를 통과했다. 실제 MySQL·PG 통합 및 동시성 검증은 별도로 필요하다.
This commit is contained in:
whitedot committed 2026-09-10 05:17:59 +00:00
1 parent 6d4e75e1c9
commit 560aa0af47
9 files changed
+315 -15

No files matched your search

+41
View File
@@ -135,6 +135,47 @@ function shop_validate_cart_request($post, $multi = false)
return array('error' => $products ? '' : $error, 'products' => $products);
}
// 기존 행과 합친 결과도 삭제/UPDATE 전에 모든 상품에 대해 확인한다.
// 동시 요청과 SQL 실패의 원자성까지 보장하는 잠금/트랜잭션은 아니다.
function shop_validate_cart_merge($cart_id, $products, $direct = false, $replace = false)
{
global $g5;
$cart_id = sql_escape_string($cart_id);
foreach ($products as $it_id => $product) {
$id = sql_escape_string($it_id);
$rows = array();
if (!$replace) {
$exclude = $direct ? ' and ct_direct <> 1 ' : '';
$result = sql_query(" select * from {$g5['g5_shop_cart_table']} where od_id = '$cart_id' and it_id = '$id' and ct_status = '쇼핑' $exclude order by ct_id asc ");
while ($row = sql_fetch_array($result))
$rows[] = $row;
}
$rows = array_merge($rows, $product['rows']);
list($item, $options) = shop_cart_option_data($it_id);
$validated = shop_validate_cart_rows($item, $options, $rows, true);
if ($validated['error'] !== '')
return $validated['error'];
// 바로구매에서는 다른 장바구니가 선택해 둔 수량도 선삭제 전에 검사한다.
if ($direct) {
$quantities = array();
foreach ($rows as $row) {
$key = $row['io_type'].':'.$row['io_id'];
$quantities[$key] = isset($quantities[$key]) ? $quantities[$key] + $row['ct_qty'] : $row['ct_qty'];
}
foreach ($product['rows'] as $row) {
$io_id = sql_escape_string($row['io_id']);
$type = (int) $row['io_type'];
$reserved = sql_fetch(" select SUM(ct_qty) as cnt from {$g5['g5_shop_cart_table']} where od_id <> '$cart_id' and it_id = '$id' and io_id = '$io_id' and io_type = '$type' and ct_stock_use = 0 and ct_status = '쇼핑' and ct_select = '1' ");
$stock = $row['io_id'] === '' ? get_it_stock_qty($it_id) : get_option_stock_qty($it_id, $row['io_id'], $type);
if ($quantities[$type.':'.$row['io_id']] + (int) $reserved['cnt'] > $stock)
return '상품 또는 옵션의 재고수량이 부족합니다.';
}
}
}
return '';
}
// 주문 준비/확정 시에는 선택된 행만 검증하여 보조옵션 단독 선택과 과거 조작 행도 차단한다.
function shop_validate_order_cart($cart_id)
{