Roblox ใช้ระบบการจัดเตรียมฟิสิกส์แบบกระจาย ในระบบที่ลูกค้ามีอำนาจครอบครองการจำลองทางกายภาพของวัตถุในการควบคุมของพวกเขา, โดยปกติเป็นตัวละครของผู้เล่นและวัตถุที่ไม่ได้ถูกยึดติดกับตัวละครนั้นนอกจากนี้ ผ่านการใช้ซอฟต์แวร์บุคคลที่สาม ผู้โจมตีสามารถรันโค้ด Luau สุ่มบนไคลเอนต์เพื่อปรับแต่งโมเดลข้อมูลของไคลเอนต์และถอดรหัสและดูโค้ดที่ทำงานบนมัน
โดยรวมแล้ว ซึ่งหมายความว่าผู้ใช้ที่มีทักษะสามารถดําเนินการโค้ดเพื่อโกงในเกมของคุณได้ รวมถึง:
- เทเลพอร์ตตัวละครของตนเองไปรอบๆ สถานที่
- ยิงไม่ปลอดภัย RemoteEvents หรือเรียกใช้ RemoteFunctions เช่นเพื่อมอบรางวัลให้กับตัวเองโดยไม่ได้รับพวกเขา
- ปรับแต่งตัวละครของพวกเขา WalkSpeed เพื่อให้เคลื่อนที่ได้เร็วมาก
ในขณะที่คุณสามารถใช้การป้องกันการออกแบบที่จํากัด เพื่อจับการโจมตีทั่วไป คุณควรใช้กลยุทธ์การบรรเทาทางด้านเซิร์ฟเวอร์ที่เชื่อถือได้มากขึ้น เนื่องจากเซิร์ฟเวอร์เป็นอํานาจสูงสุดสําหรับประสบการณ์การทํางานใด ๆ
กลยุทธ์การออกแบบป้องกัน
การตัดสินใจออกแบบพื้นฐานสามารถใช้เป็นมาตรการรักษาความปลอดภัย "ขั้นแรก" เพื่อป้องกันการโจมตีตัวอย่างเช่น ในเกมยิงที่ผู้เล่นได้รับคะแนนจากการฆ่าผู้เล่นคนอื่น แฮ็กเกอร์อาจสร้างกลุ่มบอทที่เทเลพอร์ตไปยังสถานที่เดียวกันเพื่อให้สามารถฆ่าได้อย่างรวดเร็วเพื่อรับคะแนนพิจารณาสองวิธีและผลลัพธ์ที่คาดได้จากการโจมตีนี้:
วิธีการ | ผลลัพธ์ที่คาดได้ |
---|---|
ไล่บอทโดยการเขียนโค้ดที่พยายามตรวจจับพวกเขา | |
ลดหรือลบจุดได้รับสำหรับการฆ่าบนผู้เล่นที่เพิ่งเกิดใหม่ |
ในขณะที่การออกแบบป้องกันไม่ใช่ทางออกที่สมบูรณ์หรือครอบคลุม แต่ก็สามารถมีส่วนร่วมในการออกแบบการรักษาความปลอดภัยที่กว้างขึ้นพร้อมกับ การบรรเทาด้านเซิร์ฟเวอร์
การบรรเทาด้านเซิร์ฟเวอร์
มากที่สุดเท่าที่เป็นไปได้ เซิร์ฟเวอร์ ควร ออกคำตัดสินสุดท้ายเกี่ยวกับสิ่งที่เป็น "จริง" และสถานะปัจจุบันของโลกคืออะไรลูกค้าสามารถขอให้เซิร์ฟเวอร์ทำการเปลี่ยนแปลงหรือดำเนินการใดๆ ได้ แต่เซิร์ฟเวอร์ควร ตรวจสอบและอนุมัติ แอ็คชัน
ยกเว้นการดำเนินการทางกายภาพบางอย่าง การเปลี่ยนแปลงในโมเดลข้อมูลบนไคลเอนต์จะไม่ถูกส่งไปยังเซิร์ฟเวอร์ ดังนั้นเส้นทางการโจมตีหลักมักจะผ่านเหตุการณ์เครือข่ายที่คุณได้ประกาศไว้ด้วย RemoteEvents และ RemoteFunctionsโปรดจำไว้ว่าเอ็กซ์โพเลอร์ที่ดำเนินโค้ดของตนเองบนไคลเอนต์ของคุณสามารถเรียกใช้สิ่งเหล่านี้ด้วยข้อมูลใดก็ได้ที่พวกเขาต้องการ
การตรวจสอบประเภทการทำงานระยะไกล
เส้นทางการโจมตีหนึ่งสำหรับผู้โจมตีที่จะเรียก RemoteEvents และ RemoteFunctions พิมพ์อาจทำให้โค้ดบนเซิร์ฟเวอร์ที่ฟังรีโมทเหล่านี้เกิดข้อผิดพลาดในลักษณะที่เป็นประโยชน์ต่อผู้โจมตี
เมื่อใช้เหตุการณ์/ฟังก์ชันระยะไกลคุณสามารถป้องกันการโจมตีประเภทนี้โดยการตรวจสอบประเภท ของอาร์กิวเมนต์ที่ส่งบนเซิร์ฟเวอร์ โมดูล "t" ซึ่งมีอยู่ ที่นี่ เป็นประโยชน์สำหรับการตรวจสอบประเภทในลักษณะนี้ตัวอย่างเช่น คาดว่ารหัสของโมดูลมีอยู่เป็น ModuleScript ชื่อ t ภายใน ReplicatedStorage :
สคริปท้องถิ่นใน StarterPlayerScripts
local ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")-- ส่งสีและตำแหน่งส่วนที่ผ่านเมื่อเรียกใช้ฟังก์ชันlocal newPart = remoteFunction:InvokeServer(Color3.fromRGB(200, 0, 50), Vector3.new(0, 25, 0))if newPart thenprint("The server created the requested part:", newPart)elseif newPart == false thenprint("The server denied the request. No part was created.")end
สคริปต์ใน ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
local t = require(ReplicatedStorage:WaitForChild("t"))
-- สร้างตัวตรวจสอบประเภทล่วงหน้าเพื่อหลีกเลี่ยงค่าใช้จ่ายที่ไม่จำเป็น
local createPartTypeValidator = t.tuple(t.instanceIsA("Player"), t.Color3, t.Vector3)
-- สร้างส่วนใหม่ด้วยคุณสมบัติที่ส่งผ่าน
local function createPart(player, partColor, partPosition)
-- ตรวจสอบข้อโต้แย้งที่ผ่านมา
if not createPartTypeValidator(player, partColor, partPosition) then
-- กลับ "ไม่ถูกต้อง" อย่างเงียบๆ หากการตรวจสอบประเภทล้มเหลวที่นี่
-- การเพิ่มข้อผิดพลาดโดยไม่มีคูลดาวน์สามารถใช้เพื่อทำให้เซิร์ฟเวอร์ช้าลงได้
-- ให้ความคิดเห็นของไคลเอนต์แทน!
return false
end
print(player.Name .. " requested a new part")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
return newPart
end
-- ผูก "createPart()" กับการโทรกลับฟังก์ชันระยะไกล
remoteFunction.OnServerInvoke = createPart
การตรวจสอบข้อมูล
การโจมตีอีกอันหนึ่งที่ผู้โจมตีอาจเปิดตัวคือการส่ง ประเภทที่ถูกต้องทางเทคนิค แต่ทำให้พวกเขาใหญ่มาก ยาว หรืออื่นอย่างไม่ถูกต้องตัวอย่างเช่น หากเซิร์ฟเวอร์ต้องดำเนินการด้วยค่าใช้จ่ายสูงในการทำงานกับสตริงที่ขยายตามความยาว แฮ็กเกอร์สามารถส่งสตริงที่มีขนาดใหญ่หรือแบบฟอร์มไม่ถูกต้องไปยังเซิร์ฟเวอร์ได้อย่างน่าอัศจรรย์
เช่นเดียวกับทั้ง inf และ NaN จะ type() เป็น number แต่ทั้งสองสามารถทําให้เกิดปัญหาใหญ่ได้หากมีการส่งพวกเขาและไม่ได้รับการจัดการอย่างถูกต้องผ่านฟังก์ชันเช่นต่อไปนี้กำลังติดตาม
local function isNaN(n: number): boolean
-- NaN ไม่เท่ากับตัวเอง
return n ~= n
end
local function isInf(n: number): boolean
-- ตัวเลขอาจเป็น -inf หรือ inf
return math.abs(n) == math.huge
end
การโจมตีทั่วไปอีกอันหนึ่งที่ผู้โจมตีอาจใช้คือการส่ง tables แทน Instanceโหลดที่ซับซ้อนสามารถจำลองสิ่งที่จะเป็นการอ้างอิงวัตถุธรรมดาได้
ตัวอย่างเช่น มีระบบ ร้านค้าในประสบการณ์ ที่มีข้อมูลรายการเช่นราคาถูกเก็บไว้ในวัตถุ NumberValue กำลังติดตาม
สคริปท้องถิ่นใน StarterPlayerScripts
local ReplicatedStorage = game:GetService("ReplicatedStorage")local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")local payload = {Name = "Ultra Blade",ClassName = "Folder",Parent = itemDataFolder,Price = {Name = "Price",ClassName = "NumberValue",Value = 0, -- ค่าลบยังสามารถใช้ได้ ซึ่งจะทำให้ได้รับเงินแทนที่จะเอาไป!},}-- ส่งภาระที่เป็นอันตรายไปยังเซิร์ฟเวอร์ (จะถูกปฏิเสธ)print(buyItemEvent:InvokeServer(payload)) -- ออก "false รายการไม่ถูกต้องที่ให้"-- ส่งรายการจริงไปยังเซิร์ฟเวอร์ (จะผ่านไป!)print(buyItemEvent:InvokeServer(itemDatafolder["Real Blade"])) -- Outputs "true" and remaining currency if purchase succeeds
สคริปต์ใน ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local function buyItem(player, item)
-- ตรวจสอบว่าไอเทมที่ผ่านมาไม่ถูกสอดแนมและอยู่ในไดเรกทอรี ItemData
if typeof(item) ~= "Instance" or not item:IsDescendantOf(itemDataFolder) then
return false, "Invalid item provided"
end
-- เซิร์ฟเวอร์สามารถดำเนินการต่อเพื่อประมวลผลการซื้อตามตัวอย่างการไหลข้างล่าง
end
-- ผูก "buyItem()" กับการโทรกลับฟังก์ชันระยะไกล
buyItemEvent.OnServerInvoke = buyItem
การตรวจสอบค่า
นอกจากการตรวจสอบประเภท และข้อมูล ที่ถูกต้องแล้ว คุณควรตรวจสอบค่า ที่ส่งผ่านผ่าน และ เพื่อให้แน่ใจว่าถูกต้องและสมเหตุสมผลในบริบทที่ร้องขอตัวอย่างทั่วไปสองตัวคือร้านค้าในประสบการณ์ และระบบเล็งเป้าอาวุธ
เลือกซื้อ
พิจารณาระบบร้านค้าในประสบการณ์ที่มีอินเทอร์เฟซผู้ใช้ เช่น เมนูการเลือกผลิตภัณฑ์ที่มีปุ่ม "ซื้อ"เมื่อกดปุ่มแล้ว คุณสามารถเรียกใช้ RemoteFunction ระหว่างไคลเอนต์และเซิร์ฟเวอร์เพื่อขอซื้อได้อย่างไรก็ตาม เป็นสิ่งสำคัญที่เซิร์ฟเวอร์ จะต้องยืนยัน ว่าผู้ใช้มีเงินเพียงพอที่จะซื้อรายการ

เล็งอาวุธ
สถานการณ์การต่อสู้ต้องการความสนใจพิเศษในการตรวจสอบค่าโดยเฉพาะผ่านการเล็งและการตรวจสอบการโจมตี
จินตนาการถึงเกมที่ผู้เล่นสามารถยิงลำแสงเลเซอร์ไปยังผู้เล่นคนอื่นได้แทนที่จะให้ไคลเอนต์บอกเซิร์ฟเวอร์ ใคร ที่จะทำลาย กำลังติดตาม:
ตำแหน่งที่ลูกค้ารายงาน ยิงจาก อยู่ใกล้ตัวละครของผู้เล่นบนเซิร์ฟเวอร์โปรดทราบว่าเซิร์ฟเวอร์และไคลเอนต์จะแตกต่างกันเล็กน้อยเนื่องจากความล่าช้าดังนั้นจะต้องใช้ความอดทนเพิ่มเติม
ตำแหน่งที่ลูกค้ารายงาน โจมตี อยู่ใกล้กับตำแหน่งของ ส่วน ที่ลูกค้ารายงานโจมตีบนเซิร์ฟเวอร์
ไม่มีสิ่งกีดขวางคงที่ระหว่างตำแหน่งที่ลูกค้ารายงานยิงและตำแหน่งที่ลูกค้ารายงานยิงการตรวจสอบนี้ช่วยให้แน่ใจว่าไม่มีไคลเอนต์พยายามยิงผ่านผนังโปรดทราบว่านี่ควรตรวจสอบเพียงรูปทรงคงที่เพื่อหลีกเลี่ยงการปฏิเสธการยิงที่ถูกต้องเนื่องจากความล่าช้า นอกจากนี้ คุณอาจต้องการที่จะดำเนินการตรวจสอบด้านเซิร์ฟเวอร์ต่อไปนี้:
ติดตามเมื่อผู้เล่นยิงอาวุธล่าสุดและยืนยันเพื่อให้แน่ใจว่าพวกเขาไม่ยิงเร็วเกินไป
ติดตามปริมาณกระสุนของผู้เล่นแต่ละคนบนเซิร์ฟเวอร์และยืนยันว่าผู้ยิงมีกระสุนเพียงพอที่จะดำเนินการโจมตีอาวุธ
หากคุณได้ใช้ ทีม หรือระบบการต่อสู้แบบ "ผู้เล่นกับบอท" ยืนยันว่าตัวละครที่โจมตีเป็นศัตรูไม่ใช่เพื่อนร่วมทีม
ยืนยันว่าผู้เล่นที่โดนมีชีวิตอยู่
เก็บอาวุธและสถานะผู้เล่นบนเซิร์ฟเวอร์และยืนยันว่าผู้เล่นยิงไม่ถูกบล็อกโดยการดำเนินการปัจจุบันเช่นการรีโหลดหรือสถานะเช่นการวิ่ง
การจัดการคลังข้อมูล
ในประสบการณ์ที่ใช้ DataStoreService เพื่อบันทึกข้อมูลผู้เล่น ผู้โจมตีอาจใช้ประโยชน์จากข้อมูลที่ไม่ถูกต้อง และวิธีที่ลึกลับมากขึ้นเพื่อป้องกันไม่ให้ DataStore บันทึกได้อย่างถูกต้องสิ่งนี้สามารถถูกใช้งานอย่างผิดปกติในประสบการณ์การซื้อขายไอเทม ตลาด คลังไอเท็ม
ตรวจสอบให้แน่ใจว่าการดำเนินการใดๆ ที่ดำเนินการผ่าน RemoteEvent หรือ RemoteFunction กำลังติดตาม:
- DataStores มี ข้อจํากัดข้อมูลสตริงความยาวแบบสุ่มควรตรวจสอบและ/หรือจำกัดเพื่อหลีกเลี่ยงสิ่งนี้โดยการรับประกันว่าไม่สามารถเพิ่มกุญแจสุ่มไม่จำกัดไปยังตารางโดยไคลเอนต์ได้
- ดัชนีตารางไม่สามารถเป็น NaN หรือ nil ได้ ให้ทำซ้ำกับทุกตารางที่ส่งโดยไคลเอนต์และตรวจสอบให้แน่ใจว่าดัชนีทั้งหมดถูกต้อง
- DataStores สามารถยอมรับตัวอักษร UTF-8 ที่ถูกต้องได้เท่านั้น ดังนั้นคุณควรทำความสะอาดข้อความทั้งหมดที่ให้โดยไคลเอนต์ผ่าน utf8.len() เพื่อให้แน่ใจว่าถูกต้อง utf8.len() จะคืนความยาวของสตริงโดยปฏิบัติตัวอักษรยูนิโค้ดเป็นตัวอักษรเดียว; หากพบตัวอักษร UTF-8 ที่ไม่ถูกต้องจะคืน nil และตำแหน่งของตัวอักษรที่ไม่ถูกต้องโปรดทราบว่าสตริง UTF-8 ที่ไม่ถูกต้องอาจปรากฏในตารางเป็นคีย์และค่าได้เช่นกัน
การจำกัดการใช้งานระยะไกล
หากไคลเอนต์สามารถทําให้เซิร์ฟเวอร์ของคุณสําเร็จการดําเนินการที่มีราคาแพงทางคณิตศาสตร์หรือเข้าถึงบริการจํากัดอัตราเช่น DataStoreService ผ่านทาง RemoteEvent ก็เป็นสิ่งสําคัญที่คุณต้องใช้การจํากัดอัตรา **** เพื่อให้แน่ใจว่าการดําเนินการจะไม่ถูกเรียกบ่อยเกินไปการจํากัดอัตราสามารถดําเนินการได้โดยติดตามเมื่อไคลเอนต์เรียกกิจกรรมระยะไกลครั้งล่าสุดและปฏิเสธคําขอต่อไปหากเรียกเร็วเกินไป
การตรวจสอบการเคลื่อนที่
สำหรับประสบการณ์การแข่งขันคุณอาจต้องการตรวจสอบการเคลื่อนไหวตัวละครผู้เล่นบนเซิร์ฟเวอร์เพื่อให้แน่ใจว่าพวกเขาไม่ได้เทเลพอร์ตไปรอบๆ แผนที่หรือเคลื่อนที่เร็วกว่าที่ยอมรับได้
ในช่วงเวลา 1 วินาทีตรวจสอบตำแหน่งใหม่ของตัวละครกับตำแหน่งที่บันทึกไว้ก่อนหน้านี้
เปรียบเทียบความแตกต่างระยะทางจริงกับความแตกต่างระยะทางที่ยอมรับได้และดำเนินการต่อไปตามลำดับดังนี้:
- สำหรับเดลต้าที่ยอมรับได้ให้เก็บตำแหน่งใหม่ของตัวละครไว้เพื่อเตรียมพร้อมสำหรับการตรวจสอบครั้งถัดไปที่เพิ่มขึ้น
- สำหรับเดลต้าที่ไม่คาดหรือไม่ทนได้ (การโจมตีความเร็ว/การเทเลพอร์ตที่อาจเกิดขึ้น):
- เพิ่มมูลค่า "จํานวนคดี" แยกต่างหากสําหรับผู้เล่น เมื่อเทียบกับการลงโทษพวกเขาสําหรับ "ความผิดพลาดที่เป็นเท็จ" ที่เกิดจากความล่าช้าของเซิร์ฟเวอร์อย่างมากหรือปัจจัยอื่น ๆ ที่ไม่ใช่การโจมตี
- หากเกิดการละเมิดจํานวนมากในช่วงระยะเวลา 30-60 วินาที Kick() ผู้เล่นจากประสบการณ์ทั้งหมด; มิฉะนั้นรีเซ็ตจํานวนการละเมิดโปรดทราบว่าเมื่อเตะผู้เล่นที่โกง การบันทึกเหตุการณ์เป็นการปฏิบัติที่ดีที่สุดเพื่อให้คุณสามารถติดตามได้ว่ามีผู้เล่นกี่คนที่ได้รับผลกระทบ