ExxDev
TRIAL MOD.
Katılım:
18 Tem 2026
Mesajlar:
4
Beğeniler:
2
QBCORE SUNUCU GÜVENLİĞİ
Para Hilesi, Event Exploit, Aim, Wallhack ve Entity Spam Koruması
Hazırlayan: ExxDev
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Önemli Bilgilendirme
FiveM sunucusuna eklenen tek bir Lua dosyasının bütün hileleri tamamen engellemesi mümkün değildir.
Hile kullanan oyuncular, istemci tarafından erişilebilen eventleri kendileri tetikleyebilir. Bu nedenle asıl güvenlik; para, item, meslek, konum, yetki ve ödül kontrollerinin sunucu tarafında yapılmasıyla sağlanır.
Bu rehberde:
- Para hilesine neden olan açık eventlerin kapatılması
- Event spam ve tetikleme sınırı
- Güvenli market satın alma sistemi
- Güvenli meslek ödülü sistemi
- Şüpheli para hareketlerinin kaydedilmesi
- Anormal silah hasarının engellenmesi
- Şüpheli aim hareketlerinin kayıt altına alınması
- Entity spam sınırlandırması
- server.cfg güvenlik ayarları
- QBCore yetki güvenliği
- Şüpheli bakiyelerin SQL üzerinden kontrolü
anlatılacaktır.
Uyarı: Kodları canlı sunucuya eklemeden önce yedek alın ve test sunucusunda deneyin. Her QBCore paketinin script yapısı farklı olabilir.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Hileler Para Açığını Nasıl Kullanıyor?
Aşağıdaki kullanım son derece güvensizdir:
Kod:
RegisterNetEvent('meslek:server:odul', function(amount)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
Player.Functions.AddMoney('cash', amount)
end)
Burada para miktarı client tarafından gönderilmektedir. Hile kullanan kişi eventi istediği miktarla çağırabilir:
Kod:
meslek:server:odul
amount = 99999999
Aynı tehlike aşağıdaki değerler için de geçerlidir:
- Para miktarı
- Ürün fiyatı
- Satılacak item değeri
- Meslek ödülü
- Oyuncu yetkisi
- Meslek adı
- Hedef oyuncu ID’si
- Araç fiyatı
- Fatura miktarı
- Silah ve item miktarı
Client yalnızca oyuncunun gerçekleştirmek istediği işlemi bildirmelidir. İşlemin fiyatı, sonucu ve ödülü server tarafından hesaplanmalıdır.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2. server.cfg Güvenlik Ayarları
Öncelikle server.cfg dosyanızın yedeğini alın.
Aşağıdaki temel ayarları server.cfg içerisine ekleyin:
Kod:
# ScriptHook tabanlı eklentileri kapatır
sv_scriptHookAllowed 0
# Değiştirilmiş istemci dosyalarını sınırlar
sv_pureLevel 1
# Başka oyuncuların entity kontrolünü ele geçirme isteklerini sınırlar
sv_filterRequestControl 1
# Oyuncu IP adreslerini genel raporlarda gizler
sv_endpointPrivacy true
# Network üzerinden telefon patlaması eventini kapalı tutar
set sv_enableNetworkedPhoneExplosions false
Önce sv_filterRequestControl 1 kullanın. Scriptlerinizi test ettikten sonra daha sıkı koruma için şu ayarı deneyebilirsiniz:
Kod:
sv_filterRequestControl 2
Dikkat: 3 veya 4 gibi daha katı seviyeler bazı araç, garaj ve entity scriptlerini bozabilir. Değişiklikleri doğrudan canlı sunucuda denemeyin.
İsteğe bağlı gelişmiş ayarlar
Kod:
# Network üzerinden yönlendirilen ses eventlerini kapatır
set sv_enableNetworkedSounds false
# Network script entity state eventlerini kapatır
set sv_enableNetworkedScriptEntityStates false
# Client replay özelliğini kapatır
set sv_disableClientReplays 1
Bu ayarlar bazı yasal scriptleri etkileyebilir:
- sv_enableNetworkedSounds false: Network ses kullanan scriptleri bozabilir.
- sv_enableNetworkedScriptEntityStates false: Bazı entity ve araç scriptlerini etkileyebilir.
- sv_disableClientReplays 1: Rockstar Editor kullanımını kapatır.
- sv_pureLevel 2: Ses ve grafik modları dahil bütün değiştirilmiş dosyaları engeller.
Bütün ayarları aynı anda açmak yerine tek tek açıp test edin.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3. ExxDev Security Resource Oluşturma
Sunucunuzun resources klasörüne girin ve şu klasörü oluşturun:
Kod:
resources/[standalone]/exxdev_security
Klasörün içerisine şu dosyaları oluşturun:
Kod:
exexxdev_security/
├── fxmanifest.lua
├── config.lua
└── server/
└── main.lua
fxmanifest.lua
Kod:
fx_version 'cerulean'
game 'gta5'
author 'ExxDev'
description 'QBCore server-side security helpers'
version '1.0.0'
server_scripts {
'config.lua',
'server/main.lua'
}
dependency 'qb-core'
config.lua
Kod:
Config = {}
-- İlk kurulumda false bırakın.
-- Logları kontrol ettikten sonra true yapabilirsiniz.
Config.AutoKick = false
-- Belirlenen süre içerisinde bu puana ulaşan oyuncu atılır.
Config.KickAfter = 10
Config.StrikeWindowSeconds = 60
-- Tek işlemde bu miktarların üzerindeki para hareketleri loglanır.
-- Kendi ekonominize göre değiştirin.
Config.MoneyAlert = {
cash = 50000,
bank = 250000,
crypto = 50
}
Config.Combat = {
-- Bir saniyede izin verilecek hasar eventi
MaxDamageEventsPerSecond = 80,
-- overrideDefaultDamage kullanılarak gönderilebilecek en yüksek hasar
MaxOverrideDamage = 1000,
-- Kısa sürede gerçekleşen ölümcül hit sayısı
LethalHitsForReview = 6,
LethalWindowSeconds = 15
}
-- İlk kurulumda kapalı tutun.
-- Çok fazla obje oluşturan scriptlerle çakışabilir.
Config.EntityCreation = {
Enabled = false,
MaxEntities = 80,
WindowMilliseconds = 10000
}
server/main.lua
Kod:
local QBCore = exports['qb-core']:GetCoreObject()
local rateBuckets = {}
local playerStrikes = {}
local lethalHits = {}
local function GetLicense(src)
for _, identifier in ipairs(GetPlayerIdentifiers(src)) do
if identifier:sub(1, 8) == 'license:' then
return identifier
end
end
return 'license:unknown'
end
local function SecurityLog(src, reason, points)
src = tonumber(src)
if not src or src <= 0 then
return
end
points = tonumber(points) or 0
local now = os.time()
local strike = playerStrikes[src]
if not strike or now >= strike.resetAt then
strike = {
points = 0,
resetAt = now + Config.StrikeWindowSeconds
}
playerStrikes[src] = strike
end
strike.points = strike.points + points
local playerName = GetPlayerName(src) or 'Bilinmeyen'
local license = GetLicense(src)
local message = (
'[ExxDev Security] Oyuncu: %s | ID: %s | License: %s | Sebep: %s | Puan: %s'
):format(
playerName,
src,
license,
tostring(reason),
strike.points
)
print(message)
if GetResourceState('qb-log') == 'started' then
TriggerEvent(
'qb-log:server:CreateLog',
'anticheat',
'ExxDev Security',
'red',
message,
false
)
end
if Config.AutoKick and strike.points >= Config.KickAfter then
DropPlayer(
src,
'Sunucu güvenlik sistemi tarafından şüpheli işlemler nedeniyle bağlantınız kesildi.'
)
end
end
local function RateLimit(src, eventName, maxCalls, windowMilliseconds)
src = tonumber(src)
if not src or src <= 0 then
return false
end
eventName = tostring(eventName)
maxCalls = math.floor(tonumber(maxCalls) or 1)
windowMilliseconds = math.floor(tonumber(windowMilliseconds) or 1000)
local now = GetGameTimer()
local key = ('%s:%s'):format(src, eventName)
local bucket = rateBuckets[key]
if not bucket
or now < bucket.startedAt
or now - bucket.startedAt >= windowMilliseconds
then
rateBuckets[key] = {
startedAt = now,
count = 1
}
return true
end
bucket.count = bucket.count + 1
if bucket.count > maxCalls then
SecurityLog(
src,
('Event spam: %s (%s çağrı)'):format(eventName, bucket.count),
1
)
return false
end
return true
end
local function PositiveInteger(value, maximum)
value = tonumber(value)
maximum = tonumber(maximum)
if not value or value ~= value then
return nil
end
if value ~= math.floor(value) or value < 1 then
return nil
end
if maximum and value > maximum then
return nil
end
return value
end
local function IsNear(src, targetCoords, maximumDistance)
src = tonumber(src)
maximumDistance = tonumber(maximumDistance) or 5.0
if not src or not targetCoords then
return false
end
local ped = GetPlayerPed(src)
if ped == 0 or not DoesEntityExist(ped) then
return false
end
local playerCoords = GetEntityCoords(ped)
return #(playerCoords - targetCoords) <= maximumDistance
end
exports('RateLimit', RateLimit)
exports('PositiveInteger', PositiveInteger)
exports('IsNear', IsNear)
exports('Flag', SecurityLog)
-- QBCore para hareketlerini izler.
-- Bu event para hareketini engellemez; şüpheli işlemi loglar.
AddEventHandler(
'QBCore:Server:OnMoneyChange',
function(playerSource, moneyType, amount, action, reason)
local src = tonumber(playerSource)
amount = tonumber(amount)
moneyType = tostring(moneyType or ''):lower()
action = tostring(action or '')
reason = tostring(reason or 'unknown'):sub(1, 100)
if not src or not amount then
return
end
local threshold = Config.MoneyAlert[moneyType]
if not threshold then
return
end
if (action == 'add' or action == 'set') and amount >= threshold then
SecurityLog(
src,
(
'Yüksek para hareketi | Tür: %s | İşlem: %s | Miktar: %s | Reason: %s'
):format(moneyType, action, amount, reason),
0
)
end
end
)
-- Anormal silah hasarı ve hasar event spam koruması
AddEventHandler('weaponDamageEvent', function(sender, data)
sender = tonumber(sender)
if not sender or sender <= 0 or type(data) ~= 'table' then
return
end
if not RateLimit(
sender,
'weaponDamageEvent',
Config.Combat.MaxDamageEventsPerSecond,
1000
) then
CancelEvent()
return
end
if data.overrideDefaultDamage then
local damage = tonumber(data.weaponDamage)
if not damage
or damage ~= damage
or damage < 0
or damage > Config.Combat.MaxOverrideDamage
then
CancelEvent()
SecurityLog(
sender,
('Anormal silah hasarı engellendi: %s'):format(tostring(damage)),
3
)
return
end
end
-- Bu bölüm otomatik ban atmaz.
-- Yalnızca kısa süredeki ölümcül hitleri inceleme için kaydeder.
if data.willKill and tonumber(data.hitGlobalId) then
local netId = tonumber(data.hitGlobalId)
local hitEntity = NetworkGetEntityFromNetworkId(netId)
if hitEntity ~= 0 and DoesEntityExist(hitEntity) then
local targetOwner = NetworkGetEntityOwner(hitEntity)
if targetOwner and targetOwner > 0 and targetOwner ~= sender then
local now = os.time()
local hits = lethalHits[sender] or {}
for index = #hits, 1, -1 do
if now - hits[index] > Config.Combat.LethalWindowSeconds then
table.remove(hits, index)
end
end
hits[#hits + 1] = now
lethalHits[sender] = hits
if #hits >= Config.Combat.LethalHitsForReview then
SecurityLog(
sender,
(
'%s saniyede %s ölümcül hit. Aim incelemesi gerekli.'
):format(
Config.Combat.LethalWindowSeconds,
#hits
),
0
)
lethalHits[sender] = {}
end
end
end
end
end)
-- İsteğe bağlı entity spam koruması
if Config.EntityCreation.Enabled then
AddEventHandler('entityCreating', function(entity)
local owner = NetworkGetEntityOwner(entity)
if owner and owner > 0 then
local allowed = RateLimit(
owner,
'entityCreating',
Config.EntityCreation.MaxEntities,
Config.EntityCreation.WindowMilliseconds
)
if not allowed then
CancelEvent()
SecurityLog(
owner,
'Entity oluşturma limiti aşıldı.',
2
)
end
end
end)
end
AddEventHandler('playerDropped', function()
local src = source
local prefix = tostring(src) .. ':'
playerStrikes[src] = nil
lethalHits[src] = nil
for key in pairs(rateBuckets) do
if key:sub(1, #prefix) == prefix then
rateBuckets[key] = nil
end
end
end)
Önemli: Bu resource tek başına diğer scriptlerde bulunan açık eventleri kapatmaz. Aşağıdaki güvenli kontrolleri para ve item veren scriptlerin server dosyalarına uygulamanız gerekir.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4. Resource Başlatma Sırası
server.cfg içerisine şu sırayla ekleyin:
Kod:
ensure qb-core
ensure qb-inventory
ensure qb-log
ensure exxdev_security
# Korunacak meslek ve market scriptleri bundan sonra başlamalıdır.
ensure exx-shop
ensure exx-job
qb-log kullanmıyorsanız ilgili satırı kaldırabilirsiniz. Güvenlik sistemi konsol üzerinden yine kayıt oluşturacaktır.
Sunucuyu yeniden başlatın ve konsolda hata bulunmadığını kontrol edin.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
5. Güvenli Market Satın Alma Eventi
Aşağıdaki örnekte client yalnızca item adı ve miktar gönderir. Fiyat, maksimum miktar, oyuncunun konumu, parası ve envanter kapasitesi server tarafından kontrol edilir.
Bu kodu kendi market scriptinizin server dosyasına uyarlayın:
Kod:
local QBCore = exports['qb-core']:GetCoreObject()
local Market = {
coords = vector3(25.74, -1347.27, 29.49),
maximumDistance = 5.0,
items = {
water_bottle = {
price = 3,
maximumAmount = 10
},
sandwich = {
price = 5,
maximumAmount = 10
}
}
}
RegisterNetEvent('exx-shop:server:buyItem', function(itemName, requestedAmount)
local src = source
if not exports['exxdev_security']:RateLimit(
src,
'exx-shop:buyItem',
5,
5000
) then
return
end
if type(itemName) ~= 'string' then
exports['exxdev_security']:Flag(
src,
'Market eventinde geçersiz item türü.',
1
)
return
end
local itemData = Market.items[itemName]
if not itemData then
exports['exxdev_security']:Flag(
src,
'Market listesinden bulunmayan item istenildi: ' .. itemName,
2
)
return
end
local amount = exports['exxdev_security']:PositiveInteger(
requestedAmount,
itemData.maximumAmount
)
if not amount then
exports['exxdev_security']:Flag(
src,
'Market eventinde geçersiz miktar.',
1
)
return
end
if not exports['exxdev_security']:IsNear(
src,
Market.coords,
Market.maximumDistance
) then
exports['exxdev_security']:Flag(
src,
'Marketten uzakta satın alma eventi tetiklendi.',
2
)
return
end
local Player = QBCore.Functions.GetPlayer(src)
if not Player then
return
end
local totalPrice = itemData.price * amount
local canAdd, reason = exports['qb-inventory']:CanAddItem(
src,
itemName,
amount
)
if not canAdd then
TriggerClientEvent(
'QBCore:Notify',
src,
reason or 'Envanterinizde yeterli alan bulunmuyor.',
'error'
)
return
end
local paid = Player.Functions.RemoveMoney(
'cash',
totalPrice,
'exx-shop-purchase'
)
if not paid then
TriggerClientEvent(
'QBCore:Notify',
src,
'Yeterli paranız bulunmuyor.',
'error'
)
return
end
local added = exports['qb-inventory']:AddItem(
src,
itemName,
amount,
false,
false,
'exx-shop-purchase'
)
if not added then
Player.Functions.AddMoney(
'cash',
totalPrice,
'exx-shop-refund'
)
TriggerClientEvent(
'QBCore:Notify',
src,
'Item eklenemediği için ücret iade edildi.',
'error'
)
return
end
TriggerClientEvent(
'QBCore:Notify',
src,
('%sx %s satın aldınız.'):format(amount, itemName),
'success'
)
end)
Bu yapıda hile kullanan kişi fiyatı değiştiremez. Çünkü fiyat client tarafından alınmaz; server içerisindeki Market tablosundan hesaplanır.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
6. Güvenli Meslek Ödülü Sistemi
Sadece “meslek bitti” eventi kullanmak yeterli değildir. Oyuncunun görevi başlatıp başlatmadığı, checkpoint sırası, geçen süre ve konumu server tarafından takip edilmelidir.
Aşağıdaki örneği meslek scriptinizin server dosyasına ekleyebilirsiniz:
Kod:
local QBCore = exports['qb-core']:GetCoreObject()
local ActiveJobs = {}
local Job = {
requiredJob = 'garbage',
startCoords = vector3(-322.24, -1545.82, 31.02),
maximumDistance = 8.0,
reward = {
minimum = 400,
maximum = 550
},
steps = {
{
coords = vector3(114.18, -1462.01, 29.29),
minimumDelay = 20
},
{
coords = vector3(-6.04, -1566.23, 29.21),
minimumDelay = 20
},
{
coords = vector3(-146.67, -1688.35, 33.06),
minimumDelay = 20
}
}
}
RegisterNetEvent('exx-job:server:start', function()
local src = source
if not exports['exxdev_security']:RateLimit(
src,
'exx-job:start',
2,
10000
) then
return
end
if ActiveJobs[src] then
return
end
if not exports['exxdev_security']:IsNear(
src,
Job.startCoords,
Job.maximumDistance
) then
exports['exxdev_security']:Flag(
src,
'Meslek başlangıç noktasından uzakta start eventi.',
2
)
return
end
local Player = QBCore.Functions.GetPlayer(src)
if not Player then
return
end
if Job.requiredJob
and Player.PlayerData.job.name ~= Job.requiredJob
then
exports['exxdev_security']:Flag(
src,
'Yanlış meslekle görev başlatılmaya çalışıldı.',
1
)
return
end
ActiveJobs[src] = {
nextStep = 1,
lastStepAt = os.time(),
startedAt = os.time()
}
TriggerClientEvent(
'QBCore:Notify',
src,
'Görev güvenli şekilde başlatıldı.',
'success'
)
end)
RegisterNetEvent('exx-job:server:completeStep', function(requestedStep)
local src = source
if not exports['exxdev_security']:RateLimit(
src,
'exx-job:completeStep',
4,
5000
) then
return
end
local session = ActiveJobs[src]
if not session then
exports['exxdev_security']:Flag(
src,
'Görev başlatılmadan checkpoint eventi tetiklendi.',
2
)
return
end
local step = exports['exxdev_security']:PositiveInteger(
requestedStep,
#Job.steps
)
if not step or step ~= session.nextStep then
exports['exxdev_security']:Flag(
src,
'Meslek checkpoint sırası değiştirildi.',
2
)
return
end
local stepData = Job.steps[step]
local now = os.time()
if now - session.lastStepAt < stepData.minimumDelay then
exports['exxdev_security']:Flag(
src,
'Meslek checkpointi mümkün olmayan sürede tamamlandı.',
1
)
return
end
if not exports['exxdev_security']:IsNear(
src,
stepData.coords,
Job.maximumDistance
) then
exports['exxdev_security']:Flag(
src,
'Checkpointten uzakta görev eventi tetiklendi.',
2
)
return
end
session.lastStepAt = now
if step < #Job.steps then
session.nextStep = step + 1
TriggerClientEvent(
'QBCore:Notify',
src,
('Görev aşaması tamamlandı: %s/%s'):format(step, #Job.steps),
'success'
)
return
end
-- Event tekrar tetiklense bile ikinci kez para vermemesi için
-- ödülden önce aktif görev silinir.
ActiveJobs[src] = nil
local Player = QBCore.Functions.GetPlayer(src)
if not Player then
return
end
local reward = math.random(
Job.reward.minimum,
Job.reward.maximum
)
Player.Functions.AddMoney(
'bank',
reward,
'exx-job-secure-reward'
)
TriggerClientEvent(
'QBCore:Notify',
src,
('$%s meslek ödülü banka hesabınıza yatırıldı.'):format(reward),
'success'
)
end)
AddEventHandler('playerDropped', function()
ActiveJobs[source] = nil
end)
Kendi meslek scriptinizdeki koordinatları, minimum süreleri, meslek adını ve ödülleri değiştirin.
Not: Bu sistem teleport kullanan oyuncuyu tek başına kesin olarak tespit etmez. Ancak görevi başlatmadan, sırasını tamamlamadan veya doğrudan para eventini spamlayarak ödül alınmasını engeller.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
7. Güvenli Item Satış Mantığı
Item satan scriptlerde para vermeden önce item server tarafından kaldırılmalıdır.
Kod:
local QBCore = exports['qb-core']:GetCoreObject()
local SellPrices = {
copper = 25,
iron = 35,
aluminum = 30
}
RegisterNetEvent('exx-sell:server:sellItem', function(itemName, requestedAmount)
local src = source
if not exports['exxdev_security']:RateLimit(
src,
'exx-sell:sellItem',
5,
5000
) then
return
end
if type(itemName) ~= 'string' or not SellPrices[itemName] then
exports['exxdev_security']:Flag(
src,
'Geçersiz item satış isteği.',
2
)
return
end
local amount = exports['exxdev_security']:PositiveInteger(
requestedAmount,
25
)
if not amount then
return
end
local removed = exports['qb-inventory']:RemoveItem(
src,
itemName,
amount,
false,
'exx-secure-item-sale'
)
if not removed then
exports['exxdev_security']:Flag(
src,
'Sahip olunmayan item satılmaya çalışıldı.',
2
)
return
end
local Player = QBCore.Functions.GetPlayer(src)
if not Player then
return
end
local payment = SellPrices[itemName] * amount
Player.Functions.AddMoney(
'cash',
payment,
'exx-secure-item-sale'
)
end)
Satış fiyatını hiçbir zaman client tarafından almayın.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
8. Açık Eventleri Bulma
Visual Studio Code üzerinden resources klasörünü açın ve genel aramada aşağıdaki ifadeleri tek tek arayın:
Kod:
RegisterNetEvent
AddMoney(
SetMoney(
AddItem(
RemoveItem(
TriggerServerEvent
QBCore.Functions.CreateCallback
MySQL.query
MySQL.update
MySQL.insert
Özellikle şu yapıları arayın:
Kod:
AddMoney('cash', amount)
AddMoney('bank', price)
AddItem(item, amount)
SetMoney(moneyType, amount)
Her network eventinde şu soruları sorun:
- Miktar client tarafından mı geliyor?
- Fiyat client tarafından mı geliyor?
- Oyuncunun mesleği server üzerinden kontrol ediliyor mu?
- Oyuncunun konumu server üzerinden kontrol ediliyor mu?
- Event için cooldown veya rate limit var mı?
- Item gerçekten oyuncuda bulunuyor mu?
- Oyuncu hedef oyuncuya yakın mı?
- Görev daha önce başlatılmış mı?
- Checkpointler doğru sırayla tamamlanmış mı?
- Yetkili işlemlerinde ACE veya QBCore permission kontrolü var mı?
Event adını karmaşık veya rastgele yapmak güvenlik sağlamaz. Hile kullanan kişi event adlarını görebilir. Eventin kendisi güvenli olmalıdır.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
9. Aim Hilesi Hakkında Gerçekler
Aim hilesi kullanan bir oyuncu server tarafına çoğu zaman normal bir silah hasarı gibi görünen veri gönderebilir. Bu nedenle yalnızca “çok headshot attı” kontrolüyle otomatik ban atmak doğru değildir.
Yukarıdaki güvenlik resource’u:
- Bir saniyedeki aşırı hasar eventi sayısını sınırlar.
- Anormal override hasarını iptal eder.
- Kısa sürede gerçekleşen ölümcül hitleri loglar.
- Şüpheli oyuncuyu personel incelemesine yönlendirir.
Ancak ölümcül hit kaydı tek başına aim kanıtı değildir. İyi oynayan oyuncular, pompalı tüfekler, yakın mesafe çatışmaları veya özel silah scriptleri yanlış alarm oluşturabilir.
Bu nedenle:
- Aim kayıtlarında otomatik ban kullanmayın.
- Oyuncunun geçmiş combat loglarını kontrol edin.
- Personel tarafından spectate incelemesi yapın.
- Silah türü, mesafe, isabet serisi ve çatışma koşullarını birlikte değerlendirin.
- Kesin olmayan tespitlerde kalıcı ban uygulamayın.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
10. Wallhack Tamamen Engellenebilir mi?
Wallhack, oyuncunun istemcisine gönderilen entity ve oyuncu bilgilerini ekranda farklı şekilde göstermeye dayanabilir. Server tarafındaki basit bir Lua kodu oyuncunun ekranındaki çizgi, kutu veya iskelet görüntüsünü doğrudan göremez.
Wallhack riskini azaltmak için:
- Güncel FiveM artifact kullanın.
- Güncel ve aktif geliştirilen bir anti-cheat kullanın.
- Gereksiz oyuncu ve koordinat verilerini client eventleriyle dağıtmayın.
- Bütün oyuncuların koordinatlarını sürekli broadcast eden scriptleri kaldırın.
- Yönetici blip ve isim sistemlerini sadece yetkililere açın.
- Görev odaklı özel oturumlarda doğru routing bucket kullanın.
- Whitelist ve hesap doğrulama sistemi uygulayın.
- Combat loglarıyla şüpheli takip davranışlarını inceleyin.
Routing bucket sistemini bütün ana haritaya bilinçsiz şekilde uygulamayın. Özellikle mevcut entity ve garaj sistemleriyle test edilmeden strict lockdown açılması scriptleri bozabilir.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
11. QBCore Yetki Güvenliği
QBCore içerisinde aşağıdaki komutlar normal şartlarda admin yetkisine bağlıdır:
Kod:
/givemoney
/setmoney
/giveitem
/addpermission
/removepermission
server.cfg içerisindeki QBCore yetkilerini kontrol edin:
Kod:
add_ace group.admin command allow
add_ace resource.qb-core command allow
add_ace qbcore.god command allow
add_principal qbcore.god group.admin
add_principal qbcore.god qbcore.admin
add_principal qbcore.admin qbcore.mod
Oyuncu yetkileri için isim veya geçici server ID kullanmayın. Kalıcı Rockstar license identifier kullanın:
Kod:
add_principal identifier.license:BURAYA_LICENSE qbcore.admin
Kontrol edilmesi gerekenler:
- Eski yetkililerin license satırlarını kaldırın.
- Herkese god veya admin vermeyin.
- Scriptlerin içerisinde gizli admin identifier olup olmadığını kontrol edin.
- txAdmin üzerinde herkese all_permissions vermeyin.
- Console erişimini yalnızca güvenilir yöneticilere verin.
- server.cfg ve txData dosyalarını herkese açmayın.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
12. Yüksek Para Bakiyelerini SQL ile Kontrol Etme
Aşağıdaki sorguyu phpMyAdmin veya HeidiSQL üzerinden çalıştırarak en yüksek bakiyeleri görüntüleyebilirsiniz:
Kod:
SELECT
citizenid,
CAST(
COALESCE(
JSON_UNQUOTE(JSON_EXTRACT(money, '$.cash')),
'0'
) AS DECIMAL(20, 2)
) AS cash,
CAST(
COALESCE(
JSON_UNQUOTE(JSON_EXTRACT(money, '$.bank')),
'0'
) AS DECIMAL(20, 2)
) AS bank,
CAST(
COALESCE(
JSON_UNQUOTE(JSON_EXTRACT(money, '$.crypto')),
'0'
) AS DECIMAL(20, 2)
) AS crypto
FROM players
ORDER BY bank DESC
LIMIT 50;
Bu sorgu yalnızca kontrol içindir; hiçbir oyuncunun parasını silmez.
Şüpheli hesap tespit edildiğinde hemen para silmek yerine:
- qb-log para kayıtlarını kontrol edin.
- Para hareketindeki reason bilgisini inceleyin.
- Parayı veren resource’u tespit edin.
- Açık eventi kapatın.
- Aynı açıktan yararlanan diğer hesapları bulun.
- Yedek aldıktan sonra gerekli ekonomi düzeltmesini yapın.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
13. Test Aşaması
Kurulumdan sonra aşağıdaki testleri yapın:
- Normal market satın alma işlemini deneyin.
- Yetersiz parayla ürün almaya çalışın.
- Maksimum miktarın üzerinde ürün almaya çalışın.
- Market noktasından uzakta eventi çalıştırmayı deneyin.
- Görevi başlatmadan bitirme eventini test edin.
- Checkpointleri yanlış sırayla tamamlamayı deneyin.
- Aynı eventi kısa sürede tekrar tekrar çağırın.
- Yüksek para vererek log sistemini test edin.
- Normal çatışmalarda yanlış hasar iptali olup olmadığını kontrol edin.
- Araç, garaj, telefon ve ses scriptlerini test edin.
İlk aşamada:
Kod:
Config.AutoKick = false
kullanın.
En az birkaç gün boyunca logları inceleyin. Yanlış alarm olmadığından emin olduktan sonra otomatik kick sistemini açabilirsiniz:
Kod:
Config.AutoKick = true
Şüpheli aim veya wallhack kayıtlarında otomatik kalıcı ban tavsiye edilmez.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Sonuç
FiveM güvenliğinde en önemli kural şudur:
CLIENT TARAFINDAN GELEN HİÇBİR VERİYE DOĞRUDAN GÜVENMEYİN.
Para, fiyat, ödül, item, meslek, konum ve yetki kontrollerini server tarafında gerçekleştirin. Eventlere rate limit ekleyin, yüksek para hareketlerini kaydedin ve her scripti tek tek denetleyin.
Aim ve wallhack için yalnızca basit Lua kontrollerine güvenmeyin. Güncel artifact, güvenli server eventleri, doğru yapılandırılmış anti-cheat, whitelist ve personel incelemesini birlikte kullanın.
Hazırlayan: ExxDev
Kaynak belirtilmeden paylaşılmaması rica olunur.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Resmî Kaynaklar
