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:

text
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

lua
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.

lua
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.

lua
-- 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')
lua
-- 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.

lua
-- ESX
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer or xPlayer.job.name ~= 'police' then return end
lua
-- QBCore
local Player = QBCore.Functions.GetPlayer(source)
if not Player or Player.PlayerData.job.name ~= 'police' then return end

Admin eylemleri için, istemci bayrağı yerine ACE izni kontrol edin. Bkz. ACE permissions:

lua
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.
lua
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 source kullanın. giveMoney(playerId, amount) gibi olay hile çekenin herkese ödeyebilmesini sağlar.
  • Gerek duymazsanız olayları açığa çıkarmayın. RegisterNetEvent olmadan sadece AddEventHandler ile kaydedilen olay istemciden tetiklenemez.
  • İstemci dizelerini kod olarak çalıştırmayın. Hiçbir zaman istemci değerini load, ExecuteCommand veya 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 →

Okumaya devam edin