Client and server in depth · Lesson 1/4 · 10 min

Secure events: don't trust the client

Any player can trigger your network events with whatever data they want. Learn to validate them so they don't take over your server.

A RegisterNetEvent is an open door: any player can trigger it from their client with whatever arguments they please. If you don't validate, you're handing out cheats.

The typical mistake (vulnerable)

lua
-- ❌ BAD: trusts the amount sent by the client
RegisterNetEvent('tienda:server:vender')
AddEventHandler('tienda:server:vender', function(cantidad, precio)
  local xPlayer = ESX.GetPlayerFromId(source)
  xPlayer.addMoney(cantidad * precio) -- the client sends amount AND price = infinite money
end)

Vulnerable

Here a cheater sends cantidad=99999 and precio=99999 and gets rich. The price and the logic must NEVER come from the client.

The secure version

lua
RegisterNetEvent('tienda:server:vender')
AddEventHandler('tienda:server:vender', function(itemName, cantidad)
  local src = source
  local xPlayer = ESX.GetPlayerFromId(src)
  if not xPlayer then return end

  -- 1) validate types and ranges
  cantidad = tonumber(cantidad)
  if not cantidad or cantidad < 1 or cantidad > 100 then return end

  -- 2) the PRICE is decided by the server, not the client
  local precio = Config.Precios[itemName]
  if not precio then return end

  -- 3) check that the player ACTUALLY has what they claim to sell
  local item = xPlayer.getInventoryItem(itemName)
  if not item or item.count < cantidad then return end

  xPlayer.removeInventoryItem(itemName, cantidad)
  xPlayer.addMoney(precio * cantidad)
end)

Full validation

  • Validate the type and range of every argument (tonumber, limits).
  • Prices, rewards and logic come from Config or the DB on the server, never from the client.
  • Check that the player has/can do what they ask (item, money, job, distance).

Practice what you learned

0/3
Test

Un evento de servidor hace: xPlayer.addMoney(cantidad * precio), donde cantidad y precio llegan como argumentos del cliente. ¿Por qué es un agujero?

Pista

¿Quién controla los valores que llegan en los argumentos?

Rellena los huecos

Completa la validación segura: convierte la cantidad a número, comprueba el rango y saca el precio del servidor.

1cantidad = (cantidad)
2if not cantidad or cantidad < 1 or cantidad > 100 then return end
3local precio = [itemName]
4if not precio then return end
Pista

Primero valida el tipo numérico; el precio sale de tu tabla de Config.

Corrige el error

Blinda este evento vulnerable: el precio NO puede venir del cliente, debe salir de Config, y valida la cantidad con tonumber.

Este código tiene un fallo:

1RegisterNetEvent('tienda:server:vender')
2AddEventHandler('tienda:server:vender', function(cantidad, precio)
3 local xPlayer = ESX.GetPlayerFromId(source)
4 xPlayer.addMoney(cantidad * precio)
5end)

Reescríbelo corregido:

Pista

Quita 'precio' de los argumentos y léelo de Config.Precios[itemName].

Challenge: code it yourself

Take an event that gives an item to the player and harden it: validate the amount (1-10) and that the item exists in a list of Config-allowed items.

Write it yourself in your editor (VS Code) and test it on your server. You learn here by doing it, not by copying.

See hint

tonumber + range check + Config.ItemsPermitidos[item] before addInventoryItem.

Escribe aquí tu solución:

How was this lesson?