Depurar y asegurar tus recursos · Lección 3/3 · 9 min

Blindaje server-side, anti-spam y checklist

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.

Anti-spam de eventos

lua
local ultimo = {} -- [src] = timestamp

RegisterNetEvent('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 con QBCore.Functions.GetPlayer …
end)

Rate-limit por jugador

Checklist antes de publicar lo tuyo

  • Toda la lógica sensible (dinero, items, permisos) se decide y ejecuta en el servidor.
  • Valida tipo, rango y propiedad de cada argumento del cliente.
  • Consultas parametrizadas (?), nada de concatenar SQL.
  • Sin secretos hardcodeados: van en server.cfg / convars vía GetConvar.
  • Anti-spam en los eventos que dan dinero/items.
  • config.lua para lo configurable; sin valores mágicos sueltos.

Antes de INSTALAR algo de fuera: pásalo por la Auditoría de seguridad, busca os.execute / load( / webhooks, desconfía de lo muy ofuscado y pruébalo primero en un servidor de test.

Practica lo aprendido

0/3
Test

Un jugador manda al servidor el evento 'tienda:server:vender' con item y precio. ¿Por qué NO debes usar el precio que llega?

Pista

¿Quién controla lo que se envía desde el cliente? El jugador. Por eso no te fías.

Rellena los huecos

Completa el guard que comprueba que el jugador existe antes de tocar nada en el servidor (QBCore).

1RegisterNetEvent('tienda:server:comprar', function(item)
2 local src = source
3 local Player = QBCore.Functions.GetPlayer(src)
4 if not then return end
5 -- … lógica validada en el servidor …
6end)
Pista

Si GetPlayer no encuentra al jugador devuelve nil; corta ahí mismo con return.

Corrige el error

Este evento confía en el precio que manda el cliente y no comprueba al jugador. Arréglalo: añade el guard del Player y lee el precio de Config en el servidor, no del cliente.

Este código tiene un fallo:

1RegisterNetEvent('tienda:server:vender')
2AddEventHandler('tienda:server:vender', function(item, precio)
3 local Player = QBCore.Functions.GetPlayer(source)
4 Player.Functions.AddMoney('cash', precio)
5end)

Reescríbelo corregido:

Pista

Quita 'precio' de los argumentos del handler, añade 'if not Player then return end' y léelo con local precio = Config.Precios[item] dentro del servidor.

Reto: prográmalo tú

Añade un anti-spam a un evento 'mercado:server: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:

¿Qué tal esta lección?