Taktik keamanan dan mitigasi penipuan

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

Roblox menggunakan sistem fisika terdistribusi yang memiliki kustodian klien atas simulasi fisik objek dalam kendali mereka, biasanya karakter pemain dan objek yang tidak diikat dekat karakter itu.Selain itu, melalui penggunaan perangkat lunak pihak ketiga, penyalahguna dapat menjalankan kode Luau arbitrer di klien untuk memanipulasi model data klien dan mendekompilasi dan melihat kode yang dijalankan di atasnya.

Secara kolektif, ini berarti bahwa seorang pengeksploit terampil dapat secara potensial mengeksekusi kode untuk menipu dalam gameAnda, termasuk:

  • Teleport karakter mereka sendiri di sekitar tempat.
  • Menembak tidak aman RemoteEvents atau memanggil RemoteFunctions , seperti untuk memberikan hadiah kepada diri sendiri tanpa mendapatkannya.
  • Menyesuaikan karakter mereka WalkSpeed sehingga bergerak sangat cepat.

Sementara Anda dapat menerapkan pertahanan desain terbatas untuk menangkap serangan umum , sangat disarankan agar Anda menerapkan taktik mitigasi sisi server yang lebih dapat diandalkan , karena server adalah otoritas terakhir untuk pengalaman eksekusi apa pun.

Taktik desain defensif

Keputusan desain dasar dapat dijadikan sebagai "langkah pertama" tindakan keamanan untuk mencegah exploit.Sebagai contoh, dalam permainan penembak di mana pemain mendapat poin untuk membunuh pemain lain, seorang peretas dapat membuat sekelompok bot yang berteleportasi ke tempat yang sama sehingga mereka dapat dengan cepat dibunuh untuk poin.Mengingat exploit potensial ini, pertimbangkan dua pendekatan dan hasilnya yang dapat diprediksi:

PendekatanHasil yang dapat diprediksi
Kejar bot dengan menulis kode yang mencoba mendeteksi mereka.
Kurangi atau hapus sepenuhnya keuntungan titik untuk membunuh pemain yang baru lahir.

Sementara desain pertahanan jelas bukan solusi sempurna atau lengkap, ia dapat berkontribusi pada pendekatan keamanan yang lebih luas, bersama dengan mitigasi sisi server.

Peredaman sisi server

Sebanyak mungkin, server harus melemparkan putusan terakhir tentang apa yang "benar" dan apa status saat ini dunia.Klien dapat, tentu saja, meminta server untuk membuat perubahan atau melakukan action, tetapi server harus memverifikasi dan menyetujui masing-masing perubahan/tindakan ini sebelum hasilnya direplikasi ke pemain lain.

Dengan pengecualian operasi fisika tertentu, perubahan pada model data di klien tidak dipindahkan ke server, jadi jalur serangan utama sering melalui peristiwa jaringan yang Anda deklarasikan dengan RemoteEvents dan RemoteFunctions .Ingat bahwa seorang peretas yang menjalankan kode sendiri di klien Anda dapat memanggil ini dengan data apa pun yang mereka inginkan.

Validasi jenis runtime jarak jauh

Satu jalur serangan adalah untuk seorang penyerang untuk memanggil RemoteEvents dan RemoteFunctions dengan argumen ketikyang salah.Dalam beberapa skenario, ini dapat menyebabkan kode di server mendengarkan remote ini untuk kesalahan dengan cara yang menguntungkan bagi penyerang.

Saat menggunakan acara/fungsi remote, Anda dapat mencegah jenis serangan ini dengan memverifikasi jenis argumen yang dilewati di server.Modul "t" , tersedia di sini , berguna untuk memeriksa jenis dengan cara ini.Sebagai contoh, mengasumsikan kode modul ada sebagai ModuleScript bernama t di dalam ReplicatedStorage :

Skrip Lokal di StarterPlayerScripts

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
-- Lewati warna dan posisi bagian saat memanggil fungsi
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(200, 0, 50), Vector3.new(0, 25, 0))
if newPart then
print("The server created the requested part:", newPart)
elseif newPart == false then
print("The server denied the request. No part was created.")
end
Skrip di ServerScriptService

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
local t = require(ReplicatedStorage:WaitForChild("t"))
-- Buat validator jenis sebelumnya untuk menghindari biaya tambahan yang tidak perlu
local createPartTypeValidator = t.tuple(t.instanceIsA("Player"), t.Color3, t.Vector3)
-- Buat bagian baru dengan properti yang disampaikan
local function createPart(player, partColor, partPosition)
-- Periksa jenis argumen yang dilewati
if not createPartTypeValidator(player, partColor, partPosition) then
-- Dengan diam return "false" jika pemeriksaan jenis gagal di sini
-- Mengangkat kesalahan tanpa jeda dapat disalahgunakan untuk menjatuhkan server
-- Berikan umpan balik klien sebagai gantinya!
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
-- Ikatkan "createPart()" ke panggil balik fungsi remote
remoteFunction.OnServerInvoke = createPart

Validasi data

Serangan lain yang mungkin diluncurkan oleh penyerang adalah mengirim jenis yang valid secara teknis tetapi membuatnya sangat besar, panjang, atau lainnya terbentuk buruk.Sebagai contoh, jika server harus melakukan operasi mahal pada string yang menyesuaikan panjang, seorang peretas dapat mengirimkan string yang sangat besar atau rusak untuk menjatuhkan server.

Demikian pula, kedua inf dan NaN akan type() sebagai number , tetapi keduanya dapat menyebabkan masalah besar jika seorang peretas mengirimkannya dan mereka tidak ditangani dengan benar melalui fungsi seperti mengikuti:


local function isNaN(n: number): boolean
-- NaN tidak pernah sama dengan dirinya sendiri
return n ~= n
end
local function isInf(n: number): boolean
-- Angka bisa menjadi -inf atau inf
return math.abs(n) == math.huge
end

Serangan umum lain yang bisa digunakan oleh penyerang melibatkan mengirim tables di tempat Instance .Pemuatan kompleks dapat meniru apa yang akan menjadi referensi objek biasa.

Sebagai contoh, disediakan dengan sistem toko dalam pengalaman di mana data item seperti harga disimpan di objek , seorang peretas dapat menghindari semua pemeriksaan lain dengan melakukan hal mengikuti:

Skrip Lokal di 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, -- Nilai negatif juga bisa digunakan, menghasilkan memberikan mata uang daripada mengambilnya!
},
}
-- Kirimkan payload berbahaya ke server (ini akan ditolak)
print(buyItemEvent:InvokeServer(payload)) -- Output "false Item tidak valid disediakan"
-- Kirim item nyata ke server (ini akan melalui!)
print(buyItemEvent:InvokeServer(itemDatafolder["Real Blade"])) -- Outputs "true" and remaining currency if purchase succeeds
Skrip di ServerScriptService

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local function buyItem(player, item)
-- Periksa apakah item yang dilewati tidak dispoof dan ada di folder ItemData
if typeof(item) ~= "Instance" or not item:IsDescendantOf(itemDataFolder) then
return false, "Invalid item provided"
end
-- Server kemudian dapat melanjutkan untuk memproses pembelian berdasarkan aliran contoh di bawah ini
end
-- Ikatkan "buyItem()" ke panggil balik fungsi remote
buyItemEvent.OnServerInvoke = buyItem

Validasi nilai

Selain memverifikasi jenis dan data , Anda harus memverifikasi nilai yang dikirim melalui RemoteEvents dan RemoteFunctions , memastikan mereka valid dan logis dalam konteks yang diminta.Dua contoh umum adalah toko dalam pengalaman dan sistem penargetan senjata .

Toko belanjapengalaman

Pertimbangkan sistem toko dalam pengalaman dengan antarmuka pengguna, misalnya menu pemilihan produk dengan tombol "Beli".Ketika tombol ditekan, Anda dapat memanggil RemoteFunction antara klien dan server untuk meminta pembelian.Namun, penting bahwa server , manajer paling dapat diandalkan dari pengalaman, mengkonfirmasi bahwa pengguna memiliki cukup uang untuk membeli item.

Example purchase flow from client to server through a RemoteEvent
Contoh aliran pembelian dari klien ke server melalui sebuah RemoteFunction

Peng targetan senjata

Skenario pertempuran memerlukan perhatian khusus untuk memverifikasi nilai, terutama melalui penargetan dan validasi pukulan.

Bayangkan permainan di mana pemain dapat menembakkan balok laser ke pemain lain.Daripada klien memberi tahu server siapa untuk merusak, sebaiknya memberi tahu server posisi asal tembakan dan bagian/posisi yang menurutnya telah terkena.Server kemudian dapat memverifikasi mengikuti:

  • Posisi yang dilaporkan klien menembak dari dekat karakter pemain di server.Perhatikan bahwa server dan klien akan berbeda sedikit karena kelambatan, jadi toleransi tambahan harus diterapkan.

  • Posisi yang klien laporkan memukul adalah cukup dekat dengan posisi bagian yang klien laporkan memukul, di server.

  • Tidak ada penghalang statis di antara posisi klien melaporkan menembak dan posisi klien melaporkan menembak.Pemeriksaan ini memastikan klien tidak mencoba menembak melalui dinding.Perhatikan bahwa ini hanya harus memeriksa geometri statis untuk menghindari penolakan tembakan valid karena kelambatan. Selainnya , Anda mungkin ingin menerapkan validasi sisi server lebih lanjut sebagai berikut:

  • Lacak kapan pemain terakhir menembak senjata mereka dan validasi untuk memastikan mereka tidak menembak terlalu cepat.

  • Lacak jumlah amunisi setiap pemain di server dan konfirmasikan bahwa pemain penembak memiliki cukup amunisi untuk mengeksekusi serangan senjata.

  • Jika Anda telah menerapkan tim atau sistem pertempuran "pemain melawan bot", konfirmasikan bahwa karakter pukul adalah musuh, bukan rekan tim.

  • Konfirmasikan bahwa pemain yang terkena masih hidup.

  • Simpan senjata dan status pemain di server dan konfirmasikan bahwa pemain penembak tidak diblokir oleh tindakan saat ini seperti isi ulang atau status seperti berlari.

Manipulasi penyimpan data

Dalam pengalaman yang menggunakan DataStoreService untuk menyimpan data pemain, penyalahguna dapat memanfaatkan data tidak valid , dan metode yang lebih misterius, untuk mencegah DataStore disimpan dengan benar.Ini dapat terutama disalahgunakan dalam pengalaman perdagangan barang, pasar, dan sistem serupa di mana barang atau mata uang meninggalkan inventaris pemain.

Pastikan bahwa setiap tindakan yang dilakukan melalui RemoteEvent atau RemoteFunction yang mempengaruhi data pemain dengan input klien disanitasi berdasarkan hal mengikuti:

  • Instance nilai tidak dapat diserialkan ke dalam DataStore dan akan gagal. Gunakan validasi jenis untuk mencegah ini.
  • DataStores memiliki batas data .String panjang acak harus diperiksa dan/atau dibatasi untuk menghindari ini, sambil memastikan kunci acak tanpa batas tidak dapat ditambahkan ke tabel oleh klien.
  • Indeks tabel tidak boleh menjadi NaN atau nil. Bergulir di atas semua tabel yang diteruskan oleh klien dan memeriksa semua indeks valid.
  • DataStores hanya dapat menerima karakter UTF-8 yang valid, jadi Anda harus membersihkan semua string yang disediakan oleh klien melalui utf8.len() untuk memastikan mereka valid. utf8.len() akan mengembalikan panjang string, memperlakukan karakter Unicode sebagai satu karakter; jika karakter UTF-8 yang tidak valid ditemukan, itu akan mengembalikan nil dan posisi karakter yang tidak valid.Perhatikan bahwa string UTF-8 tidak valid juga dapat hadir di tabel sebagai kunci dan nilai.

Pengurangan jarak jauh

Jika klien dapat membuat server Anda menyelesaikan operasi yang mahal secara komputasional, atau mengakses layanan terbatas tingkat seperti melalui , penting untuk Anda menerapkan batasan tingkat untuk memastikan operasi tidak dipanggil terlalu sering.Pembatasan tingkat dapat dilaksanakan dengan melacak kapan klien terakhir memanggil acara remote dan menolak permintaan berikutnya jika dipanggil terlalu cepat.

Validasi gerakan

Untuk pengalaman kompetitif, Anda mungkin ingin memverifikasi gerakan karakter pemain di server untuk memastikan mereka tidak berteleportasi di sekitar peta atau bergerak lebih cepat dari yang dapat diterima.

  1. Dalam peningkatan 1 detik, periksa lokasi baru karakter terhadap lokasi yang disimpan sebelumnya.

    Image showing moving character's position on a straight path in increments of 1 second
  2. Tentukan perubahan maksimum "terima" pada jarak berdasarkan karakter WalkSpeed (stud per detik), dikalikan dengan ~1.4 untuk memungkinkan sedikit kelonggaran terhadap kelambatan server.Sebagai contoh, pada default WalkSpeed dari 16, delta yang dapat diterima adalah ~22.

    Image showing tolerable change in distance based on character's walk speed
  3. Bandingkan delta jarak aktual melawan delta yang dapat ditoleransi dan lanjutkan sebagai berikut:

    • Untuk delta yang dapat ditoleransi, simpan lokasi baru karakter untuk persiapan pemeriksaan berikutnya yang periksa.
    • Untuk delta tak terduga atau tidak dapat ditoleransi (eksploit kecepatan/teleportasi potensial):
      1. Meningkatkan nilai "jumlah pelanggaran" terpisah untuk pemain, dibandingkan dengan menghukum mereka karena "positif palsu" yang disebabkan oleh kelambatan server ekstrem atau faktor non-eksploit lainnya.
      2. Jika terjadi banyak pelanggaran besar dalam jangka waktu 30-60 detik, Kick() pemain dari pengalaman sepenuhnya; jika tidak, atur ulang hitungan "jumlah pelanggaran."Perhatikan bahwa ketika mengusir pemain karena curang, praktik terbaik adalah merekam peristiwa tersebut sehingga Anda dapat melacak berapa banyak pemain yang terpengaruh.