Cheats permitem que clientes maliciosos acionem eventos em qualquer contexto. Aprenda a proteger a comunicação cliente-servidor, implementar validação no lado do servidor e configurar convars de segurança do FXServer.
A equipe do anti-cheat está sempre tentando melhorar o anti-cheat, mas às vezes algumas coisas passam.
Neste guia, tentaremos ajudar a cobrir algumas práticas comuns que você pode adotar para tornar seu servidor mais seguro, bloqueando adequadamente seus eventos.
Cheats podem permitir que o cliente acione eventos em qualquer contexto.
Quando dizemos contexto, queremos dizer que eles podem executar cliente->servidor (via TriggerServerEvent) ou recurso do cliente->recurso do cliente (via TriggerEvent).
Ao trabalhar com eventos em Lua, é crucial registrá-los corretamente com base em se eles são chamados pelo cliente ou pelo servidor.
Um erro comum é registrar eventos do servidor que não deveriam ser chamados pelo cliente, ou vice-versa, o que pode levar a graves vulnerabilidades de segurança.
Use AddEventHandler quando o evento for destinado a ser acionado no mesmo contexto, seja cliente-cliente ou servidor-servidor. Isso garante que os eventos não sejam transmitidos pela rede e não possam ser chamados pelo lado oposto.
AddEventHandler("eventName", function(eventParam1, eventParam2)
-- O código aqui será executado assim que o evento for acionado no mesmo contexto.
end)Use RegisterNetEvent quando o evento precisar ser acionado em diferentes contextos, como do cliente para o servidor ou do servidor para o cliente.
RegisterNetEvent("eventName", function(eventParam1, eventParam2)
-- O código aqui será executado assim que o evento for acionado em diferentes contextos.
end)Este exemplo é para o cliente e, como qualquer coisa no cliente, não é infalível e pode ser manipulado por clientes trapaceiros.
Se você deseja bloquear a execução no mesmo contexto (como impedir que um evento de rede de servidor para servidor seja acionado pelo cliente), você deve registrar seu evento e verificar a fonte do remetente:
RegisterNetEvent("eventName", function(eventParam1, eventParam2)
-- O servidor enviará o ID de rede `65535` para eventos do servidor
if source ~= 65535 then return end
end)Mesmo que você construa um anti-cheat forte, adicionar verificações nos eventos do servidor os torna significativamente mais seguros. Esta é uma prática altamente recomendada, embora não evite tudo. Abaixo, compartilhamos algumas boas dicas.
Isso garante a integridade e a segurança do seu ambiente de jogo.
Todos os exemplos abaixo assumem algum tipo de framework (como ESX, QB-Core, etc.).
Isso serve para mostrar maneiras incorretas de lidar com eventos. Você nunca deve fazer isso. Adicionar itens diretamente ao usuário a partir de sua própria entrada é sempre uma má prática: você sempre deve validar a entrada do usuário.
RegisterNetEvent("job:givePlayerItem", function(item, count)
local ply = FX.GetPlayerFromSource(source)
-- Adicionar itens diretamente ao usuário a partir de sua própria entrada é inseguro!
ply.addItem(item, count)
end)Aqui está um padrão de segurança robusto. O servidor acompanha o estado e as coordenadas do jogador e verifica as ações usando ticks no lado do servidor, em vez de depender apenas de gatilhos do cliente.
-- coordenada fictícia
local VALID_JOB_COORD = vector3(125.0, 111.1, 35.83)
local MAX_ITEM_COUNT = 10
-- coordenada fictícia
local VALID_TURNIN_COORD = vector3(1888.0, 1254.1, 48.0)
local ITEM_NAME = 'log'
-- lista de jogadores com trabalhos ativos
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
-- processar tick do trabalho e incrementar quantidade de itens no lado do servidor
CreateThread(function()
while true do
for src, data in pairs(activeJobs) do
local ped = GetPlayerPed(src)
-- se não estiverem ao alcance, não queremos dar o item a eles
if isPedWithinRange(ped, VALID_JOB_COORD) then
-- dê o item a eles, mas limite a MAX_ITEM_COUNT
data.itemCount = math.min(data.itemCount + 1, MAX_ITEM_COUNT)
end
end
-- processar o tick do trabalho uma vez por segundo
Wait(1000)
end
end)
RegisterNetEvent("job:startJob", function()
local ped = GetPlayerPed(source)
-- se estiverem a menos de 15 unidades, estão fazendo o trabalho
if isPedWithinRange(ped, VALID_JOB_COORD) then
activeJobs[source] = {
itemCount = 0,
}
end
end)
RegisterNetEvent("job:givePlayerItem", function()
local ply = FX.GetPlayerFromSource(source)
-- se não tiverem um trabalho ativo, não deveriam estar acionando isso!
local jobData = activeJobs[source]
if not jobData then return end
local ped = GetPlayerPed(source)
-- eles não estão dentro do alcance das coordenadas de entrega, rejeite as alterações
if not isPedWithinRange(ped, VALID_TURNIN_COORD) then return end
-- redefina os dados do item para que não possam acioná-lo várias vezes
activeJobs[source] = nil
-- adicionar itens ao usuário validados no lado do servidor
ply.addItem(ITEM_NAME, jobData.itemCount)
end)Observe que as seguintes configurações não devem ser modificadas a menos que você saiba exatamente o que está fazendo. A equipe do Cfx.re / Adhesive está sempre trabalhando duro para evitar trapaceiros. A maioria desses recursos estará ativada por padrão a partir da versão de compilação do FXServer 8450 e superiores.
Ter essas convars ativas provavelmente fará com que o jogador seja expulso com o seguinte motivo: Connection to CNL timed out.
Ser expulso não significa que o jogador seja automaticamente banido globalmente (Global Banned). No entanto, fornece uma forte indicação da confiabilidade do jogador, o que é extremamente útil para avaliar a confiabilidade.
Os códigos fornecidos não devem funcionar no método de copiar e colar. São apenas algumas dicas para evitar ações que possam acontecer no servidor. Isso requer conhecimento de programação. Você sempre pode entrar em nosso Discord para obter ajuda adicional.