20 במאי 2026
5 min read
ZeroTrust Team

אבטחו את האירועים שלכם: מדריך אבטחת אירועי FiveM Lua

צ'יטים מאפשרים לקליינטים זדוניים להפעיל אירועים בכל הקשר. למדו כיצד לאבטח את התקשורת בין הקליינט לשרת, ליישם אימות בצד השרת ולהגדיר משתני אבטחה של FXServer.

צוות האנטי-צ'יט תמיד מנסה לשפר את האנטי-צ'יט, אבל לפעמים דברים חומקים.

במדריך זה ננסה לעזור לכסות כמה דברים נפוצים שתוכלו לעשות כדי להפוך את השרת שלכם למאובטח יותר על ידי נעילה נכונה של האירועים שלכם.

הבנת אירועי רשת ב-FiveM

צ'יטים יכולים לאפשר לקליינט להפעיל אירועים בכל הקשר.

כשאנו אומרים הקשר (context) אנו מתכוונים שהם יכולים לבצע קליינט->שרת (באמצעות TriggerServerEvent) או משאב קליינט->משאב קליינט (באמצעות TriggerEvent).

שימוש נכון במטפלי אירועים ב-Lua

בעבודה עם אירועים ב-Lua, חיוני לרשום אותם בצורה נכונה בהתבסס על השאלה האם הם נקראים על ידי הקליינט או השרת.

טעות נפוצה היא רישום אירועי שרת שאינם אמורים להיקרא על ידי הקליינט, או להיפך, מה שעלול להוביל לפרצות אבטחה חמורות.

AddEventHandler

השתמשו ב-AddEventHandler כאשר האירוע מיועד להפעלה באותו הקשר, קליינט-קליינט או שרת-שרת. זה מבטיח שהאירועים אינם מרושתים ולא ניתן לקרוא להם מהצד השני.

AddEventHandler("eventName", function(eventParam1, eventParam2)
    -- הקוד כאן יבוצע ברגע שהאירוע יופעל באותו הקשר.
end)

RegisterNetEvent

השתמשו ב-RegisterNetEvent כאשר האירוע צריך להיות מופעל בהקשרים שונים, כגון מקליינט לשרת או משרת לקליינט.

מתחת למכסה המנוע

הערה: זה לא חוסם ביצוע מאותו הקשר. מתחת למכסה המנוע RegisterNetEvent הוא פשוט מעטפת שהיא הדבר הבא: RegisterNetEvent("eventName") AddEventHandler("eventName", function() ... end)
RegisterNetEvent("eventName", function(eventParam1, eventParam2)
    -- הקוד כאן יבוצע ברגע שהאירוע יופעל בהקשרים שונים.
end)

דוגמה זו מיועדת לקליינט, וכמו כל דבר בקליינט, היא אינה חסינת כדורים וניתנת למניפולציה על ידי קליינטים שמשתמשים בצ'יטים.

אם ברצונכם לחסום ביצוע מאותו הקשר (כמו מניעת הפעלת אירוע רשת שרת-לשרת על ידי הקליינט), עליכם לרשום את האירוע שלכם ולאמת את מקור השולח:

RegisterNetEvent("eventName", function(eventParam1, eventParam2)
    -- השרת ישלח מזהה רשת `65535` עבור אירועים מהשרת
    if source ~= 65535 then return end
end)

הוספת בדיקות ואימות

גם אם תבנו אנטי-צ'יט חזק, הוספת בדיקות לאירועי שרת הופכת אותם למאובטחים משמעותית יותר. זוהי פרקטיקה מומלצת ביותר, אם כי היא אינה מונעת הכל. להלן אנו משתפים כמה טיפים טובים.

  • כסף של שחקן: אמתו יתרה ועסקאות בצד השרת.
  • State bags של שחקן: אמתו נתוני מצב בסשנים פעילים.
  • פריטי אינוונטר של שחקן: בדקו שמות פריטים וכמויות.
  • מיקום שחקן: אמתו טווחים ומרחקים.
  • ניסיון ורמה של שחקן: ודאו שהנתונים מחושבים בצד השרת.
  • הרשאות ותפקידים של שחקן: אמתו רשימת בקרת גישה (ACL) בצด השרת.

כלל אצבע

ודאו שאתם מאחזרים את כל הערכים באמצעות שיטות בצד השרת, ולא מאפשרים לשחקנים לספק או לשנות את הערכים. שימו לב שבדיקות קליינט יכולות להיות גם פרקטיקה טובה עבור חווית משתמש (UX) אך ניתנות לעקיפה בקלות.

זה מבטיח את שלמות ואבטחת סביבת המשחק שלכם.

דוגמאות לדפוסי אבטחה נפוצים

כל הדוגמאות להלן מניחות שימוש במסגרת עבודה כלשהי (כמו ESX, QB-Core וכו').

אבטחה גרועה (לעולם אל תעשו זאת)

זה נועד להראות לכם דרכים רעות לביצוע אירועים, לעולם אל תעשו זאת. הוספת פריטים ישירות למשתמש מהקלט שלו היא תמיד פרקטיקה גרועה: עליכם תמיד לאמת את קלט המשתמש.

RegisterNetEvent("job:givePlayerItem", function(item, count)
    local ply = FX.GetPlayerFromSource(source)
    -- הוספת פריטים ישירות למשתמש מהקלט שלו אינה בטוחה!
    ply.addItem(item, count)
end)

אבטחה טובה (מומלץ)

הנה דפוס אבטחה חזק. השרת עוקב אחר מצב השחקן והקואורדינטות שלו, ומאמת פעולות באמצעות טיקים בצד השרת במקום להסתמך אך ורק על טריגרים של הקליינט.

-- קואורדינטה אקראית
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
        -- עבד טיק עבודה פעם בשנייה
        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)

אפשרויות בעל שרת (Convars)

שימו לב שלא מומלץ לשנות את ההגדרות הבאות אלא אם כן אתם יודעים בדיוק מה אתם עושים. צוות Cfx.re / Adhesive תמיד עובד קשה כדי למנוע צ'יטרים. רוב התכונות הללו יהיו פעילות כברירת מחדל עם גרסת FXServer 8450 ומעלה.

  • sv_kick_players_cnl_timeout_sec: זהו זמן קצוב שלאחריו השרת יבעט את השחקן (למשל, אם הוא 600, יבעט אותו לאחר 10 דקות ללא חיבור CnL).
  • sv_kick_players_cnl_update_rate_sec: זו התדירות שבה מתבצעת שאילתה ל-CnL עם רשימת השחקנים.
  • sv_pure_verify_client_settings: מחליף את הבקשה המחזורית ל-info.json בקליינט. מקים חיבור מאובטח בין adhesive ל-svadhesive ומאמת חלק מהגדרות sv_settings כגون pureLevel, scripthook והגדרות אחרות.
  • sv_kick_players_cnl_consecutive_failures: כמה כשלונות רצופים מעבר ל-timeout_sec נדרשים כדי לבעוט שחקן. ברירת המחדל מוגדרת ל-2, מה שמציין שאם שחקן לא יבצע צ'ק-אין במשך 10 דקות ואז יחמיץ את עדכון הצ'ק-אין הבא, הוא ייבעט. זה משמש כמנגנון אל-כשל.
  • sv_authMaxVariance: שונות (variance) היא מידת הסבירות שמזהה המשתמש ישתנה עבור ספק נתון (כלומר 'steam', 'ip' או 'license').
  • sv_authMinTrust: אמון (trust) הוא מידת הסבירות הנמוכה שזהות המשתמש תזויף על ידי קליינט זדוני.
  • sv_filterRequestControl: משתנה קונסול המשמש לחסימת ניתוב REQUEST_CONTROL_EVENT בהתבסس על מדיניות הניתנת להגדרה.
  • sv_disableClientReplays: הפעלת אפשרות זו תפחית את הסיכויים לאפשרויות צ'יטים. שימו לב שהדבר ישבית את Rockstar Editor.

תוצאות על השחקן

הפעלת משתני קונסול אלו כנראה תגרום לבעיטת השחקן עם הסיבה הבאה: Connection to CNL timed out.

בעיטה מהשרת אינה אומרת שהשחקן מקבל באן גלובלי (Global Ban) באופן אוטומטי. עם זאת, היא מספקת אינדיקציה חזקה לאמינות השחקן, מה שמועיל ביותר להערכת מידת האמינות שלו.

חשוב לדעת

הקודים המסופקים אינם אמורים לעבוד בשיטה של העתק-הדבק. אלו רק כמה טיפים למניעת פעולות מסוימות שעלולות להתרחש בשרת. הדבר דורש ידע מסוים בתכנות. אתם תמיד מוזמנים להצטרף לדיסקורד שלנו כדי לקבל עזרה נוספת.