E-Ticaret Sitelerinde En Sık Bulunan Kritik Zafiyetler: E-Ticaret Sızma Testi Rehberi
E-ticaret güvenliği yalnızca SQL injection veya XSS aramakla ölçülemez. Fiyatın hangi sistemde belirlendiği, ödeme sonucuna neden güvenildiği, kupon ve refund haklarının eşzamanlı request’lerde nasıl korunduğu çoğu zaman gerçek kritik riski belirler.
SECNODEX Güvenlik Ekibi
Ofansif Güvenlik
Bir e-ticaret uygulamasında SQL injection bulunmayabilir. Admin panel dışarıya açık olmayabilir. TLS configuration doğru, dependency’ler güncel, ödeme kartı verisi de doğrudan payment provider tarafından işleniyor olabilir.
Yine de kullanıcı sepetteki 12.500 TL değerindeki ürünü 125 TL’ye satın alabilir.
Çünkü frontend checkout sırasında aşağıdaki request’i gönderiyordur:
{
"items": [
{
"productId": "8ed85f5a-42fa-4c16-92f8-6f4a0d0f0f25",
"quantity": 1,
"unitPrice": 12500
}
],
"currency": "TRY"
}Backend ise ürünün güncel fiyatını catalog service’ten almak yerine request’teki unitPrice değerini kullanıyordur:
const total = request.items.reduce(
(sum, item) => sum + item.unitPrice * item.quantity,
0
);
const payment = await paymentProvider.create({
amount: total,
currency: request.currency
});Request geçerlidir. Kullanıcı authenticated olabilir. Payment provider gerçekten tahsilat yapmış da olabilir. Sorun, fiyatı belirleme yetkisi müşteriye ait olmadığı hâlde backend’in client-controlled değeri authoritative kabul etmesidir.
Başka bir sitede fiyat server-side hesaplanıyor olabilir. Fakat aynı kupon iki parallel request ile iki kez tüketilebilir. Ödeme dönüş URL’sindeki status=success parametresi siparişi PAID state’ine taşıyabilir. Bir marketplace’te seller, başka seller’a ait siparişin kargo belgesini ID değiştirerek indirebilir. Password reset akışı eski session’ları iptal etmediği için ele geçirilmiş hesap saldırganın kontrolünde kalabilir. Payment page üzerinde çalışan analytics script’i değiştirilerek form alanları üçüncü tarafa gönderilebilir.
Bu örnekler aynı gerçeği gösterir:
Not
E-ticaret sızma testi yalnızca teknik zafiyet aramaz. Para, ürün, indirim, hesap ve sipariş state’ini değiştiren bütün güven kararlarının gerçekten server-side enforce edilip edilmediğini doğrular.
Bu yazıda e-ticaret sitelerinde en sık karşılaşılan kritik zafiyetleri yalnızca isimleriyle sıralamayacağız. Account takeover’dan IDOR ve BOLA’ya, fiyat manipülasyonundan kupon abuse ve race condition’a, payment webhook güvenliğinden e-skimming ve third-party script riskine kadar her problemi attack path, root cause, test yaklaşımı ve kalıcı remediation açısından inceleyeceğiz.
1. E-ticaret sızma testi nedir?
E-ticaret sızma testi, alışveriş deneyimini oluşturan web uygulaması, API, mobil backend, payment integration, seller panel, admin panel ve destek servislerinin yetkilendirilmiş saldırı senaryolarıyla değerlendirilmesidir.
Amaç yalnızca bilinen CVE’leri veya scanner’ın işaretleyebileceği teknik configuration sorunlarını bulmak değildir. Gerçek test şu sorulara cevap üretmelidir:
- Bir müşteri başka müşterinin siparişini, adresini veya faturasını görebilir mi?
- Ürün fiyatı, kargo ücreti, vergi, indirim veya currency client tarafından değiştirilebilir mi?
- Kupon, hediye kartı, loyalty point veya referral hakkı birden fazla kez kullanılabilir mi?
- Checkout adımları atlanarak ödeme yapılmadan sipariş oluşturulabilir mi?
- Payment callback sahte, tekrar edilmiş veya yanlış siparişe bağlanmış olabilir mi?
- Aynı refund veya sipariş parallel request’lerle iki kez işlenebilir mi?
- Seller yalnızca kendi mağazasına ait order ve müşteri verisini görebiliyor mu?
- Support veya operasyon kullanıcısı ihtiyacından fazla kişisel veriye erişebiliyor mu?
- Mobil uygulama ve web sitesi aynı API’de aynı authorization kurallarını uyguluyor mu?
- Payment page’e etki eden third-party script’ler envanterli ve integrity açısından izleniyor mu?
Bu soruların önemli bir bölümü vulnerability scanner ile cevaplanamaz. Çünkü uygulamaya özgü business rule, actor-resource ilişkisi, payment state ve expected workflow bilinmeden teknik olarak geçerli bir request’in güvenli olup olmadığı anlaşılamaz.
Zafiyet taraması ile aynı çalışma değildir
Automated vulnerability scanning, geniş asset yüzeyinde eksik patch, açık service, bilinen CVE, TLS problemi ve bazı web pattern’leri için değerlidir. E-ticaret sızma testi ise gerçek kullanıcı rolleri, order lifecycle, API contract, payment integration ve business logic üzerinde kontrollü exploitation ve manuel doğrulama yapar.
Bir scanner aşağıdaki request’in schema’ya uygun olduğunu görebilir:
{
"couponCode": "WELCOME20",
"quantity": 2
}Fakat aynı kampanyanın yalnızca ilk alışverişte, tek hesapta, tek payment instrument’ta ve bir kez kullanılabileceğini kendiliğinden bilemez.
Sızma testinin zafiyet taramasından, Red Team’den ve diğer değerlendirme türlerinden farkını Sızma Testi Nedir? Kapsamlı Rehber sayfasında bütünlüklü biçimde ele alıyoruz.
2. E-ticaret saldırı yüzeyi neden tek bir domain’den ibaret değildir?
Müşterinin gördüğü storefront, sistemin yalnızca görünür parçasıdır. Modern e-ticaret mimarisinde aynı sipariş onlarca component arasında hareket edebilir.
| Yüzey | Tipik function’lar | Kritik güvenlik sorusu |
|---|---|---|
| Storefront | Ürün, sepet, checkout, hesap | Client hangi veriyi belirleyebiliyor? |
| Public API | Catalog, cart, order, search | Object ve function authorization var mı? |
| Mobil backend | Login, kampanya, ödeme, bildirim | Web’den farklı veya eski endpoint var mı? |
| Seller panel | Ürün, stok, fiyat, sipariş | Seller tenant isolation doğru mu? |
| Admin panel | Refund, kullanıcı, kampanya | Privileged action’lar dar policy ile mi korunuyor? |
| Payment integration | Payment intent, 3DS, webhook | Sonuç server-to-server doğrulanıyor mu? |
| OMS/ERP | Sipariş, stok, fatura | Internal trust nedeniyle kontrol atlanıyor mu? |
| Kargo entegrasyonu | Adres, etiket, takip | PII ve label object-level korunuyor mu? |
| Customer support | Impersonation, iade, adres | Support erişimi gerekçe ve audit gerektiriyor mu? |
| CMS ve media | Ürün açıklaması, görsel | Stored XSS ve file upload riski var mı? |
| Search ve recommendation | Query, filter, personalization | Injection, data leakage ve abuse mümkün mü? |
| CDN ve object storage | Görsel, fatura, export | Private object public veya tahmin edilebilir mi? |
| Third-party script | Analytics, chat, tag manager | Payment page davranışını değiştirebilir mi? |
| Webhook | Ödeme, kargo, stok event’i | Kaynak, integrity ve replay doğrulanıyor mu? |
API inventory ile route inventory aynı değildir
OpenAPI dokümanında görünmeyen endpoint’ler production’da çalışıyor olabilir:
- Eski
/v1/ve beta/v2/route’ları - Mobil uygulamanın eski version’ı için bırakılmış API
- Internal denilen fakat internetten erişilebilen endpoint
- GraphQL operation’ları
- WebSocket ve SignalR method’ları
- Upload, export ve download URL’leri
- Payment provider callback ve return URL’leri
- Debug, health ve management endpoint’leri
- Seller veya support panelinin kullandığı ayrı API host’ları
Bu yüzden kapsam yalnızca www.example.com olarak yazılırsa gerçek attack surface’in önemli bölümü test dışında kalabilir. Web uygulaması kapsamının asset, role, integration ve yasaklı işlem bazında nasıl kurulacağını Web Uygulaması Sızma Testinde Kapsam Nasıl Belirlenir? yazısında ayrıntılı olarak inceleyebilirsiniz.
Test persona olmadan authorization testi eksik kalır
En az şu persona’lar risk bazlı değerlendirilmelidir:
- Anonymous visitor
- Yeni müşteri
- Mevcut müşteri
- Loyalty veya premium müşteri
- Seller çalışanı
- Seller administrator
- Marketplace operasyon kullanıcısı
- Customer support
- Finance veya refund operator
- Campaign manager
- Platform administrator
- Service account veya integration client
Tek bir administrator hesabıyla yapılan test, horizontal privilege escalation ve tenant isolation problemlerini gösteremez. Her kritik resource için en az bir owner ve bir non-owner test hesabı gerekir.
3. Account takeover e-ticarette neden kritik etki üretir?
Ele geçirilmiş e-ticaret hesabı yalnızca profile erişim değildir. Kayıtlı adresler, sipariş geçmişi, faturalar, loyalty point, gift card balance, kayıtlı payment token ve aktif refund süreçleri saldırgan için maddi değere dönüşebilir.
Account takeover attack path’leri çoğunlukla şu kontrollerden birindeki zayıflıkla başlar:
- Credential stuffing’e karşı yetersiz savunma
- Account enumeration
- Zayıf password policy veya breached password kontrolü eksikliği
- MFA’nın hassas operation’larda uygulanmaması
- Password reset token’ının tahmin edilebilir, uzun ömürlü veya tekrar kullanılabilir olması
- Reset sonrası mevcut session’ların iptal edilmemesi
- E-mail veya telefon değişikliğinde re-authentication eksikliği
- OAuth account linking hatası
- Session fixation veya session token leakage
- Riskli login sonrasında detection ve step-up eksikliği
Credential stuffing ile brute force aynı değildir
Brute force tek hesap için çok sayıda password deneyebilir. Credential stuffing ise başka ihlallerden elde edilmiş username-password çiftlerini geniş kullanıcı kitlesi üzerinde dener. Her hesapta bir veya iki deneme yapıldığı için yalnızca account başına lockout yeterli olmayabilir.
Savunma katmanları birlikte düşünülmelidir:
- IP, account, device ve network reputation tabanlı adaptive throttling
- Breached password kontrolü
- MFA veya passkey
- Riskli login için step-up authentication
- Yeni device ve lokasyon bildirimi
- Credential stuffing pattern’i için merkezi detection
- Account enumeration üretmeyen response
- Password reset ve login limitlerinin ortak abuse görünürlüğü
Sabit ve düşük bir account lockout eşiği de saldırgana kullanıcıları kilitleme imkânı verebilir. Kontrolün amacı yalnızca tahmini yavaşlatmak değil, account takeover riskini availability kaybı üretmeden azaltmaktır.
Password reset flow tam bir authentication flow’dur
Reset endpoint’inde şu testler yapılmalıdır:
- Kullanıcı var ve yok response’ları ayırt edilebiliyor mu?
- Token yeterli entropy’ye sahip mi?
- Token tek kullanımlık mı?
- Expiration server-side enforce ediliyor mu?
- Token doğru account, purpose ve channel ile bağlı mı?
- Yeni reset talebi eski token’ı geçersiz kılıyor mu?
- Password değişince aktif session ve refresh token’lar iptal ediliyor mu?
- E-mail değişikliği reset flow’unu başka kullanıcıya yönlendirebilir mi?
- Host header veya forwarded header reset link’ini etkileyebiliyor mu?
- Reset completion CSRF ve login CSRF risklerine karşı korunuyor mu?
Token database’de düz metin saklanmak zorunda değildir. Tek kullanımlık secret’ın hash’i saklanabilir:
const rawToken = crypto.randomBytes(32).toString("base64url");
const tokenHash = crypto
.createHash("sha256")
.update(rawToken)
.digest("hex");
await passwordResetRepository.create({
userId: user.id,
tokenHash,
expiresAt: new Date(Date.now() + 15 * 60 * 1000),
usedAt: null
});Completion sırasında token hash’i, expiration ve usedAt aynı atomic operation içinde doğrulanıp tüketilmelidir.
4. Session management hatası ödeme öncesindeki bütün kontrolleri değersizleştirebilir
Kullanıcı güvenli biçimde login olsa bile session lifecycle zayıfsa saldırgan authenticated context’i ele geçirebilir.
E-ticaret testinde şu session davranışları özellikle incelenmelidir:
- Login sonrasında session ID rotate ediliyor mu?
- Logout server-side session’ı gerçekten iptal ediyor mu?
- Password, e-mail veya MFA değişiminden sonra diğer session’lar kapanıyor mu?
- Cookie üzerinde
Secure,HttpOnlyve uygunSameSiteattribute’ları var mı? - Session token URL, analytics, referrer veya client-side log’a sızıyor mu?
- Access token browser storage’da XSS ile okunabilir biçimde tutuluyor mu?
- Refresh token rotation ve reuse detection var mı?
- Session farklı tenant veya role’e geçildiğinde eski privilege’i taşıyor mu?
- Support impersonation sona erdiğinde original ve impersonated session ayrılıyor mu?
- Guest cart ile authenticated cart merge edilirken başka kullanıcının cart’ı bağlanabiliyor mu?
Hassas operation için re-authentication
Aktif session bulunması her işlemin aynı güven düzeyinde yapılması için yeterli olmayabilir. Şu operation’larda yakın zamanda authentication veya step-up düşünülebilir:
- Password ve MFA değişikliği
- E-mail ve telefon değişikliği
- Yeni teslimat adresi ekleme
- Kayıtlı payment method yönetimi
- Gift card transferi
- Yüksek tutarlı sipariş
- Banka hesabı veya seller payout değişikliği
- Account deletion ve data export
Oturum yaşam döngüsü ve token kontrollerini Oturum Yönetiminde En Sık Yapılan Hatalar yazısında teknik ayrıntılarıyla ele alıyoruz.
5. IDOR ve BOLA sipariş verisini tenant sınırının dışına taşır
E-ticaret API’lerinde object identifier hemen her yerde bulunur:
/orders/{orderId}/invoices/{invoiceId}/addresses/{addressId}/returns/{returnId}/shipments/{shipmentId}/seller/orders/{orderId}/gift-cards/{giftCardId}/support/cases/{caseId}
Identifier UUID olduğunda zafiyet ortadan kalkmaz. UUID tahmin etmeyi zorlaştırabilir, fakat kullanıcı ID’yi response, browser history, notification, referer, log, shared URL veya başka bir endpoint üzerinden elde edebilir. Security control, identifier’ın gizliliği değil object-level authorization olmalıdır.
Zafiyetli order lookup
app.get("/api/orders/:orderId", requireAuth, async (req, res) => {
const order = await orderRepository.findById(req.params.orderId);
if (!order) {
return res.sendStatus(404);
}
return res.json(order);
});requireAuth yalnızca request sahibinin login olduğunu gösterir. Order’ın o kullanıcıya ait olduğunu göstermez.
Owner ve tenant ile bağlanan query
app.get("/api/orders/:orderId", requireAuth, async (req, res) => {
const order = await orderRepository.findOne({
id: req.params.orderId,
customerId: req.auth.subjectId,
tenantId: req.auth.tenantId
});
if (!order) {
return res.sendStatus(404);
}
return res.json(toCustomerOrderDto(order));
});Seller panelinde owner ilişkisi customerId değil sellerId, seller membership veya fulfillment assignment üzerinden kurulabilir. Support kullanıcısında case assignment ve purpose gerekebilir. Aynı object için actor türüne göre farklı policy uygulanmalıdır.
Child object ile parent ilişkisinin doğrulanması
Şu route güvenli görünür:
GET /api/orders/{orderId}/shipments/{shipmentId}Fakat backend yalnızca shipmentId ile lookup yaparsa saldırgan kendi orderId’si altında başka siparişe ait shipment ID’si kullanabilir. Query iki ilişkiyi birlikte doğrulamalıdır:
SELECT id, carrier, tracking_number, status
FROM shipments
WHERE id = :shipment_id
AND order_id = :order_id
AND customer_id = :customer_id;IDOR’un root cause ve kalıcı remediation ayrıntılarını IDOR Açığı Neden Hâlâ Bu Kadar Yaygın? içeriğinde inceleyebilirsiniz.
6. Fiyat manipülasyonu nasıl oluşur?
E-ticaret sisteminde fiyat, indirim, kargo, vergi ve total gibi alanlar kullanıcıya gösterilir. Kullanıcının bu değerleri görmesi veya client tarafında hesaplaması, backend’e authority vermemelidir.
Riskli request alanları:
unitPricesalePricediscountAmountshippingCosttaxAmountcommissioncurrencyexchangeRategrandTotalisFreeShippingcampaignId
Server-authoritative hesaplama
Client yalnızca ürün kimliği, variant, quantity ve teslimat seçimi gibi intention bilgilerini göndermelidir. Backend authoritative catalog, campaign, inventory, tax ve shipping verisinden fiyat üretmelidir:
type CheckoutItemInput = {
productId: string;
variantId: string;
quantity: number;
};
async function priceCart(
input: CheckoutItemInput[],
context: PricingContext
): Promise<PricedCart> {
const products = await catalog.getSellableVariants(
input.map(item => item.variantId),
context.tenantId
);
return pricingEngine.calculate({
requestedItems: input,
products,
customerSegment: context.customerSegment,
destination: context.destination,
currency: context.storeCurrency,
evaluatedAt: context.now
});
}Checkout sonucu order’a immutable pricing snapshot olarak yazılmalıdır:
await orderRepository.create({
customerId: context.customerId,
currency: pricedCart.currency,
subtotalMinor: pricedCart.subtotalMinor,
discountMinor: pricedCart.discountMinor,
shippingMinor: pricedCart.shippingMinor,
taxMinor: pricedCart.taxMinor,
totalMinor: pricedCart.totalMinor,
lines: pricedCart.lines.map(line => ({
productId: line.productId,
variantId: line.variantId,
quantity: line.quantity,
unitPriceMinor: line.unitPriceMinor,
lineTotalMinor: line.lineTotalMinor,
pricingRuleVersion: line.pricingRuleVersion
}))
});Para değerlerinde binary floating-point yerine integer minor unit veya para hesabına uygun decimal type kullanılmalıdır. Currency exponent ve rounding kuralı sistem genelinde tutarlı olmalıdır.
Frontend total ile payment total ayrışması
Backend total’i doğru hesaplayabilir, fakat payment intent client tarafından oluşturuluyorsa veya provider’a farklı amount gönderiliyorsa açık devam eder. Şu eşitlikler server-side doğrulanmalıdır:
Order payable total
= Payment intent amount
= Captured amount
= Currency
= Merchant account
= Order referenceResponse ekranında 12.500 TL yazması güvenlik kanıtı değildir. Provider tarafında gerçekten hangi amount’ın authorize veya capture edildiği doğrulanmalıdır.
7. Kupon, gift card ve loyalty point abuse neden scanner’ın kör noktasıdır?
Kampanya function’ları çoğu zaman geçerli input ve normal endpoint kullanır. Sorun, aynı hakkın yanlış actor, order, channel veya sayıda tüketilebilmesidir.
Test edilmesi gereken abuse case’ler:
- Aynı kuponun aynı cart’a birden fazla uygulanması
- Birbirini dışlaması gereken kuponların stack edilmesi
- İlk alışveriş kuponunun birden fazla hesapla kullanılması
- Kuponun guest ve authenticated flow arasında tekrar kullanılması
- Expire olmuş kampanyanın timezone farkıyla kabul edilmesi
- Minimum sepet tutarının indirim sonrası yanlış hesaplanması
- İade sonrası kuponun haksız biçimde yeniden tanımlanması
- Gift card balance’ın parallel request ile iki kez harcanması
- Loyalty point’in order cancel edilmeden geri verilmesi
- Referral bonus’un self-referral ile üretilmesi
- Seller’ın kendi ürününde campaign subsidy’yi abuse etmesi
- Kupon kullanımının yalnızca cookie veya client state ile izlenmesi
Check-then-act race condition
Zafiyetli yaklaşım:
const coupon = await couponRepository.findActive(code);
const usage = await couponUsageRepository.countByUser(
coupon.id,
user.id
);
if (usage >= coupon.perUserLimit) {
throw new CouponLimitExceeded();
}
await couponUsageRepository.insert({
couponId: coupon.id,
userId: user.id,
orderId
});İki parallel transaction aynı usage değerini okuyup aynı kontrolü geçebilir. Application-level check tek başına atomic değildir.
Database constraint ve transaction ile invariant korunmalıdır:
CREATE UNIQUE INDEX uq_coupon_user_order
ON coupon_usage (coupon_id, user_id, order_id);Per-user total limit 1 ise daha dar bir unique constraint kullanılabilir:
CREATE UNIQUE INDEX uq_coupon_single_use_per_user
ON coupon_usage (coupon_id, user_id)
WHERE usage_status IN ('RESERVED', 'CONSUMED');Limit 1’den büyükse atomic counter, row lock veya isolation strategy gerekebilir. Hangi mekanizmanın seçileceği database, contention ve campaign modeline bağlıdır.
8. Checkout workflow atlanabiliyorsa ödeme kontrolü nerede olursa olsun eksiktir
Tipik checkout akışı tek bir request değildir:
Cart
→ Address selected
→ Shipping quoted
→ Promotion evaluated
→ Order reserved
→ Payment initiated
→ 3DS or provider flow
→ Payment authorized/captured
→ Order confirmed
→ Fulfillment startedHer transition yalnızca izin verilen previous state’ten gerçekleşmelidir. Frontend’in butonları sırayla göstermesi server-side workflow enforcement değildir.
Generic state update kritik açıktır
app.patch("/api/orders/:id", requireAuth, async (req, res) => {
const order = await orderRepository.findById(req.params.id);
order.status = req.body.status;
await orderRepository.save(order);
return res.sendStatus(204);
});Bu endpoint ownership kontrolü eklenerek bile güvenli hâle gelmez. Müşteri kendi siparişinin status değerini PAID, SHIPPED veya REFUNDED yapabilmemelidir.
State transition use-case-specific olmalıdır:
const allowedTransitions: Record<OrderStatus, OrderStatus[]> = {
CART: ["PAYMENT_PENDING", "CANCELLED"],
PAYMENT_PENDING: ["PAID", "PAYMENT_FAILED", "CANCELLED"],
PAID: ["FULFILLMENT_PENDING", "REFUND_PENDING"],
FULFILLMENT_PENDING: ["SHIPPED", "CANCELLED"],
SHIPPED: ["DELIVERED", "RETURN_REQUESTED"],
DELIVERED: ["RETURN_REQUESTED"],
PAYMENT_FAILED: ["PAYMENT_PENDING", "CANCELLED"],
REFUND_PENDING: ["REFUNDED", "REFUND_FAILED"],
REFUNDED: [],
RETURN_REQUESTED: ["RETURN_APPROVED", "RETURN_REJECTED"],
RETURN_APPROVED: ["REFUND_PENDING"],
RETURN_REJECTED: [],
CANCELLED: []
};Bu tablo tek başına yeterli değildir. Transition’ı hangi actor’ın ve hangi precondition ile yapabildiği de tanımlanmalıdır:
| Transition | Yetkili actor | Zorunlu kanıt |
|---|---|---|
CART → PAYMENT_PENDING | Customer | Güncel pricing ve stock reservation |
PAYMENT_PENDING → PAID | Payment event processor | Doğrulanmış provider event ve amount |
PAID → FULFILLMENT_PENDING | Order service | Fraud ve inventory kontrolleri |
SHIPPED → DELIVERED | Carrier integration veya operasyon | Doğrulanmış shipment event |
PAID → REFUND_PENDING | Yetkili customer flow veya finance | Refund eligibility ve kalan tutar |
REFUND_PENDING → REFUNDED | Payment event processor | Provider refund confirmation |
Success page order state değiştirmemelidir
Kullanıcının browser’ı şu URL’ye dönebilir:
/payment/return?orderId=...&status=successBu query parameter veya browser POST’u payment authority değildir. Return endpoint kullanıcıya deneyim sunabilir, ancak order state server-to-server doğrulanmış payment sonucu üzerinden değişmelidir.
Riskli pattern:
app.get("/payment/return", async (req, res) => {
if (req.query.status === "success") {
await orderRepository.markPaid(req.query.orderId as string);
}
return res.redirect("/account/orders");
});Doğru yaklaşım provider modeline göre signed callback, server-side payment status query veya her ikisini kullanır. Browser sonucu yalnızca display için kullanılır.
Cart ile order arasında pricing drift
Ürün fiyatı veya campaign, cart oluşturulduktan sonra değişebilir. Sistem şu kararı açıkça vermelidir:
- Fiyat cart’a eklendiğinde mi, checkout başladığında mı, payment anında mı sabitlenir?
- Reservation ne kadar süre geçerlidir?
- Expiration sonrası payment callback gelirse ne olur?
- Currency veya vergi kuralı değişirse hangi snapshot kullanılır?
- Seller fiyatı payment sırasında değiştirirse eski order etkilenir mi?
Belirsiz state modeli, hem müşteri kaybı hem abuse alanı üretir.
9. Payment integration güvenliğinde en kritik hata provider’a yanlış noktada güvenmektir
Payment provider kullanmak kart verisinin belirli bir bölümünü uygulama dışına taşıyabilir. Merchant uygulamasındaki authorization, order state, webhook, amount ve client-side script risklerini ortadan kaldırmaz.
Webhook verification yalnızca signature check değildir
Sağlam payment event işleme en az şu kontrolleri içerir:
- 1Provider’ın resmi SDK veya dokümante ettiği yöntemle raw request body üzerinde signature doğrulaması
- 2Timestamp tolerance ve replay değerlendirmesi
- 3Event ID için idempotency
- 4Event type allowlist
- 5Payment object ile local order arasında doğrulanmış ilişki
- 6Amount ve currency eşleşmesi
- 7Doğru merchant veya connected account kontrolü
- 8İzin verilen mevcut state’ten atomic transition
- 9Duplicate ve out-of-order event davranışı
- 10Audit ve reconciliation
Framework body’yi parse edip yeniden serialize ettikten sonra signature doğrulamak yanlış sonuç üretebilir. Provider signature’ı raw bytes üzerinde tanımlıyorsa raw body korunmalıdır.
Illustrative TypeScript:
app.post(
"/webhooks/payment",
rawBodyMiddleware,
async (req, res) => {
const signature = req.header("payment-signature");
const event = paymentProvider.webhooks.constructEvent(
req.rawBody,
signature,
process.env.PAYMENT_WEBHOOK_SECRET!
);
await paymentEventService.process(event);
return res.sendStatus(204);
}
);İşleme katmanı:
async function processPaymentCaptured(
event: PaymentCapturedEvent
): Promise<void> {
await database.transaction(async tx => {
const inserted = await tx.paymentEvents.insertIfAbsent({
providerEventId: event.id,
eventType: event.type,
processingStatus: "PROCESSING",
receivedAt: new Date()
});
if (!inserted) {
return;
}
const payment = await tx.payments.findByProviderPaymentId(
event.data.paymentId
);
if (!payment) {
throw new UnknownPaymentReference();
}
if (
payment.amountMinor !== event.data.amountMinor ||
payment.currency !== event.data.currency ||
payment.merchantAccountId !== event.accountId
) {
await tx.paymentEvents.markRejected(
event.id,
"PAYMENT_INTEGRITY_MISMATCH"
);
return;
}
const transitioned = await tx.payments.markCapturedIfPending({
paymentId: payment.id,
providerEventId: event.id,
capturedAt: event.createdAt
});
if (!transitioned) {
await tx.paymentEvents.markRejected(
event.id,
"UNEXPECTED_PAYMENT_STATE"
);
return;
}
await tx.paymentEvents.markProcessed(event.id);
});
}Bu örnek provider-neutral bir modeldir. Rejected event’ler transaction sonrasında security alert ve reconciliation üretmelidir. Signature formatı, event semantics ve retry davranışı kullanılan provider’ın resmi dokümantasyonuna göre uygulanmalıdır.
Metadata authority değildir
Payment provider metadata alanına orderId yazmak correlation için yararlı olabilir. Client ödeme nesnesi oluşturabiliyorsa metadata’yı da değiştirebilir. Local payment record, authenticated customer, order ve provider payment ID server-side bağlanmalıdır.
Amount verification’de kısmi ödeme ve currency
Sadece payment.status === "succeeded" kontrolü yetersizdir. Şunlar da doğrulanmalıdır:
- Beklenen amount
- Currency
- Authorized amount ile captured amount
- Partial capture
- Multiple payment attempt toplamı
- Refund ve chargeback sonrası net state
- Connected merchant account
- Production ve test mode ayrımı
3DS tek başına checkout güvenliği değildir
3DS kart sahibi doğrulamasına katkı sağlar. Order ownership, amount integrity, webhook authenticity, replay, refund ve seller authorization problemlerini çözmez.
10. Race condition ve idempotency zafiyetleri gerçek para kaybettirir
E-ticaret sisteminde aynı action’ın iki kez çalışması doğrudan maddi etki üretebilir:
- Aynı gift card balance’ın iki kez harcanması
- Son stok ürününün birden fazla müşteriye satılması
- Aynı order için iki refund
- Aynı kuponun iki kez tüketilmesi
- Loyalty point’in iki kez kazanılması veya harcanması
- Aynı payment callback ile iki fulfillment başlatılması
- Aynı withdrawal veya seller payout’ın iki kez yapılması
if kontrolü concurrency control değildir
const order = await orderRepository.findById(orderId);
if (order.refundedAmountMinor + amountMinor > order.paidAmountMinor) {
throw new RefundAmountExceeded();
}
await paymentProvider.refund(order.paymentId, amountMinor);
await orderRepository.addRefundedAmount(orderId, amountMinor);İki request aynı refundedAmountMinor değerini görüp kontrolü geçebilir. Remote side effect ile local update arasında crash olursa state daha da karmaşıklaşır.
Idempotency key nasıl tasarlanmalıdır?
Idempotency key:
- Actor ve operation scope’una bağlanmalı
- Request’in canonical hash’i ile ilişkilendirilmeli
- Unique constraint ile korunmalı
- Aynı key farklı payload ile gelirse reject edilmeli
- İlk başarılı response veya stable result saklanmalı
- Belirlenmiş retention süresine sahip olmalı
- Downstream provider’a da aktarılmalı
Örnek tablo:
CREATE TABLE idempotency_records (
actor_id VARCHAR(128) NOT NULL,
operation VARCHAR(64) NOT NULL,
idempotency_key VARCHAR(128) NOT NULL,
request_hash CHAR(64) NOT NULL,
resource_id VARCHAR(128),
status VARCHAR(32) NOT NULL,
response_code INTEGER,
response_body JSONB,
created_at TIMESTAMPTZ NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
PRIMARY KEY (actor_id, operation, idempotency_key)
);Idempotency, aynı business operation’ın iki kez sonuç üretmesini önlemeye yardımcı olur. Authorization ve business eligibility kontrolünün yerine geçmez.
Stock reservation
“Önce stock oku, sonra düş” pattern’i overselling üretir:
SELECT available_quantity
FROM inventory
WHERE sku = :sku;
UPDATE inventory
SET available_quantity = available_quantity - :quantity
WHERE sku = :sku;Atomic conditional update:
UPDATE inventory
SET available_quantity = available_quantity - :quantity
WHERE sku = :sku
AND available_quantity >= :quantity;Etkilenen row sayısı 1 değilse reservation başarısız sayılır. Reservation expiration ve abandoned checkout cleanup ayrıca tasarlanmalıdır.
Fiyat, kupon, state transition, idempotency ve race condition kontrollerinin kaynak kod üzerinden nasıl izlendiğini Kod İncelemesinde Business Logic Zafiyetleri Nasıl Yakalanır? yazısında ayrıntılı olarak ele alıyoruz.
11. API güvenliği storefront güvenliğinden ayrı test edilmelidir
SPA ve mobil uygulama, backend API’nin client’ıdır. Frontend’de butonu gizlemek, request field’ını disabled yapmak veya route’u menüden kaldırmak API authorization değildir.
OWASP API Security Top 10:2023 e-ticaret için özellikle şu riskleri görünür kılar:
- API1 Broken Object Level Authorization
- API2 Broken Authentication
- API3 Broken Object Property Level Authorization
- API4 Unrestricted Resource Consumption
- API5 Broken Function Level Authorization
- API6 Unrestricted Access to Sensitive Business Flows
- API7 Server Side Request Forgery
- API9 Improper Inventory Management
- API10 Unsafe Consumption of APIs
Broken Function Level Authorization
Customer token’ı admin function’ına erişebiliyor mu?
POST /api/admin/orders/{id}/refund
POST /api/sellers/{sellerId}/payout
POST /api/campaigns
GET /api/reports/customer-exportURL’de admin bulunması zorunlu değildir. Aynı route HTTP method değiştirilerek privileged function’a dönüşebilir:
GET /api/products/{id}
PATCH /api/products/{id}
DELETE /api/products/{id}Her method ve operation ayrı authorization kararı almalıdır.
Broken Object Property Level Authorization
Customer kendi profile object’ini değiştirebilir, fakat aşağıdaki alanları değiştirememelidir:
{
"displayName": "Example",
"role": "ADMIN",
"loyaltyBalance": 500000,
"sellerId": "other-seller",
"accountStatus": "VERIFIED",
"riskLevel": "LOW"
}DTO ve mapper yalnızca use-case’in izin verdiği alanları kabul etmelidir:
const updateMyProfileSchema = z.object({
displayName: z.string().min(1).max(100),
preferredLanguage: z.enum(["tr", "en"])
}).strict();Unknown field’ları sessizce ignore etmek bazı sistemlerde backward compatibility sağlar. Security-sensitive API’lerde reject etmek client hatalarını ve mass assignment denemelerini daha görünür kılabilir.
Unrestricted Access to Sensitive Business Flows
Şu function’lar teknik olarak public veya customer-accessible olabilir, fakat limitsiz otomasyon business kaybı yaratabilir:
- Limited stock satın alma
- Kupon ve gift card doğrulama
- Referral oluşturma
- Ücretsiz numune isteme
- Product reservation
- Review ve rating gönderme
- Password reset SMS/e-mail üretme
- Seller teklif verme
- Kargo fiyatı hesaplama
Rate limiting tek boyutlu olmamalıdır. Actor, account, device, payment instrument, address, product, campaign ve global inventory context’i birlikte gerekebilir.
12. Marketplace ve seller panelinde tenant isolation kritik sınırdır
Marketplace mimarisinde customer-to-customer IDOR’a ek olarak seller-to-seller erişim riski bulunur.
Seller’ın erişebileceği alanlar genellikle:
- Kendi ürün ve variant’ları
- Kendi inventory kayıtları
- Kendi order line’ları
- Fulfillment için gerekli sınırlı müşteri verisi
- Kendi payout ve commission bilgisi
- Kendi return ve dispute kayıtları
Seller bütün order’ı değil, yalnızca kendisine ait order line’ı görmelidir. Aynı sepet birden fazla seller içeriyorsa yanlış projection başka seller’ın ürününü, fiyatını, müşteri notunu veya operasyon bilgisini açabilir.
Seller ID request’ten alınmamalıdır
app.get("/api/seller/orders", requireSeller, async (req, res) => {
const sellerId = req.query.sellerId as string;
return res.json(
await orderRepository.findForSeller(sellerId)
);
});sellerId, authenticated seller membership’inden server-side türetilmelidir:
const sellerId = req.auth.requiredSellerId;
const orders = await orderRepository.findForSeller(sellerId);Bir kullanıcı birden fazla seller hesabında çalışabiliyorsa seçilen seller için membership ve role doğrulanıp trusted seller context oluşturulmalıdır.
Payout ve banka hesabı değişikliği
Seller payout account değişikliği account takeover sonrası yüksek etkili hedeftir. Şunlar değerlendirilmelidir:
- Re-authentication veya step-up
- MFA
- Mevcut ve yeni iletişim kanalına bildirim
- Cooling-off veya review period
- Dual approval
- Banka hesabı owner doğrulaması
- Değişiklik sonrası mevcut session’ların risk değerlendirmesi
- Audit ve anomaly detection
Sadece seller admin role’ü taşıyan session’a güvenmek yeterli olmayabilir.
13. Injection zafiyetleri e-ticaretin arama ve yönetim yüzeylerinde saklanabilir
Modern ORM ve framework’ler SQL injection riskini azaltabilir. Dynamic query, raw SQL, search syntax ve report builder kullanımları açık üretmeye devam eder.
Riskli alanlar:
- Product search ve filter
- Seller report
- Order export
- Coupon query
- Admin log search
- Dynamic sorting
- Warehouse veya ERP integration
- Elasticsearch/OpenSearch query
- NoSQL filter
- Server-side template
- CSV export
- Image processing command
Dynamic sort allowlist
Parameterization column name için kullanılamaz. User-controlled sort field doğrudan query’ye eklenmemelidir:
const sortableColumns = {
price: "price_minor",
createdAt: "created_at",
popularity: "sales_rank"
} as const;
const column =
sortableColumns[request.sortBy as keyof typeof sortableColumns];
if (!column) {
throw new InvalidSortField();
}
const direction = request.direction === "asc" ? "ASC" : "DESC";
const sql = `
SELECT id, name, price_minor
FROM products
WHERE tenant_id = $1
ORDER BY ${column} ${direction}
LIMIT $2
`;Value parametreleri yine parameterized gönderilmelidir. Allowlist yalnızca identifier ve direction gibi query structure parçaları içindir.
CSV injection
Seller veya admin export’unda product name, customer input veya address field’ı spreadsheet formula karakterleriyle başlıyorsa dosya açıldığında formula olarak yorumlanabilir. Export pipeline untrusted cell’leri uygun şekilde nötrleştirmeli, CSV çıktısı da güvenlik testine alınmalıdır.
14. SSRF e-ticaret entegrasyonlarını internal network’e köprü yapabilir
E-ticaret platformları URL alan fonksiyonları sık kullanır:
- Ürün görselini URL’den import etme
- Seller feed çekme
- Webhook test etme
- Kargo belgesi veya invoice alma
- Open Graph preview
- PDF veya screenshot üretme
- Marketplace integration
- Remote avatar ve logo yükleme
Zafiyetli örnek:
app.post("/api/seller/import-image", async (req, res) => {
const response = await fetch(req.body.url);
const bytes = await response.arrayBuffer();
const key = await mediaStore.save(bytes);
return res.json({ key });
});Bu function internal service’lere, cloud metadata endpoint’lerine veya local network’e request gönderebilir.
Yalnızca hostname allowlist yeterli değildir
Güvenli tasarım şu katmanları değerlendirmelidir:
- Gerekli değilse arbitrary URL alma özelliğini kaldırma
- Sabit ve işlevsel destination allowlist
- Scheme restriction
- URL parsing ve canonicalization
- DNS resolution sonrası bütün IP’leri doğrulama
- Private, loopback, link-local, multicast ve reserved range engeli
- Redirect’leri kapatma veya her hop’ta yeniden doğrulama
- Egress firewall ve proxy
- Response size, content type ve timeout limitleri
- Port restriction
- Request header ve credential izolasyonu
- Fetch worker’ını ayrı network segmentinde çalıştırma
SSRF remediation katmanlarını SSRF’yi Kapatmak İçin Yalnızca Allowlist Yeterli mi? yazısında ayrıntılı olarak ele alıyoruz.
15. File upload alanı yalnızca ürün görselinden ibaret değildir
E-ticaret uygulamalarında upload yüzeyi geniştir:
- Product image ve video
- Seller logo
- Invoice veya expense document
- Return kanıtı
- Support attachment
- CSV product import
- Kargo veya gümrük belgesi
- Identity ve company verification document
- Review görseli
Extension kontrolü yeterli değildir
Güvenli upload pipeline en az şu kontrolleri kapsamalıdır:
- İzin verilen extension ve MIME allowlist
- File signature veya content doğrulaması
- Size, dimension, page ve decompression limitleri
- Random server-generated object key
- Original filename’in storage path olarak kullanılmaması
- Web root dışında veya ayrı object storage
- Download sırasında güvenli
Content-TypeveContent-Disposition - Active content ve metadata değerlendirmesi
- Image re-encoding
- Malware scanning gerektiğinde quarantine
- Archive extraction için path traversal ve zip bomb kontrolü
- Upload ve download authorization
- Private document için kısa ömürlü signed URL ve doğru scope
Polyglot ve active content
Bir dosyanın image viewer’da açılması güvenli olduğu anlamına gelmez. SVG script içerebilir. HTML dosyası aynı origin altında render edilirse XSS üretebilir. PDF viewer ve office document parser’ları ayrı attack surface oluşturabilir.
Kapsamlı geliştirici kontrollerini Güvenli Dosya Yükleme İçin Geliştirici Kontrol Listesi sayfasında bulabilirsiniz.
16. XSS e-ticarette account takeover ve e-skimming zincirine dönüşebilir
Stored XSS için verimli giriş alanları:
- Product name ve description
- Seller store page
- Review ve question
- Gift message
- Customer support ticket
- Shipping note
- Coupon description
- CMS banner
- Search suggestion
- Admin log viewer
Seller’ın girdiği payload admin veya operasyon panelinde çalışıyorsa düşük yetkili seller privileged session’a ulaşabilir. Bu nedenle “yalnızca seller girebiliyor” güvenli bir varsayım değildir.
Context-aware output encoding
Tek bir sanitizer bütün context’lerde doğru değildir. Veri şu context’lerden hangisine yazılıyor?
- HTML body
- HTML attribute
- JavaScript string
- URL
- CSS
- JSON embedded in HTML
- DOM sink
Framework auto-escaping korunmalı, gerektiğinde context’e uygun encoding ve güvenilir sanitizer kullanılmalıdır. innerHTML, dangerouslySetInnerHTML, template bypass ve dynamic script creation call site’leri özel olarak incelenmelidir.
Payment page ve third-party script
Payment card field’ları iframe içinde provider tarafından sunulsa bile merchant checkout page’indeki bir script:
- Sahte form overlay oluşturabilir
- Kullanıcı girdilerini checkout öncesinde okuyabilir
- Payment iframe’i farklı kaynağa yönlendirebilir
- Form action veya redirect akışını değiştirebilir
- DOM’u manipüle ederek phishing arayüzü gösterebilir
PCI SSC’nin güncel payment page rehberi, e-commerce payment güvenliğinde script’lerin yetkilendirilmesi, integrity’sinin sağlanması ve sayfa değişikliklerinin tampering açısından izlenmesini vurgular.
Bu kapsamda:
- Payment page script inventory
- Her script için business justification ve owner
- Change authorization
- Integrity mechanism
- CSP ve mümkün olan yerde Subresource Integrity
- Tag manager governance
- Third-party script minimization
- Tampering detection
- Payment page değişiklik alert’i
birlikte değerlendirilmelidir.
17. Secret, cloud storage ve security misconfiguration hangi verileri açığa çıkarır?
E-ticaret uygulaması yalnızca source code ve database’den oluşmaz. CI/CD, object storage, CDN, container registry, feature flag, analytics ve support araçları aynı veri akışına bağlanır.
Sık incelenen exposure noktaları:
- Public object storage bucket
- Tahmin edilebilir invoice veya export URL’si
- Uzun ömürlü ve geniş yetkili signed URL
- Source map içinde internal endpoint veya secret
- Public
.env, backup, archive veya deployment artifact - CI log’unda access token
- Mobile application içinde production API key
- Client bundle içinde privileged secret
- Debug veya actuator endpoint
- Public GraphQL introspection ve test operation’ları
- Default admin credential
- Staging ortamında production verisi
- CDN cache’inde kişiye özel response
- Error response’unda stack trace ve internal object
Signed URL authorization yerine geçmez
Signed URL private object erişimini belirli süreyle mümkün kılabilir. URL oluşturulmadan önce kullanıcının ilgili invoice, shipment label veya seller document üzerinde yetkisi doğrulanmalıdır.
Riskli:
app.get("/api/download", requireAuth, async (req, res) => {
const url = await storage.createSignedUrl(
req.query.objectKey as string,
{ expiresInSeconds: 3600 }
);
return res.json({ url });
});Güvenli model:
app.get(
"/api/orders/:orderId/invoice",
requireAuth,
async (req, res) => {
const invoice = await invoiceRepository.findForCustomer({
orderId: req.params.orderId,
customerId: req.auth.subjectId,
tenantId: req.auth.tenantId
});
if (!invoice) {
return res.sendStatus(404);
}
const url = await storage.createSignedUrl(
invoice.privateObjectKey,
{
expiresInSeconds: 60,
responseContentDisposition: "attachment"
}
);
return res.json({ url });
}
);Signed URL log, analytics veya referrer üzerinden sızabilir. Expiration düşük tutulmalı, object key tahmin edilebilir olsa bile storage public olmamalı ve yüksek riskli belgelerde ek access pattern değerlendirilmelidir.
Secret ile public identifier ayrımı
Frontend’in ihtiyaç duyduğu publishable key ile server secret aynı değildir. Payment provider secret key, webhook secret, database credential ve private API token browser bundle’a konulmamalıdır.
Source repository içinde secret taraması şu dosyalarla sınırlı kalmamalıdır:
- Git history
- CI/CD variable ve log
- Container image layer
- Helm chart ve manifest
- Mobile binary
- Source map
- Backup ve artifact repository
- IaC state file
- Support ticket attachment
- Developer example configuration
Secret bulunduğunda yalnızca koddan silmek yeterli değildir. Credential revoke edilmeli, kullanım log’ları incelenmeli ve gerekli incident response süreci başlatılmalıdır.
CDN ve cache key hataları
Authenticated response CDN tarafından yanlış cache’lenirse bir müşterinin invoice’u başka müşteriye dönebilir. Authorization, cookie, tenant, language ve query parametrelerinin cache key davranışı incelenmelidir.
Hassas response için:
Cache-Control: no-storegibi uygun directive gerekebilir. Public product response ile private account response aynı cache policy’yi kullanmamalıdır.
18. Logging ve exceptional condition hataları e-ticarette nasıl zincir oluşturur?
OWASP Top 10:2025 listesinde Security Logging and Alerting Failures ile Mishandling of Exceptional Conditions ayrı risk alanlarıdır. E-ticaret için iki kategori doğrudan finansal süreçlere dokunur.
Hangi event’ler güvenlik açısından izlenmelidir?
- Başarısız ve riskli login
- Password reset ve e-mail değişikliği
- MFA ekleme veya kaldırma
- Yeni device ve session
- Kupon ve gift card doğrulama yoğunluğu
- Fiyat ve campaign rule değişikliği
- Payment amount mismatch
- Invalid webhook signature
- Duplicate veya out-of-order event
- Refund ve partial refund
- Seller payout değişikliği
- Cross-tenant access denemesi
- Admin ve support impersonation
- Bulk export
- Query filter veya tenant bypass
- Payment page script değişikliği
- Çok sayıda stock reservation ve cancellation
Log yalnızca event adını değil actor, tenant, resource, operation, result, reason category, correlation ID ve mümkün olduğunda risk context’ini taşımalıdır. Access token, password, CVV, full PAN ve gereksiz kişisel veri loglanmamalıdır.
Timeout başarı anlamına gelmemelidir
Payment provider veya fraud service timeout olduğunda aşağıdaki yaklaşım kritik hata üretir:
try {
await fraudService.check(order);
} catch {
return { approved: true };
}Availability baskısı authorization veya fraud kararını fail-open yapmamalıdır. Uygun davranış business risk’e göre PENDING_REVIEW, retry, circuit breaker veya işlemi durdurmak olabilir.
Partial failure ve reconciliation
Remote payment capture başarılı, local database update başarısız olabilir. Local refund kaydı oluşmuş, provider request’i timeout vermiş fakat aslında refund tamamlanmış olabilir.
Bu durumlarda:
- Stable provider idempotency key
- Outbox veya durable event
- Explicit pending state
- Retry policy
- Provider reconciliation job
- Manual review queue
- Duplicate-safe consumer
- Audit trail
gerekir.
Exception’ı yakalayıp generic success dönmek veya order’ı tahminle PAID yapmak veri bütünlüğünü bozar.
19. E-ticarette en sık bulunan kritik zafiyetler nasıl önceliklendirilmelidir?
“En sık” ifadesi her uygulamada aynı sıra bulunduğu anlamına gelmez. Platformun marketplace olması, guest checkout desteklemesi, kart verisini nasıl işlediği ve hangi third-party servisleri kullandığı risk sırasını değiştirir.
Saha değerlendirmesinde yüksek öncelikli kümeler şu şekilde özetlenebilir:
| Açık sınıfı | Tipik exploit sonucu | Neden kritik olabilir? |
|---|---|---|
| Account takeover | Hesap, adres, balance ve sipariş kontrolü | Geniş kullanıcı kitlesine ölçeklenebilir |
| IDOR/BOLA | Başka müşterinin order, invoice ve PII verisi | Tenant veya kullanıcı sınırını kırar |
| Fiyat manipülasyonu | Eksik tahsilatla ürün alımı | Doğrudan finansal kayıp üretir |
| Checkout bypass | Ödemesiz veya yanlış state’li order | Fulfillment yanlışlıkla başlayabilir |
| Webhook forgery/replay | Sahte ödeme veya tekrar işleme | Server trust boundary’sini bozar |
| Coupon/gift card abuse | Aynı değerin çoklu tüketimi | Otomasyona ve concurrency’ye açıktır |
| Duplicate refund | Tahsilattan fazla iade | Doğrudan para çıkışı üretir |
| Seller isolation hatası | Başka mağazanın order ve PII verisi | Marketplace tenant sınırını kırar |
| Stored XSS | Admin session ve payment page manipülasyonu | Düşük yetkiden privileged context’e ulaşabilir |
| SSRF | Internal service ve cloud metadata erişimi | Uygulama arkasındaki network’e sıçrayabilir |
| Injection | Database, OS veya template etkisi | Toplu veri ihlali veya code execution üretebilir |
| Public storage/secret | Invoice, export veya credential sızıntısı | Uygulama dışındaki asset’i etkiler |
Severity ile business impact ayrılmalıdır
Bir finding’in CVSS skoru önemlidir, fakat tek başına karar vermez. E-ticaret raporunda şu context de yazılmalıdır:
- Etkilenen müşteri veya seller sayısı
- Tek object mi, bulk data mı olduğu
- Para veya ürün kaybı
- Gerekli mevcut yetki
- Otomasyona uygunluk
- Exploit için yarış penceresi
- Detection olasılığı
- Geri alma ve reconciliation imkânı
- Third-party ve compliance etkisi
Örneğin tek siparişte 10 TL rounding farkı düşük görünebilir. Aynı işlem milyonlarca order’da otomatik uygulanabiliyorsa business impact değişir.
20. PCI DSS, KVKK ve Güven Damgası bağlamı nasıl okunmalıdır?
E-ticaret sızma testi compliance checklist’ine indirgenmemelidir. Buna karşılık ödeme ve kişisel veri işleyen sistemlerde teknik bulguların compliance etkisi de doğru anlaşılmalıdır.
PCI DSS
PCI DSS scope, kart verisinin merchant sistemlerine nasıl temas ettiğine göre değişir. Redirect, embedded iframe, hosted field ve merchant-controlled payment page aynı scope’u üretmeyebilir.
PCI DSS v4.0.1 kapsamındaki e-commerce payment page kontrolleri, özellikle payment page script’lerinin:
- Yetkilendirilmesini
- Integrity açısından güvenceye alınmasını
- Envanterlenmesini ve gerekçelendirilmesini
- Unauthorized change ve tampering açısından izlenmesini
öne çıkarır.
SAQ A raporlama koşullarında 2025’te yapılan değişiklikler, underlying payment page riskini ortadan kaldırmamıştır. PCI SSC, embedded payment form kullanan merchant’lar için sitenin e-commerce sistemini etkileyebilecek script saldırılarına açık olmadığının doğrulanmasını ele alır.
Hangi SAQ veya assessment yönteminin geçerli olduğuna acquirer, payment brand ve yetkili compliance tarafıyla karar verilmelidir. Sızma testi firması tek başına PCI uyumluluğu ilan etmemelidir.
KVKK
E-ticaret uygulamalarında kimlik, iletişim, adres, sipariş, fatura, device ve davranış verileri işlenebilir. Teknik inceleme açısından amaç:
- Gereksiz data exposure
- Yetkisiz erişim
- Zayıf access control
- Public storage
- Log ve analytics sızıntısı
- Retention sonrası erişilebilir veri
- Third-party aktarım yüzeyi
gibi riskleri belirlemektir.
KVKK compliance kararı yalnızca teknik test sonucundan çıkarılamaz. Hukuki dayanak, aydınlatma, veri işleme amacı, aktarım ve retention gibi idari ve hukuki unsurlar ayrıca değerlendirilir.
Elektronik Ticarette Güven Damgası
Türkiye’de Güven Damgası sistemi, güvenlik ve hizmet kalitesi standartlarını destekleyen bir yapı olarak düzenlenmiştir. Ticaret Bakanlığı kaynakları, sistem kapsamında belirli aralıklarla gerçekleştirilen sızma testleriyle zafiyetlerin tespit edilmesini güvenlik yaklaşımının bir parçası olarak ifade eder.
Güven Damgası sahibi olmak uygulamanın sürekli açık taşımadığı anlamına gelmez. Release, integration, campaign ve architecture değiştikçe attack surface yeniden değerlendirilmelidir.
21. E-ticaret sızma testi kapsamı nasıl kurulmalıdır?
İyi kapsam “web sitesi test edilecek” cümlesinden daha ayrıntılıdır.
Varlıklar
- Production ve test domain’leri
- API gateway ve API host’ları
- Mobil backend
- Seller, admin ve support paneli
- Static asset, CDN ve object storage
- Payment return ve webhook endpoint’leri
- Kargo, ERP, OMS, CRM ve fraud integration
- GraphQL, WebSocket ve asynchronous consumer yüzeyi
Roller
- Anonymous
- Guest checkout
- En az iki customer
- En az iki seller veya tenant
- Seller çalışanı ve administrator
- Support
- Finance ve refund operator
- Campaign manager
- Platform administrator
- Integration/service account
Business flow’lar
- Registration, login, MFA ve recovery
- Cart ve cart merge
- Pricing ve promotion
- Checkout
- Payment initiation, 3DS ve callback
- Order confirmation
- Cancellation
- Return ve refund
- Gift card ve loyalty
- Seller product ve inventory
- Payout
- Invoice, export ve document download
Test verisi ve entegrasyon
- Test ürünleri
- Düşük değerli payment yöntemi veya provider sandbox
- Kupon ve gift card
- Stock-limited ürün
- Refund edilebilir order
- Farklı tenant ve owner object’leri
- Webhook replay verisi
- Test e-mail ve telefon kanalı
Kapsam dışı ve üçüncü taraf izinleri
Payment provider, CDN, SaaS support platformu ve kargo servisi customer’ın doğrudan test yetkisi dışında olabilir. Test scope’u hangi host’un, hangi integration’ın ve hangi davranışın yetkili olduğunu açıkça belirtmelidir.
Üçüncü taraf servise saldırı yapılmadan merchant tarafındaki integration doğrulanabilir:
- Signature verification
- Callback replay
- Amount ve order binding
- Redirect handling
- Error ve timeout behavior
- Credential scope
- Data minimization
Kapsam formu tek başına sınırsız test yetkisi değildir. SoW, Rules of Engagement ve gerekli third-party izinleriyle birlikte değerlendirilmelidir.
22. Production ortamında e-ticaret testi nasıl güvenli yürütülür?
E-ticaret sızma testi gerçek ödeme, stock, müşteri iletişimi ve fulfillment etkisi üretebilir. Test derinliği korunurken operasyonel sınırlar önceden belirlenmelidir.
Rules of Engagement içinde bulunması gerekenler
- Test tarih ve saatleri
- Yetkili kaynak IP’ler
- Acil durdurma iletişimi
- Test hesapları ve roller
- Gerçek ödeme üst sınırı
- Refund ve reversal yöntemi
- Sipariş ve fulfillment’ın durdurulma noktası
- SMS, e-mail ve push notification limiti
- Stock reservation sınırı
- Race condition concurrency üst sınırı
- Rate-limit ve availability test sınırı
- Upload ve malware simulation yöntemi
- PII erişim ve kanıt redaction kuralı
- Third-party sistemlere dokunmama sınırı
- Finding notification eşiği
Destructive test ile doğrulama aynı şey değildir
Bir duplicate refund riskini kanıtlamak için yüksek tutarlı gerçek müşteriye iki refund göndermek gerekmez. Test merchant, test order, düşük tutar ve kontrollü concurrency ile root cause doğrulanabilir.
Benzer şekilde unrestricted resource consumption testinde production’ı DoS etmek gerekmez. Limit bulunmadığı kontrollü artış, server metric ve architecture review ile kanıtlanabilir.
Evidence minimum olmalıdır
PoC için gereğinden fazla müşteri verisi indirilmemelidir. Birkaç kontrollü object ile cross-account erişim kanıtlanabiliyorsa bulk export çalıştırılmamalıdır.
Kanıt paketi:
- Redacted request-response
- Test actor ve resource ilişkisi
- Precondition
- Tekrarlanabilir adımlar
- Minimum veri örneği
- Zaman ve correlation ID
- İş etkisi
- Cleanup bilgisi
içermelidir.
23. E-ticaret bulgusu nasıl raporlanmalı ve retest edilmelidir?
“Fiyat değiştirilebiliyor” ifadesi geliştirici için yeterli değildir. Root cause ve güven sınırı gösterilmelidir.
Örnek finding
Başlık: Client-controlled unitPrice nedeniyle düşük tutarla order oluşturma
Etkilenen component: Checkout API
Entry point: POST /api/checkout
Ön koşul: Authenticated customer ve satılabilir ürün
Root cause: Backend, ürünün authoritative catalog price değerini almak yerine request body’deki unitPrice alanını payment amount ve order total hesabında kullanıyor.
Attack path:
- 1Customer ürünü cart’a ekler.
- 2Checkout request’ini intercept eder.
- 3
unitPricedeğerini düşürür. - 4Backend değiştirilmiş total ile payment intent ve order oluşturur.
- 5Düşük tutarlı payment başarılı olduğunda order fulfillment’a ilerler.
Etkisi: Ürünün gerçek satış fiyatından düşük tutarla satın alınması, campaign ve muhasebe verisinin bozulması, otomasyonla ölçeklenebilir finansal kayıp.
Remediation: Client’tan yalnızca product/variant ID ve quantity al. Fiyatı server-side authoritative catalog ve pricing engine üzerinden hesapla. Order’a immutable pricing snapshot yaz. Payment amount, currency ve order total eşleşmesini provider event’inde yeniden doğrula.
Regression test: Request’te fiyat alanı gönderildiğinde reject veya ignore edilmeli. Catalog price, order total, payment amount ve captured amount aynı olmalı. Web, mobile ve guest checkout path’leri ayrı test edilmeli.
Retest yalnızca eski payload’ı çalıştırmamak değildir
Retest şu sorulara cevap vermelidir:
- Root cause kaldırıldı mı?
- Web ve mobil API aynı düzeltmeyi kullanıyor mu?
- Guest ve authenticated checkout korunuyor mu?
- Bulk endpoint veya eski API version’ı açık mı?
- Alternate parameter ve currency path’i var mı?
- Negative regression test CI/CD’ye eklendi mi?
- Payment callback aynı invariant’ı yeniden doğruluyor mu?
- Log ve alert üretimi çalışıyor mu?
24. E-ticaret güvenliği kontrol listesi
Account ve session
- [ ] Login, reset ve OTP endpoint’lerinde adaptive abuse control var mı?
- [ ] Account enumeration engelleniyor mu?
- [ ] Password reset token’ı tek kullanımlık ve kısa ömürlü mü?
- [ ] Password değişince mevcut session ve refresh token’lar iptal oluyor mu?
- [ ] E-mail, MFA ve payment method değişikliğinde re-authentication var mı?
- [ ] Login sonrası session ID rotate ediliyor mu?
- [ ] Logout server-side session’ı geçersiz kılıyor mu?
- [ ] Guest cart merge başka account verisini bağlamıyor mu?
Authorization ve tenant
- [ ] Order, invoice, address ve shipment lookup actor ile bağlanıyor mu?
- [ ] UUID secrecy authorization yerine kullanılmıyor mu?
- [ ] Customer, seller, support ve admin ayrı policy alıyor mu?
- [ ] Seller yalnızca kendi order line ve customer data subset’ini görüyor mu?
- [ ] Child object gerçekten route’taki parent’a ait mi?
- [ ] Bulk export row-level authorization uyguluyor mu?
- [ ] Object property authorization DTO ve projection ile korunuyor mu?
- [ ] Mobil ve eski API version’ları aynı control’ü uyguluyor mu?
Pricing ve campaign
- [ ] Price, discount, tax, shipping ve total server-side hesaplanıyor mu?
- [ ] Currency ve exchange rate client’tan authority olarak alınmıyor mu?
- [ ] Order immutable pricing snapshot içeriyor mu?
- [ ] Coupon stacking kuralları server-side enforce ediliyor mu?
- [ ] Gift card ve loyalty balance atomic tüketiliyor mu?
- [ ] İlk kullanım ve per-user limitleri account dışı abuse context’ini değerlendiriyor mu?
- [ ] Campaign timezone ve expiration davranışı test edildi mi?
- [ ] İade sonrası kupon ve point geri verme kuralı doğru mu?
Checkout ve payment
- [ ] State transition’lar explicit ve actor-specific mi?
- [ ] Success return URL order’ı
PAIDyapmıyor mu? - [ ] Webhook raw body üzerinde resmi yöntemle doğrulanıyor mu?
- [ ] Event ID idempotency ile korunuyor mu?
- [ ] Amount, currency, merchant ve order reference eşleşiyor mu?
- [ ] Duplicate ve out-of-order event test edildi mi?
- [ ] Partial capture, refund ve chargeback state’i tanımlı mı?
- [ ] Payment timeout ve partial failure reconciliation’a giriyor mu?
- [ ] 3DS sonucu diğer authorization kontrollerinin yerine kullanılmıyor mu?
Concurrency
- [ ] Stock reservation atomic mi?
- [ ] Duplicate refund engelleniyor mu?
- [ ] Idempotency key actor, operation ve request hash ile bağlı mı?
- [ ] Aynı key farklı payload ile kullanıldığında request reddediliyor mu?
- [ ] Database constraint business invariant’ı destekliyor mu?
- [ ] Parallel coupon, gift card ve loyalty testleri var mı?
- [ ] Downstream provider idempotency kullanılıyor mu?
API ve integration
- [ ] Bütün API host ve version’ları envanterde mi?
- [ ] BOLA, BOPLA ve BFLA test edildi mi?
- [ ] Sensitive business flow’lar otomasyon abuse’una karşı korunuyor mu?
- [ ] URL-fetch function’ları SSRF katmanlarıyla korunuyor mu?
- [ ] Webhook source, integrity ve replay kontrolü var mı?
- [ ] Third-party response’lar untrusted input gibi validate ediliyor mu?
- [ ] Error ve timeout path’leri fail-open değil mi?
Client, upload ve supply chain
- [ ] Stored XSS seller ve admin context’inde test edildi mi?
- [ ] Active content same-origin render edilmiyor mu?
- [ ] Upload content, size, storage ve download authorization ile korunuyor mu?
- [ ] Payment page script inventory ve owner listesi var mı?
- [ ] Third-party script change ve integrity izleniyor mu?
- [ ] Tag manager erişimi least privilege ile sınırlandırılmış mı?
- [ ] Source map ve browser bundle secret içermiyor mu?
- [ ] Dependency ve build artifact integrity kontrolü var mı?
Veri, cloud ve operasyon
- [ ] Private bucket ve object’ler public değil mi?
- [ ] Signed URL üretmeden önce object authorization yapılıyor mu?
- [ ] Hassas response cache’lenmiyor mu?
- [ ] Staging production verisi taşımıyor mu?
- [ ] Secret’lar revoke ve rotate edilebilir mi?
- [ ] Payment, refund ve admin event’leri audit ediliyor mu?
- [ ] Log’lar token, CVV, full PAN ve gereksiz PII içermiyor mu?
- [ ] Production test için RoE ve emergency stop tanımlı mı?
26. Sonuç: E-ticaret güvenliği ödeme sayfasından önce başlar, refund’dan sonra bitmez
E-ticaret uygulamasındaki kritik risk her zaman karmaşık bir payload’dan doğmaz. Çoğu zaman kullanılan endpoint meşru, request schema’ya uygun ve kullanıcı authenticated’dir.
Açık şu yanlış güven kararlarından birinde oluşur:
- Client’ın fiyatı belirleyebileceğine güvenmek
- Login olan kullanıcının istediği order’ı görebileceğini varsaymak
- Seller role’ünün bütün seller verisine yettiğini düşünmek
- Browser’daki success sonucunu payment kanıtı saymak
- Signature doğrulanmış event’in doğru order ve amount’a ait olduğunu ayrıca kontrol etmemek
- Application-level
ifkontrolünün parallel request’leri durduracağını varsaymak - Payment provider kullanıldığı için merchant sayfasındaki script riskini önemsiz görmek
- UUID, signed URL veya hidden button’ı authorization kabul etmek
Güçlü e-ticaret sızma testi bu kararları tek tek değil, attack path olarak değerlendirir:
- 1Actor kim ve identity nasıl oluşuyor?
- 2Hangi customer, seller veya tenant adına işlem yapıyor?
- 3Resource kime ait?
- 4Fiyat ve campaign verisinin authoritative source’u hangisi?
- 5Order hangi state’te?
- 6Bu transition’ı hangi actor hangi kanıtla yapabilir?
- 7Payment amount, currency ve order nasıl bağlanıyor?
- 8Aynı action duplicate veya parallel çalışırsa ne oluyor?
- 9Web, mobile, API, webhook ve background consumer aynı invariant’ı koruyor mu?
- 10Failure ve retry sonrasında sistem nasıl reconcile oluyor?
Scanner coverage sağlar. Gerçek riskin anlaşılması için manuel exploitation, business logic analizi, API authorization testi, payment integration review ve kontrollü concurrency gerekir.
SECNODEX’in Sızma Testi hizmeti, e-ticaret uygulamalarını yalnızca otomatik tarama sonucu üzerinden değerlendirmez. Web, API ve ilgili uygulama yüzeyleri uzmanlar tarafından manuel olarak incelenir. Doğrulanmış bulgular, replay edilebilir PoC, iş etkisi, uygulanabilir remediation ve retest sonucu ile raporlanır.
Checkout, payment, seller paneli ve mobil backend’iniz için doğru test kapsamını belirlemek üzere SECNODEX ile iletişime geçebilirsiniz.
Kaynaklar ve ileri okuma
- OWASP Top 10:2025
- OWASP API Security Top 10:2023
- OWASP Web Security Testing Guide — Business Logic Testing
- OWASP WSTG — Test Number of Times a Function Can Be Used Limits
- OWASP WSTG — Testing for the Circumvention of Work Flows
- OWASP Web Security Testing Guide
- OWASP Application Security Verification Standard 5.0.0
- PCI SSC — Payment Page Security and Preventing E-Skimming
- PCI SSC — Updated SAQ A Eligibility Criteria for E-Commerce Merchants
- T.C. Ticaret Bakanlığı — Elektronik Ticaret Mevzuatı
- T.C. Ticaret Bakanlığı — Elektronik Ticarette Güven Damgası
- Kişisel Verileri Koruma Kurumu — E-Ticaret Sitesi Veri İhlali Karar Özeti
- MITRE CWE-639 — Authorization Bypass Through User-Controlled Key
- MITRE CWE-841 — Improper Enforcement of Behavioral Workflow
- MITRE CWE-362 — Concurrent Execution Using Shared Resource with Improper Synchronization
<!--
EDİTORYAL INTERNAL LINK NOTU
Bu içerik Sızma Testi pillar'ının e-ticaret ve business logic cluster yazısıdır.
Ana pillar:
- /blog/sizma-testi-nedir-kapsamli-rehber
Destek içerikleri:
- /blog/web-uygulamasi-sizma-testinde-kapsam-nasil-belirlenir
- /blog/idor-acigi-neden-hala-bu-kadar-yaygin
- /blog/oturum-yonetiminde-en-sik-yapilan-hatalar
- /blog/ssrfyi-kapatmak-icin-yalnizca-allowlist-yeterli-mi
- /blog/guvenli-dosya-yukleme-gelistirici-kontrol-listesi
- /blog/kod-incelemesinde-business-logic-aciklari-nasil-yakalanir
Bu cluster yazısından pillar'a ilk iki bölüm içinde doğal bağlantı verilmiştir.
Pillar içindeki "Sık Bulunan Zafiyetler", "Sızma Testi Türleri" veya "Web Uygulaması Sızma Testi" bölümünden bu yazıya geri link verilmelidir.
Ana hizmet bağlantısı /hizmetler/sizma-testi olmalıdır.
FAQPage schema yalnızca sayfada görünen 12 soru-cevapla birebir eşleşmelidir.
-->
Sık sorulan sorular
E-ticaret sızma testi nedir?
E-ticaret sızma testi, storefront, API, mobil backend, seller ve admin paneli, checkout, payment integration ve sipariş yaşam döngüsünün yetkilendirilmiş saldırı senaryolarıyla değerlendirilmesidir.
E-ticaret sitesinde en kritik zafiyetler hangileridir?
Account takeover, IDOR/BOLA, fiyat manipülasyonu, checkout bypass, sahte veya replay edilmiş payment callback, duplicate refund, coupon/gift card abuse, seller tenant isolation hatası, stored XSS, SSRF ve injection en kritik sınıflar arasındadır.
Otomatik vulnerability scan yeterli midir?
Hayır. Scanner bilinen teknik pattern’leri ve geniş attack surface’i kontrol edebilir. Fiyatın kim tarafından belirlenmesi gerektiği, kuponun kaç kez kullanılabileceği veya payment state’in hangi event ile değişmesi gerektiği manuel business logic testi gerektirir.
Payment provider kullanmak kart ve ödeme güvenliği için yeterli midir?
Hayır. Provider kart işlemenin belirli bölümünü üstlenebilir. Merchant uygulamasındaki order authorization, amount binding, webhook verification, payment page script, refund ve state transition riskleri devam eder.
3DS bütün ödeme zafiyetlerini engeller mi?
Hayır. 3DS kart sahibi doğrulamasına katkı sağlar. Fiyat manipülasyonu, yanlış order binding, sahte callback, duplicate refund, IDOR ve seller authorization problemlerini çözmez.
E-ticaret testinde gerçek ödeme yapılır mı?
Payment flow’un gerçek davranışını doğrulamak için provider sandbox veya önceden onaylanmış düşük tutarlı test işlemleri kullanılabilir. Tutar, refund yöntemi ve fulfillment etkisi Rules of Engagement içinde belirlenmelidir.
Üretimde race condition testi güvenli midir?
Kontrollü test hesapları, düşük değerli object’ler ve önceden belirlenmiş concurrency sınırıyla yapılabilir. Amaç availability bozmak değil business invariant’ın parallel execution altında korunup korunmadığını doğrulamaktır.
E-ticaret API’si ayrıca test edilmeli midir?
Evet. Web ve mobil client aynı veya farklı API version’larını kullanabilir. Object, function ve property-level authorization, rate limit ve inventory problemleri yalnızca UI testiyle görünmeyebilir.
Seller paneli neden ayrı kapsama alınmalıdır?
Seller paneli tenant sınırı, customer PII, product price, inventory ve payout verisine erişir. Seller-to-seller IDOR ve payout account takeover, marketplace için doğrudan finansal ve gizlilik riski üretir.
PCI DSS uyumluluğu sızma testiyle sağlanır mı?
Sızma testi PCI DSS güvenlik programının bir parçası olabilir, fakat tek başına uyumluluk kararı vermez. Scope ve validation yöntemi payment architecture, acquirer ve payment brand gereksinimlerine göre belirlenir.
E-ticaret sızma testi ne zaman yapılmalıdır?
Büyük release, checkout veya payment provider değişikliği, mobil API yenilemesi, marketplace/seller özelliği, campaign engine değişikliği ve security incident sonrasında yapılmalıdır. Periyodik test, sürekli zafiyet yönetimi ve release bazlı security regression birlikte yürütülmelidir.
E-ticaret sızma testi raporu neleri içermelidir?
Yönetici özeti, teknik root cause, etkilenen actor-resource-operation, redacted request-response, replay edilebilir PoC, business impact, risk skoru, uygulanabilir remediation, pattern expansion ve retest sonucu içermelidir.
Okumaya devam et
Kaynak Kod Analizi
Kod İncelemesinde İş Mantığı (Business Logic) Açıkları Nasıl Yakalanır?
Business logic açıkları çoğu zaman geçerli request’ler, izin verilen endpoint’ler ve syntactically doğru veriler kullanılarak ortaya çıkar. Bu nedenle etkili kod incelemesi yalnızca tehlikeli function aramaz, uygulamanın değişmez iş kurallarını, state transition’larını ve transaction sınırlarını kanıt üzerinden değerlendirir.
Yazıyı okuWeb Uygulama Güvenliği
IDOR Açığı Neden Hâlâ Bu Kadar Yaygın?
IDOR, identifier tahmin edilebildiği için değil, server her object access sırasında doğru authorization kararını veremediği için oluşur. Yaygınlığın mimari ve süreç nedenlerini inceliyoruz.
Yazıyı oku