作弊允许恶意客户端在任何上下文中触发事件。了解如何保护客户端-服务器通信、实现服务器端验证以及配置 FXServer 安全 Convars。
反作弊团队一直在努力改进反作弊系统,但有时还是会有漏洞。
在本指南中,我们将尝试帮助您介绍一些常见做法,您可以通过正确锁定事件来使服务器更加安全。
作弊可以允许客户端在任何上下文中触发事件。
当我们说上下文时,是指他们可以执行客户端->服务器(通过 TriggerServerEvent)或客户端资源->客户端资源(通过 TriggerEvent)。
在 Lua 中处理事件时,根据事件是由客户端还是服务器调用来正确注册它们至关重要。
一个常见的错误是注册了不应该被客户端调用的服务器事件,反之亦然,这可能会导致严重的安全漏洞。
当事件旨在在相同上下文(客户端-客户端或服务器-服务器)内触发时,请使用 AddEventHandler。这可以确保事件不联网,并且不能被对立面调用。
AddEventHandler("eventName", function(eventParam1, eventParam2)
-- 一旦在相同上下文中触发事件,此处代码将被执行。
end)当事件需要跨不同上下文触发时(例如从客户端到服务器,或从服务器到客户端),请使用 RegisterNetEvent。
RegisterNetEvent("eventName", function(eventParam1, eventParam2)
-- 一旦跨不同上下文触发事件,此处代码将被执行。
end)此示例针对客户端,与客户端上的任何内容一样,它不是万无一失的,并且可以被作弊客户端操纵。
如果您想阻止来自相同上下文的执行(例如防止客户端触发服务器到服务器的网络事件),您应该注册您的事件并验证发件人来源:
RegisterNetEvent("eventName", function(eventParam1, eventParam2)
-- 服务器将为来自服务器的事件发送网络 ID `65535`
if source ~= 65535 then return end
end)即使您构建了强大的反作弊系统,在服务器事件上添加检查也会使其显著更加安全。这是一种强烈推荐的做法,尽管它不能防止所有事情。下面,我们分享一些不错的技巧。
这可以确保您游戏环境的完整性和安全。
以下所有示例均假设使用某种框架(例如 ESX、QB-Core 等)。
这是为了向您展示做事件的不安全方式,您千万不要这样做。直接根据用户自身的输入向其添加物品总是糟糕的做法:您应该始终验证用户输入。
RegisterNetEvent("job:givePlayerItem", function(item, count)
local ply = FX.GetPlayerFromSource(source)
-- 直接根据用户自身的输入向其添加物品是不安全的!
ply.addItem(item, count)
end)这是一个强大的安全模式。服务器追踪玩家状态和坐标,并使用服务器端 Tick 验证操作,而不是仅仅依赖客户端触发器。
-- 随机坐标
local VALID_JOB_COORD = vector3(125.0, 111.1, 35.83)
local MAX_ITEM_COUNT = 10
-- 随机坐标
local VALID_TURNIN_COORD = vector3(1888.0, 1254.1, 48.0)
local ITEM_NAME = 'log'
-- 具有活跃工作的玩家列表
local activeJobs = {}
AddEventHandler("playerDropped", function ()
if not activeJobs[source] then return end
activeJobs[source] = nil
end)
function isPedWithinRange(ped, tgtCoords)
return #(GetEntityCoords(ped) - tgtCoords) < 15.0
end
-- 在服务器端处理增加玩家获得的物品数量
CreateThread(function()
while true do
for src, data in pairs(activeJobs) do
local ped = GetPlayerPed(src)
-- 如果他们不在范围内,我们就不想给他们物品
if isPedWithinRange(ped, VALID_JOB_COORD) then
-- 给他们物品,但限制为 MAX_ITEM_COUNT
data.itemCount = math.min(data.itemCount + 1, MAX_ITEM_COUNT)
end
end
-- 每秒处理一次工作 tick
Wait(1000)
end
end)
RegisterNetEvent("job:startJob", function()
local ped = GetPlayerPed(source)
-- 如果他们在 15 个单位内,他们就在做这项工作
if isPedWithinRange(ped, VALID_JOB_COORD) then
activeJobs[source] = {
itemCount = 0,
}
end
end)
RegisterNetEvent("job:givePlayerItem", function()
local ply = FX.GetPlayerFromSource(source)
-- 如果他们没有活跃的工作,他们就不应该触发这个!
local jobData = activeJobs[source]
if not jobData then return end
local ped = GetPlayerPed(source)
-- 他们不在交件坐标范围内,拒绝其更改
if not isPedWithinRange(ped, VALID_TURNIN_COORD) then return end
-- 重置物品数据,以便他们无法多次触发它
activeJobs[source] = nil
-- 将经验证的物品添加到用户,在服务器端验证
ply.addItem(ITEM_NAME, jobData.itemCount)
end)请注意,除非您确切知道自己在做什么,否则不应修改以下设置。Cfx.re / Adhesive 团队一直在非常努力地防范作弊者。在 FXServer 8450 构建版本及更高版本中,您将默认启用大多数这些功能。
激活这些 Convars 可能会让玩家因以下原因被踢出: Connection to CNL timed out.
被踢出并不意味着玩家被自动全局封禁 (Global Ban)。然而,它提供了玩家可靠性的有力指示,这对于评估信任度非常有用。
所提供的代码并不适用于直接复制粘贴使用。这只是一些防止服务器中可能发生的某些行为的提示。这需要一些编程知识。欢迎您随时加入我们的 Discord 以获取更多帮助。