Güvenli FiveM sunucu olayları: hile çekenler net olayları kötüye kullanmaktan durdurun
Hile çekenler sunucu olaylarınızı herhangi bir değerle tetikler. Sunucuda doğrulamaya nasıl yapılır: source kullanın, mesafe, iş ve bekleme süresi kontrol edin ve fiyatları sunucu tablosunda tutun.
Birçok sunucuda bir dükkan betiği şöyle görünür ve ücretsiz para düğmesidir:
TriggerServerEvent('shop:buy', 'weapon_pistol', 1, -999999)Hile menüsü olan herkes o satırı gönderebilir. Sunucu işleyiciyi çalıştırır, oyuncudan negatif fiyat alır ve mutlu bir şekilde parayı ekler. Bu kılavuz sunucu olaylarını istemciye güvenmeyecek şekilde nasıl yazacağınızı gösterir.
Kural: istemciye güvenilmez
Ağ olayına ulaşan her şey oyuncunun kontrol ettiği oyuncunun makinesinden gelir. Her argümanı web sitesinde kullanıcı girişi olarak işleyin: eksik olabilir, yanlış tür, negatif, büyük veya sadece icat olabilir.
Sunucu yapabilir güven:
source, olayı tetikleyen oyuncu. Motor ayarlar.- Sunucunun zaten tuttuğu veriler: oyuncunun işi, envanteri, parası, konumu ve kendi yapılandırma tabloları.
Asla güvenmemelidir: miktarlar, fiyatlar, öğe adları, oyuncu kimlikleri, koordinatlar, iş adları ve istemci tarafından gönderilen "başarılı" bayrakları.
Kötü örnek
RegisterNetEvent('shop:buy', function(item, count, price)
local xPlayer = ESX.GetPlayerFromId(source)
xPlayer.removeMoney(price * count)
xPlayer.addInventoryItem(item, count)
end)İstemci öğeyi, sayıyı ve fiyatı seçer. Hile çeken herhangi bir şey hiçbir şey için satın alır veya para basmak için negatif sayı.
İyi örnek
Fiyatları sunucuda tutun, türleri doğrulayın, oyuncunun nerede olduğunu kontrol edin, sonra hareket edin.
local Items = {
water = { price = 5, max = 10 },
bread = { price = 8, max = 10 },
}
local shopCoords = vec3(25.7, -1347.3, 29.5)
local lastBuy = {}
RegisterNetEvent('shop:buy', function(item, count)
local src = source
-- 1. types and ranges
if type(item) ~= 'string' or type(count) ~= 'number' then return end
count = math.floor(count)
local def = Items[item]
if not def or count < 1 or count > def.max then return end
-- 2. cooldown
local now = GetGameTimer()
if lastBuy[src] and now - lastBuy[src] < 1000 then return end
lastBuy[src] = now
-- 3. distance
local ped = GetPlayerPed(src)
if #(GetEntityCoords(ped) - shopCoords) > 5.0 then return end
-- 4. price comes from the server table
local total = def.price * count
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer or xPlayer.getMoney() < total then return end
xPlayer.removeMoney(total)
xPlayer.addInventoryItem(item, count)
end)
AddEventHandler('playerDropped', function()
lastBuy[source] = nil
end)Sunucuda GetEntityCoords(GetPlayerPed(source)) OneSync etkinse gerekir. Bunu henüz yapmadıysanız, enabling OneSync bölümüne bakın.
QBCore ve QBox'ta aynı
Yalnızca oyuncu araması, iş alanı ve para çağrısı değişir. Doğrulama aynı kalır.
-- QBCore
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(src)
if not Player or Player.PlayerData.money.cash < total then return end
Player.Functions.RemoveMoney('cash', total, 'shop-purchase')-- QBox
local Player = exports.qbx_core:GetPlayer(src)
if not Player or Player.PlayerData.money.cash < total then return end
Player.Functions.RemoveMoney('cash', total, 'shop-purchase')İş ve izin kontrolleri
Bir olay yalnızca bir iş için çalışmalıysa, argümandan değil, çerçevenin verilerinden sunucuda kontrol edin.
-- ESX
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer or xPlayer.job.name ~= 'police' then return end-- QBCore
local Player = QBCore.Functions.GetPlayer(source)
if not Player or Player.PlayerData.job.name ~= 'police' then return endAdmin eylemleri için, istemci bayrağı yerine ACE izni kontrol edin. Bkz. ACE permissions:
if not IsPlayerAceAllowed(source, 'command.myadmin') then return endÖdüller sunucu tarafı kanıta ihtiyaç duyar
job:finished veya mission:reward gibi olaylar klasik hedefi. Hile çeken basitçe bunları bir döngüde ateşler.
- Ödül miktarını sunucu tablosunda tutun, asla olay argümanlarında değil.
- Sunucuda oyuncu başladı ve sadece bu durum varsa ödeyin. Ödedi sonra temizleyin.
- Başlama ve bitirme arasına minimum zaman ekleyin.
- Bitirdiklerinde oyuncu teslim noktası yakınında olduğunu kontrol edin.
local activeJobs = {}
RegisterNetEvent('job:start', function()
activeJobs[source] = GetGameTimer()
end)
RegisterNetEvent('job:finish', function()
local src = source
local startedAt = activeJobs[src]
if not startedAt or GetGameTimer() - startedAt < 30000 then return end
activeJobs[src] = nil
-- pay a fixed amount defined on the server
end)Yardımcı olan diğer alışkanlıklar
- Asla istemcinin oyuncu kimliğini kullanmayın. Her zaman
sourcekullanın.giveMoney(playerId, amount)gibi olay hile çekenin herkese ödeyebilmesini sağlar. - Gerek duymazsanız olayları açığa çıkarmayın.
RegisterNetEventolmadan sadeceAddEventHandlerile kaydedilen olay istemciden tetiklenemez. - İstemci dizelerini kod olarak çalıştırmayın. Hiçbir zaman istemci değerini
load,ExecuteCommandveya SQL dizesine geçmeyin. Parametrelenmiş sorguları kullanın, oxmysql guide bölümünde olduğu gibi. - Garip durumları kaydedin. Bir kontrol başarısız olduğunda, oyuncu ve olay adını yazdırın. Başarısızlıkların deseni hile çekenin nasıl bulacağınızdır. txAdmin'den yasaklayın, moderating with txAdmin bölümüne bakın.
Dikkat: olay adını gizlemek, karıştırmak veya istemci tarafı "belirteci" eklemek onu korumaz. İstemci bunların hepsini okuyabilir. Yalnızca sunucuda kontroller sayılır.
Kontrol listesi
| Belirtisi | Çözüm |
|---|---|
| İstemci fiyat veya miktarı gönderiyor | Sunucuda fiyat tablosu tutun ve toplamı orada hesaplayın |
| İstemci oyuncu kimliği gönderiyor | Bunun yerine source kullanın |
| Öğe adı istemciden geliyor | Sunucu tablosunda bulunan adları sadece kabul edin |
| Negatif veya büyük miktarlar | type, math.floor kontrol edin ve minimum ve maksimumu |
| Olay haritanın karşı tarafından ateşlendi | GetEntityCoords(GetPlayerPed(source))'ı hedef konumla karşılaştırın |
| Olay döngüde spamlanıyor | Oyuncu başına bekleme süresi, playerDropped seçildi |
| Yalnızca iş eylemi | İşi sunucuda çerçeveden okuyun |
| Ödül olayı kötüye kullanılıyor | Sunucuda iş durumu saklayın ve sabit miktarı bir kez ödeyin |
Kısa yanıtlar
Oyuncu gerçekten sunucu olaylarımı tetikleyebilir mi?
Evet. RegisterNetEvent ile kaydedilen herhangi bir olay, değiştirilmiş istemci tarafından herhangi bir argümanla tetiklenebilir. Sunucu gerçek betik çağrısını sahte olandan ayıramaz, bu nedenle her şeyi doğrulaması gerekir.
İstemci tarafından gönderilen oyuncu kimliğini kullanmak güvenli mi?
Hayır. Sunucuda, source motor tarafından ayarlanır ve tahrif edilemez. Argüman olarak gönderilen oyuncu kimliği, adı veya kimliği yapılabilir, bu nedenle kimin ödeneceğine veya cezalandırılacağına karar vermek için asla kullanmayın.
Olaylarımı doğrularsam antihile yazılımına ihtiyacım var mı?
Doğrulama temel ve çoğu kendi betiklerinizin kötüye kullanımını durdurur. Antihile, enjekte edilmiş menüler gibi olayların göremediği şeyler için tespit ekler. Bkz. [FiveM anticheat basics](/blog/fivem-anticheat-basics).
Bu sorunu yaşatmayan scriptler
Shop CreatorBir dakikadan kısa sürede dükkân kurun — sahipler, çalışanlar, kasalar ve soygunlar dahil.Scripti gör →
Item Creator V2Animasyonlar, proplar, efektler ve daha fazlasıyla kullanılabilir eşyalar oluşturun — kod yazmadan.Scripti gör →
Advanced BoostingTabletten araç boosting: D’den S+ sınıfına kontratlar, ekipler ve canlı sıra.Scripti gör →