İstemci-sunucu sınırını güvence altına alma

*Bu içerik, yapay zekâ (beta) kullanılarak çevrildi ve hatalar içerebilir. Sayfayı İngilizce görüntülemek için buraya tıkla.

Bir istemci sunucuda bir eylemi tetikleyebiliyorsa, bu istismar potansiyeli taşır. RemoteEvents ve RemoteFunctions burada en yaygın saldırı vektörleridir, ancak ProximityPrompt gibi diğer durumlar da hassastır. Bu bölüm, bu sınırın nasıl güvence altına alınacağını kapsar.

Uzaktan girişlerin doğrulanması

Bir istemciden gönderilen her veri parçası, kullanılmadan önce sunucu tarafından doğrulanmalıdır. Uzaktan olayın ne yaptığına bağlı olarak bu doğrulama katmanlarını uygulayın.

Bağlam/izin doğrulaması

Bu, deneyimin durumunu, ilerlemesini veya diğer oyuncuları etkileyen uzantılar için gereklidir. Sunucu, oyuncunun isteği yapmak için gerekli izinlere sahip olup olmadığını doğrulamalıdır. Örneğin, oyuncu bir şey satın almak için bir dükkana yeterince yakın mı? Kapıyı açmak için gerekli bir anahtara sahip mi? Karakteri hayatta mı?

Doğrulama, aşağıdaki durumlar için gereklidir:

  • Ödüller vermek veya oyuncu ilerlemesini değiştirmek
  • Diğer oyuncuları veya paylaşılan deneyim durumunu etkilemek
  • Mesafe, zamanlama veya izin gereksinimlerine sahip eylemler gerçekleştirmek (örneğin, dükkana mesafe)

Tür ve yapı doğrulaması

Diğer bir istismar biçimi, kötü niyetli kullanıcıların teknik olarak geçerli türler göndermesi ancak bunları son derece büyük, uzun veya başka bir şekilde bozuk hale getirmesidir. Örneğin, bir sunucunun uzunluğa göre ölçeklenen bir dize üzerinde pahalı bir işlem gerçekleştirmesi gerekiyorsa, bir kötü niyetli kullanıcı sunucu üzerinde yük oluşturmak için son derece büyük veya bozuk bir dize gönderebilir.

Kötü niyetli kullanıcıların kullanabileceği bir diğer yaygın saldırı, tables yerine bir Instance göndermektir. Karmaşık yükler, normalde sıradan bir nesne referansını taklit edebilir.

Örneğin, fiyat gibi öğe verilerinin NumberValue nesnelerinde saklandığı bir deneyim içi dükkân sistemi sağlanırsa, bir kötü niyetli kullanıcı, şu şekilde diğer tüm kontrolleri geçebilir:

StarterPlayerScripts içindeki LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local payload = {
Name = "Ultra Blade",
ClassName = "Folder",
Parent = itemDataFolder,
Price = {
Name = "Price",
ClassName = "NumberValue",
Value = 0, -- Negatif değerler de kullanılabilir, bunun sonucunda para vermektense almak mümkün olabilir!
},
}
-- Kötü niyetli yükü sunucuya gönder (bu reddedilecektir)
print(buyItemEvent:InvokeServer(payload)) -- "false Geçersiz öğe sağlandı" çıktısını verir
-- Sunucuya gerçek bir item gönder (bu geçecektir!)
print(buyItemEvent:InvokeServer(itemDataFolder["Real Blade"])) -- "true" çıktısını verir ve satın alım başarılı olursa kalan parayı gösterir
ServerScriptStorage içindeki Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local function buyItem(player, item)
-- Geçerli öğenin sahte olmadığını ve ItemData klasöründe olduğunu kontrol et
if typeof(item) ~= "Instance" or not item:IsDescendantOf(itemDataFolder) then
return false, "Geçersiz öğe sağlandı"
end
-- Sunucu, aşağıdaki örnek akışa göre satın almayı işleme alabilir
end
-- "buyItem()" fonksiyonunu uzaktan fonksiyonun geri çağırma işlevine bağla
buyItemEvent.OnServerInvoke = buyItem

Değer doğrulaması

Türleri ve verileri doğrulamanın yanı sıra, RemoteEvents ve RemoteFunctions aracılığıyla iletilen değerlerin, talep edilen bağlamda geçerli ve mantıklı olduğundan emin olmalısınız. Bu, para, öğeler, sayısal girişler veya kullanıcı tarafından oluşturulan içerik ile ilgili uzantılar için gereklidir. Değerlerin beklenen sınırlar içinde (örneğin, satın alma miktarının sıfırdan büyük olması) olduğundan ve sağlanan kimliklerin veya adların geçerli olduğundan emin olmalısınız (örneğin, bir itemId'nin oyununuzda gerçek bir öğeye karşılık gelmesi vb.).

Sayısal değerler için özel dikkate alınması gereken hususlar: Hem inf hem de NaN geçerli sayı türleridir, ancak bir kötü niyetli kullanıcı bunları gönderdiğinde ve doğru bir şekilde işlenmediğinde büyük sorunlara yol açabilir. Bunları tespit etmek ve reddetmek için aşağıdaki gibi işlevler kullanın:


local function isNaN(n: number): boolean
-- NaN, asla kendisiyle eşit değildir
return n ~= n
end
local function isInf(n: number): boolean
-- Sayı -inf ya da +inf olabilir
return math.abs(n) == math.huge
end

NaN tehlikesi

Bir kötü niyetli kullanıcı, bir argüman olarak NaN (Sayı Değil) gönderebilir. NaN, "sayı" türündedir ama tüm standart karşılaştırmaları geçmez, böylece mantıklı kontrolleri gizlice geçebilir. Bir oyuncunun bir teklif yaptığı zayıf bir takas sistemi örneğine bakalım.


-- ZAYIF SUNUCU KODU
local function onCreateTradeOffer(player, offeredGold)
-- 1. TÜR DOĞRULAMASI: Bu geçer! typeof(NaN) "sayı" dır.
if typeof(offeredGold) ~= "number" then
return "Geçersiz teklif"
end
-- 2. ARALIK KONTROLÜ: Bu geçiş yapıldı!
-- (NaN < 0) yanlıştır. (NaN > 1000000) da yanlıştır. Kontrol etkisizdir.
if offeredGold < 0 or offeredGold > 1000000 then
return "Teklif aralığın dışında"
end
-- 3. ENVANTER KONTROLÜ: Bu geçiş yapıldı!
-- (NaN > player.Gold.Value) yanlıştır.
if offeredGold > player.Gold.Value then
return "Yeterli altın yok"
end
-- ZAYIFLIK: NaN altın ile sahte bir ticaret teklifi oluşturuldu!
createTrade(player, {gold = offeredGold})
return "Ticaret teklifi oluşturuldu."
end

Kötü niyetli kullanıcı, hiçbir altına sahip olmadan bir ticaret teklifi oluşturmayı başardı çünkü her kontrol sessizce başarısız oldu. Dahası, bu tek bir NaN değeri, onu kullanmaya çalışan diğer sistemlerin hepsini zehirleyecek ve teklif aracılığıyla diğer oyunculara yayılacaktır.

Aşağıda, yaygın oyun içi özelliklerin güvenli tasarımıyla ilgili birkaç yüksek seviyeli örnek bulunmaktadır.

Deneyim içi dükkân

Bir kullanıcı arayüzüne sahip bir deneyim içi dükkan sistemini düşünün; örneğin, "Satın Al" düğmesi olan bir ürün seçim menüsü. Düğmeye basıldığında, satın alma talep etmek için istemci ile sunucu arasında bir RemoteFunction çağrısı yapabilirsiniz. Ancak, sunucunun güvenilir bir yöneticisi olarak, kullanıcının öğeyi satın almak için yeterli paraya sahip olduğunu doğrulaması önemlidir.

İstemciden sunucuya RemoteEvent aracılığıyla örnek satın alma akışı
İstemciden sunucuya bir RemoteFunction aracılığıyla örnek satın alma akışı

Silah hedefleme

Savaş senaryolarında, değerleri doğrulama konusunda özel dikkat gereklidir, özellikle nişan alma ve vurma doğrulaması yoluyla.

Bir oyuncunun başka bir oyuncuya lazer ışını ateşleyebildiği bir deneyim hayal edin. İstemcinin sunucuya kime zarar vereceğini söylemesi yerine, sunucuya ateşin köken pozisyonunu ve neyi vurduğunu bildirmelidir. Sunucu ardından şu kontrolleri doğrulayabilir:

  • İstemcinin ateş açtığını bildirip bildirirken, sunucudaki oyuncu karakterine yakın bir konumda mı? Sunucu ve istemcinin gecikmeden dolayı hafif farklılık oluşturabileceğini unutmayın, yani ek tolerans uygulanması gerekecektir.
  • İstemcinin vurduğunu bildirdiği pozisyon, istemcinin vurduğunu bildirdiği parçanın pozisyonuna makul bir mesafede mi?
  • İstemcinin ateş açtığı pozisyon ile vurduğu pozisyon arasında herhangi bir statik engel var mı? Bu kontrol, bir istemcinin duvarlardan geçerek ateş etmeye çalışmadığından emin olmak içindir. Bu yalnızca geçerli atışların gecikme nedeniyle reddedilmemesi için statik geometrinin kontrol edilmesi gerekir.

Ek olarak, sunucu tarafında şu şekilde daha fazla doğrulama uygulamayı da düşünebilirsiniz:

  • Oyuncunun en son ne zaman silah ateşi açtığını izleyin ve çok hızlı ateş etmediğini doğrulayın.
  • Her oyuncunun mermi miktarını sunucuda takip edin ve ateş eden oyuncunun silah saldırısını gerçekleştirebilmesi için yeterli mermisi olduğundan emin olun.
  • Eğer takımlar veya "oyuncular botlara karşı" savaş sistemi uyguladıysanız, vurulan karakterin düşman olduğunu, takım arkadaşı olmadığını kontrol edin.
  • Vurulan oyuncunun hayatta olduğunu doğrulayın.
  • Silah ve oyuncu durumunu sunucuda saklayın ve ateş eden oyuncunun yeniden yükleme gibi bir eylem veya koşuldan etkilenmediğinden emin olun.

Hız sınırlaması

Sunucu tarafı mantığının istemci tarafından tetiklenebileceği durumlarda (uzaktan, Touched olayları, yakınlık istemleri, ClickDetectors vb.), bu mantığın kötü niyetli kullanıcılar veya hatta meşru kullanıcılar tarafından spam'lenme olasılığı vardır. Hız sınırlaması, bu eylemlerin ne sıklıkla gerçekleştirilebileceğini kontrol eder, istismar ve sistem aşırı yüklenmesini önler. İstemcide hız sınırları uygulamak pratik olsa da (ve bazen gerekli olsa da), asla yalnızca istemci tarafında bir hız sınırına güvenmeyin.

İstemci tarafından tetiklenebilen herhangi bir sunucu tarafı mantığı için, bu mantığın ne maksima hızda çalışması gerektiğini her zaman düşünün. Birçok sunucu tarafı eylemi, istismar veya hata olasılığını önlemek için sıklıklarının sınırlandırılması gerekmektedir, örneğin:

  • Roblox API çağrıları: DataStoreService ve BadgeService gibi arka uç API'leri, aşılırsa isteklerinizin başarısız olmasına neden olan yerleşik hız sınırlamalarına sahiptir.
  • Hesaplama açısından pahalı işlemler: Önemli sunucu kaynaklarını tüketen veya diğer istemcileri etkileyen eylemler
  • Sunucu örneği: ServerStorage'tan büyük modelleri kopyalamak, bunlar asla istemcilere çoğaltılmasa bile
  • İstemci örneği: Tüm bağlı istemcilere GUI'lerini aynı anda güncelleme talimatı vermek
  • İstismar edilebilir mekanikler: Hızlı bir şekilde gerçekleştirildiğinde istismar edilebilecek eylemler, örneğin, dokunulmazlık vermek, oyuncuları teleport etmek veya para vermek

Token kova örneği

Hız sınırlaması için sağlam ve yaygın bir yaklaşım token kova algoritmasıdır. Her kullanıcının belirli bir sayıda token tutabilen bir kovası olduğunu hayal edin. Bir eylem gerçekleştirmek için kullanıcı bir token harcamak zorundadır. Kova, sabit bir hızda yeni tokenlarla doludur. Bu yöntem, gerektiğinde kısa patlamalara olanak tanırken, belirli bir süre zarfında ortalama bir hız uygulamak suretiyle kalıcı spam'ı önler.


--!strict
-- ServerScriptService içinde yer alan modül
type UserId = number
type Bucket = {
tokens: number,
last: number,
}
type TokenBucketT = {
capacity: number,
refillPerSecond: number,
buckets: { [UserId]: Bucket },
allow: (self: TokenBucketT, userId: UserId) -> boolean,
}
local TokenBucket = {}
TokenBucket.__index = TokenBucket
-- En fazla `capacity` eylemi kabul eden, dolum süresi `capacity / windowSeconds` tokeni hızında yeniden dolduran bir sınırlayıcı oluşturur.
function TokenBucket.new(capacity: number, windowSeconds: number): TokenBucketT
assert(capacity >= 1, "capacity must be >= 1")
assert(windowSeconds > 0, "windowSeconds must be > 0")
local self: TokenBucketT = {
capacity = capacity,
refillPerSecond = capacity / windowSeconds,
buckets = {},
}
return (setmetatable(self, TokenBucket) :: any) :: TokenBucketT
end
local function refill(b: Bucket, now: number, cap: number, rate: number)
local elapsed = now - b.last
if elapsed > 0 then
b.tokens = math.min(cap, b.tokens + elapsed * rate)
b.last = now
end
end
-- Kullanıcı limitlerini aşarsa false döner
function TokenBucket:allow(userId: UserId): boolean
local now = time()
local b = self.buckets[userId]
if not b then
b = { tokens = self.capacity, last = now }
self.buckets[userId] = b
else
refill(b, now, self.capacity, self.refillPerSecond)
end
if b.tokens >= 1 then
b.tokens -= 1
return true
end
return false
end
return TokenBucket

Modülü kullanmak için önce TokenBucket.new(capacity, windowSeconds) ile yeni bir sınırlandırıcı örneği oluşturursunuz. capacity, kullanıcının hızlı bir patlama süresinde yapabileceği maksimum istek sayısıdır, windowSeconds ise tüm bu tokenlerin yeniden doldurulmasını sağlayan süredir. Örneğin, TokenBucket.new(5, 10) maksimum 5 isteğe izin veren ve her iki saniyede bir (10 saniye / 5 token) bir token yeniden dolduran bir sınırlayıcı oluşturur.

Korunan mantığı yürütmeden önce, :allow(userId) yöntemini çağırarak harekete geçin; eğer false dönerse eylemi reddedin. Ayrıca kullanıcı ayrıldığında kullanıcıya ait kova verilerini temizlemek de iyi bir uygulamadır.

Aşağıdaki örnek betik, bir RemoteEvent'in bir özel sohbet sistemi tarafından spam'lenmesini nasıl engelleyeceğinizi gösterir.


-- Sunucu betiğinde örnek kullanım
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local TokenBucket = require(ServerScriptService.TokenBucket)
local ChatRemote = ReplicatedStorage:WaitForChild("ChatRemote") :: RemoteEvent
-- 10 saniyede 5 mesaj (kapasite 5, her saniyede 0.5 token yeniden doluyor)
local chatLimiter = TokenBucket.new(5, 10)
ChatRemote.OnServerEvent:Connect(function(player: Player, message: string)
if not chatLimiter:allow(player.UserId) then
-- Çok hızlı: isteği düşür veya spam uyarısı gönder
return
end
-- Mesajı işleme (diğer doğrulamadan sonra)
broadcastMessage(player, message)
end)
-- Bellek sızıntılarını önlemek için temizleme
Players.PlayerRemoving:Connect(function(p: Player)
chatLimiter.buckets[p.UserId] = nil
end)

İstemci-tetikli örneklerin güvenliği

ProximityPrompts, ClickDetectors ve DragDetectors uzantıları uzaktan değildir, ancak bir kötü niyetli kullanıcı bu olayları herhangi bir mesafeden ve herhangi bir zamanda tetikleyebilir, genellikle Enabled veya MaxActivationDistance gibi özellikleri görmezden gelir. Bu nesneler, uzaktan gibi aynı titizlikle güvence altına alınmalıdır.

ProximityPrompt

  • Bir kötü niyetli kullanıcı, sunucuda Enabled false olsa bile herhangi bir olayı tetikleyebilir.
  • Enabled, MaxActivationDistance ve RequiresLineOfSight istemcide sessizce değiştirilebilir, bu nedenle herhangi bir çoğaltılan ProximityPrompt, herhangi bir yerden görülebilir ve potansiyel olarak etkileşime girilebilir.
  • Sunucu, HoldDuration sıfır olsa bile bekletme olaylarını kabul eder. İstemci, etkileşimleri olağandışı hızlı bir şekilde gerçekleştirmek için HoldDuration'ı manipüle edebilir.
  • Sadece Triggered olayında sunucu tarafında bir mesafe kontrolü vardır. Diğer olaylar (örneğin, PromptButtonHoldBegan ve TriggerEnded) mesafe kontrolü gerektirmeden, herhangi bir istemci tarafından rastgele gönderilebilir.

ClickDetector

  • Sunucuda herhangi bir olay için hiç kontrol yoktur.
  • Kötü niyetli kullanıcılar, ClickDetector devre dışı olsa bile (0 MaxActivationDistance veya DragDetector.Enabled false) herhangi bir mesafeden olayı çoğaltabilir.
  • Olaylar, ClickDetector'ın üzerinde tıklanabilir bir şeye dair bağlı olmadığında bile çoğaltılabilir.

DragDetector

  • ClickDetector'dan miras alınan olaylar için hiç kontrol yoktur.
  • Sürüklenme olayları için Enabled özelliği ve PermissionPolicy özellikleri sunucu tarafından kontrol edilip saygı gösterilir. Diğer tüm özellikler kontrol edilmez.

Bu olaylardan biri tetiklendiğinde, sunucu betiğinizin kendi doğrulamasını gerçekleştirmesi önemlidir:

  • Etkin olup olmadığını kontrol edin: Sunucu üzerinde özelliklerini (Enabled, HoldDuration, RunLocally vb.) kontrol ederek nesnenin etkin olmasını sağladığınızdan emin olun. Eğer nesne her zaman etkin ise bu adım gereksizdir.
  • Oyuncu durumunu kontrol edin: Oyuncunun mevcut durumu göz önüne alındığında eylemi gerçekleştirmeye uygun olup olmadığını kontrol edin. Oyuncunun karakteri dünyada mı? Nesneye yeterince yakın mı? Bu nesne ile etkileşime girebilmek için oyuncunun hayatta kalması gerekiyor mu? Gerekirse deneyiminiz tarafından sunucuda korunan başka oyuncu durumu kontrollerini yapın.
  • Hız sınırlamalarını uygulayın: Hız Sınırlama bölümünde kapsanan bilgileri kullanarak, istemcide serinletme süresi uygulanmalı ve sunucuda bu durumların spamlenip istismar edilmesini önlemek için hız sınırları uygulanmalıdır. Minimum süre alması beklenen etkileşimler için, istemcilerin bunları çok hızlı tamamlamadığından emin olun.

Ağ mülkiyeti hakkında nota: Varsayılan olarak, eğer bu nesneler yere sabitlenmemiş parçaların çocuklarıysa veya sabitlenmemiş bir montajın içindeyse, kötü niyetli bir kullanıcı ana parçaların ağ mülkiyetini alabilir ve bunları doğrudan karakterine taşıyabilir, mesafe kontrollerinden kaçınabilir. Kritik eylemler için, yerleştirilen parçaları veya ağ mülkiyet API'sini kullanarak gerekli sunucu tarafı doğrulaması ile beraber gerçekleştirin.

RemoteEvents ve RemoteFunctions

RemoteFunctions ve RemoteEvents'in kapsamını ve etkisini sınırlayın. Uzaktan fonksiyonlar/oğulları aracılığıyla sunucunun silinmesi veya değiştirilmesi için istemcinin rastgele bir yol veya nesne referansı belirtmesine izin veren dinamik yüklemelerde son derece dikkatli olun. Sunucunun silmesi veya değiştirmesi gereken bir referans oluşturan uzantılara izin veren uzaktaki olayları uygulamak, genellikle yüzeyde önemsiz gibi görünse de, başka hatalarla zincirlenerek genel durumu veya mantığı ciddi şekilde etkileyebilir. Argüman olarak belirtilen nesnelerin türünü değil, sınıfını ve DataModel içindeki beklenen konum veya yapıyı da kontrol edin.

İstemciden istemciye iletişim

Bazı uzaktan hizmetler, bir istemcinin diğer istemciler üzerinde etkiler oluşturmalarına izin verecek şekilde tasarlanmıştır. Bu, bir istemcinin sunucuya bir uzaktan hizmeti ateşlemesi ve ardından sunucunun RemoteEvent:FireAllClients(), RemoteEvent:FireClient() veya benzeri yöntemleri kullanarak bilgiyi iletmesi durumunda gerçekleşir. Bu desen, doğru bir şekilde güvence altına alınmadığında tehlikeli olabilir - sunucu bir kapı bekçisi olmalıdır, sadece bir iletim değil.

Oyuncuların yıldırım büyüsü atabileceği bir senaryo hayal edin. Atıldığında, çevredeki oyuncular flaşı görür, sesi duyar ve kamera sarsıntısı yaşarlar.

Zayıf bir sunucu betiği şöyle görünebilir:

Zayıf sunucu kodu (ServerScriptStorage içindeki betik)

local castLightningEvent = game.ReplicatedStorage.CastLightning
-- Bu sunucu betiği, herhangi bir doğrulama olmadan mesajı herkese iletir
castLightningEvent.OnServerEvent:Connect(function(player, strikePosition)
castLightningEvent:FireAllClients(strikePosition)
end)
İstemci efekt kodu

local castLightningEvent = game.ReplicatedStorage.CastLightning
-- İstemci üzerinde görsel ve ses efektleri oluştur
local function createLightningEffect(strikePosition)
-- Kamerayı sarsan kod
-- Gürültülü bir yıldırım sesi çalacak kod
-- Görsel bir yıldırım çubuğu oluşturacak kod
print("Yıldırım şurada düşüyor: " .. tostring(strikePosition))
end
-- Sunucu olayı yaydığında, bu istemci efekt çalıştırır
castLightningEvent.OnClientEvent:Connect(createLightningEffect)

Kötü niyetli bir kullanıcı, bu zayıf sistemi aşağıdaki şekillerde istismar edebilir:

  • Spam yapmak: Uzaktan hizmeti her saniye yüzlerce kez arayarak, deneyimi oynanamaz hale getiren sürekli efektler oluşturmak
  • Geçersiz veri: Tüm istemcilerde hata oluşturan nil, NaN veya yanlış türler göndermek
  • Yetkisiz kullanım: Açıklanan veya kaynakları olmayan büyüleri atmak

Sunucu bir kapı bekçisi olmalıdır, yalnızca bir iletim değil. Yayınlama işlemini gerçekleştirmeden önce isteği doğrulamalı ve oyuncu bazında hız sınırlaması uygulamalıdır. İşte isteği doğrulamak için kullanılabilecek bazı yöntemlerin örneği.

Güvenli sunucu kodu

local castLightningEvent = game.ReplicatedStorage.CastLightning
local playerCooldowns = {}
local COOLDOWN_TIME = 3
castLightningEvent.OnServerEvent:Connect(function(player, strikePosition)
-- 1. Tür doğrulaması
if typeof(strikePosition) ~= "Vector3" then
return -- Geçersiz tür, sessizce reddet
end
-- 2. NaN kontrolü (NaN ~= NaN, bunu tespit etmenin tek yoludur)
if strikePosition.X ~= strikePosition.X then
return -- NaN içeriyor, reddet
end
-- 3. Örnek Hız sınırlaması
local lastCast = playerCooldowns[player] or 0
if tick() - lastCast < COOLDOWN_TIME then
return -- Hala beklemede
end
-- 4. Örnek İzin kontrolü
if not player:GetAttribute("HasLightningSpell") then
return -- Oyuncunun bu büyüsü yok
end
-- 5. Örnek Mesafe doğrulaması
local character = player.Character
local humanoidRootPart = character and character:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then
return
end
local distance = (humanoidRootPart.Position - strikePosition).Magnitude
if distance > 100 then
return -- Uzak mesafe
end
-- Tüm kontroller geçti - yayına devam edilebilir
playerCooldowns[player] = tick()
castLightningEvent:FireAllClients(player, strikePosition)
end)

Bu kontrolleri uygulamak, bir kötü niyetli kullanıcının diğer oyuncular için deneyimi mahvetmesini zorlaştırır. Sunucu, yalnızca geçerli ve yetkili eylemlerin diğer istemcilere yayılmasını garantileyen bir koruyucu bariyer işlevi görür.

Özel dikkate alınması gerekenler

Aşağıda, özel işleme gerektirecek bazı ek durumları göz önünde bulundurmalısınız.

Veri deposu manipülasyonu

DataStoreService kullanarak oyuncu verilerini kaydeden deneyimlerde, kötü niyetli kullanıcılar, geçersiz verilere, kaydedilmesi bozulan veya çoğaltılan öğelere karşı yarış şartlarından yararlanabilir. Bu, özellikle eşya ticareti, pazar alanları ve para sistemlerine sahip deneyimlerde sorunludur.

İstemci girişi ile etkileyen RemoteEvent veya RemoteFunction üzerinden gerçekleştirilen her eylemin aşağıdaki önlemler doğrultusunda temizlendiğinden emin olun:

  • Özellik değerleri, bir Veri Deposu'na serileştirilemez ve başarısız olur. Bunu önlemek için tür doğrulaması kullanın.
  • DataStoreların veri sınırları vardır. Belirsiz uzunlukta dizeler kontrol edilmeli veya kesilmelidir; ayrıca, istemci tarafından sınırsız rastgele anahtarların tablolar eklenmesine izin verilmemesi gerektiğinden emin olun.
  • Tablo indeksleri NaN veya nil olamaz. İstemci tarafından gönderilen tüm tablolar üzerinde yineleme yapın ve tüm indekslerin geçerli olduğunu doğrulayın.
  • DataStorelar yalnızca geçerli UTF-8 karakterlerini kabul eder, bu nedenle istemciden sağlanan tüm dizeleri utf8.len() üzerinden temizlemek, geçerliliklerini kontrol etmek gerekir. utf8.len() bir dizenin uzunluğunu döndürür; Unicode karakterleri tek bir karakter olarak değerlendirir; eğer geçersiz bir UTF-8 karakteri ile karşılaşılırsa nil ve geçersiz karakterin konumu döner. Geçersiz UTF-8 dizeleri, anahtarlar ve değerler olarak tablolarda da mevcut olabilir.
  • Sonsuz/NaN sayı istismarları - Kötü niyetli kullanıcılar, sonsuz para oluşturmak veya hesaplamaları bozmakt Bu yüzden (-1/0, 0/0 veya math.huge gibi) değerler gönderebilir. Her zaman NaN tehlikesi kısmında açıklanan yöntemleri kullanarak doğrulamalar yapın.

Yarış koşulları, oyuncuların işlemler arasındaki zamanlamayı manipüle etmesine neden olarak eşya çoğaltma veya veri bozulması oluşturabilir.

Ticaret istismarı örneği: Bir oyuncu bir ticaret başlatır, eşyasını diğer bir oyuncuya gönderir ve hemen oyundan çıkar. Eğer ticaret tamamlanırsa ama verileri geçersiz olduğundan kaydolması başarısız olursa, yeniden katıldığında, orijinal eşyalarıyla geri dönerken diğer oyuncu ticaret edilen eşyayı tutar - sonuçta çoğaltma meydana gelir.

Önleme stratejileri:

  • Ticaret işlemlerinden önce tüm verileri doğrulayın
  • Tüm oyuncu verilerinin doğrulandığı, herhangi bir değişiklik yapılmadan önce işlem benzeri kalıplar kullanın
  • Herhangi bir bölüm başarısız olduğunda tüm değişiklikleri geri almak için uygun hata yönetimi uygulayın

MarketplaceService

MarketplaceService ile etkileşimlerde, örneğin geçişler veya geliştirici ürünleriyle, tüm satın alma doğrulaması ve öğe verme sunucuda gerçekleştirilmelidir. Özellikle satın alma makbuzlarını güvenli bir şekilde doğrulamak için ProcessReceipt geri çağrısını kullanın. PromptProductPurchaseFinished gibi istemci tarafı sinyallere güvenmeyin, çünkü bunlar taklit edilebilir. ProcessReceipt işlevinizin makbuz ayrıntılarını kapsamlı bir şekilde kontrol ettiğinden emin olun ve sadece Roblox sunucuları ile geçerli bir işlem sağlandığında öğe veya para verin. Ayrıca herhangi bir ürünün belirli bir makbuz için zaten verilmiş durumunu ele almaya hazır olun.

©2026 Roblox Corporation. Roblox, the Roblox logo and Powering Imagination are among our registered and unregistered trademarks in the U.S. and other countries.