Seguridad: escribe recursos sin agujeros · Lección 2/3 · 9 min
Blindaje server-side y anti-spam
Tus propios recursos también deben ser seguros: valida todo en el servidor y limita el spam de eventos.
No basta con no meter backdoors ajenos; tus scripts tienen que ser a prueba de tramposos. Dos pilares: validar SIEMPRE en el servidor, y limitar cuántas veces se puede disparar un evento.
Checklist de validación (recordatorio)
- El cliente solo PIDE; el servidor DECIDE y EJECUTA (dinero, items, permisos).
- Valida tipo, rango y propiedad de cada argumento que llega del cliente.
- Comprueba distancia: ¿el jugador está cerca del cajero/tienda que dice usar?
- Nunca mandes precios, recompensas ni IDs sensibles desde el cliente.
Anti-spam de eventos
local ultimo = {} -- [src] = timestamp
RegisterNetEvent('tienda:server:comprar')
AddEventHandler('tienda:server:comprar', function(...)
local src = source
local ahora = GetGameTimer()
if ultimo[src] and (ahora - ultimo[src]) < 500 then return end -- máx 1 cada 0.5s
ultimo[src] = ahora
-- … lógica validada …
end)Rate-limit por jugador
Un tramposo puede disparar tu evento 1000 veces por segundo. El rate-limit por src corta esos abusos (duplicar items, farmear dinero) de raíz.
Practica lo aprendido
0/3En un sistema seguro, ¿quién DECIDE y EJECUTA el movimiento de dinero o items?
Pista
El cliente está en la máquina del jugador; un tramposo lo controla.
Completa el anti-spam por jugador: máximo un disparo por segundo.
local ultimo = {}RegisterNetEvent('mercado:server:vender')AddEventHandler('mercado:server:vender', function(itemId, cantidad) local src = source local ahora = GetGameTimer() if ultimo[src] and (ahora - ultimo[src]) < then return end ultimo[] = ahora -- … lógica validada …end)Pista
Un segundo en milisegundos; y se guarda el tiempo por jugador (source).
El cliente manda el precio (precioCliente) y el servidor se fía. Blíndalo: ignora ese dato, usa Config.Coste y valida la cantidad con tonumber.
Este código tiene un fallo:
RegisterNetEvent('tienda:server:comprar')AddEventHandler('tienda:server:comprar', function(precioCliente, cantidad) local src = source local xPlayer = ESX.GetPlayerFromId(src) local total = precioCliente * cantidad xPlayer.removeMoney(total)end)Reescríbelo corregido:
Pista
total = Config.Coste * cantidad, con cantidad = tonumber(cantidad) y comprobada > 0.
Reto: prográmalo tú
Añade un anti-spam a un evento de 'vender' para que un jugador no pueda dispararlo más de una vez por segundo.
Escríbelo tú en tu editor (VS Code) y pruébalo en tu servidor. Aquí se aprende haciéndolo, no copiando.
Ver pista
Tabla ultimo[src] con GetGameTimer(); si la diferencia < 1000 ms, return.
Escribe aquí tu solución:
