Hola Rubistas,

Hoy vengo a contaros mis aventuras con un nuevo amigo que me he echado, un SpamBot ruso. No paraba de mandarme comentarios sobre medicamentos, webs y otras cosas raras en ingles. Esta claro que lo que iba buscando es hacerse seo y a razón de un mensaje/minuto, lo cual saturo la web que atacaba, su base de datos, ancho de banda y en fin... creo que fue menos productivo que eficaz por su bombardeo constante.

Así que en este punto la pregunta fue... ¿y como paro esto? Desgraciadamente no podemos evitar que el SpamBot pare de enviarnos peticiones y en este caso no era posible tocar el servidor para evitar peticiones de ciertas Ip (también porque el SpamBot cambiaba de Ip constantemente) así que tocaba procesar cada petición un poquito y desechar las que no sean de personas reales.

La primera medida (El captcha)

Vigilar que los comentarios proceden de una persona real, no de una máquina. Esto hoy día se consigue por medio de captchas. Yo ya tenia un captcha activo (recaptcha de Google) por se lo saltaba impunemente y con descaro ante mis ojos. Decidí cambiarlo por otro, fue Humanizer quien consiguio que no entraran más comentarios porque a cada petición respondía de esta guisa el robot: "humanizer_answer"=>"84CjpD", "humanizer_question_id"=>"1"
Como se aprecia a este ritmo no iba a responder una sola pregunta de humanizer bien, ya que las preguntas por defecto de esta gema son tipo: ¿Después del lunes, viene el ...?

La segunda medida (Controlar el número de peticiones y no llegar ni a procesarlas)

Para controlar las peticiones es lógico pensar que nadie va a mandar un comentario/minuto o incluso más por minuto. Para controlar esta situación de exceso de peticiones para toda la web y para los comentarios existe la gema Rack-Attack. Esta gema vigila las peticiones por ip, a un lugar concreto o a cualquier cosa, leeros su documentación y os dejo aquí como configure config/initializers/rack-attack.rb:

class Rack::Attack
  # Acelerar grandes volúmenes de solicitudes por dirección IP
  throttle('req/ip', limit: 20, period: 20.seconds) do |req|
    @ip=req.ip
    req.ip unless req.path.starts_with?('/assets')
  end

  # Acelera intentos de inicio de sesión por dirección IP
  throttle('logins/ip', limit: 5, period: 20.seconds) do |req|
    @ip=req.ip
    if req.path == '/auth/login' && req.post?
      req.ip
    end
  end

  # Acelera intentos de inicio de sesión por dirección de correo electrónico
  throttle("logins/email", limit: 5, period: 20.seconds) do |req|
    if req.path == '/auth/login' && req.post?
      req.params['email'].presence
    end
  end

  # Acelera intentos de comentarios
  throttle("logins/email", limit: 2, period: 20.seconds) do |req|
    if (req.path.include? '/comments') && req.post?
      req.params['comment'].presence
    end
  end

  # Respuesta al exceso de peticiones
  self.throttled_response = lambda do |env|
    [ 429, {}, ["Uff dejarme respirar!... demasiadas peticiones amigo"]]
  end
end

Tercera medida (captcha negativo o poner un señuelo al robot)

Ya no nos entraran comentarios falsos por Humanizer, se reducirá mucho el numero de peticiones a procesar por Rack-Attack pero alguna si que llegará a ser procesada así que hay que minimizar el tiempo de cpu que llevara solucionarla. Engañaremos en el formulario al robot, vemos que es muy espabilado y competa todos nuestros campos asi que le colocaremos un señuelo. He creado un campo en el formulario (vista) que no me vale para nada pero que comprobaré si es escrito ya que el Css lo esconderá y un humano nunca lo vería: <input type="text" name="name" class="hidden">

Al ser procesado el formulario por la petición Post en el controlador, compruebo como viene ese campo suelto name, si viene relleno devuelvo: render text: '', status: '404' y reseteo la sesión. En caso contrario, proceso la petición y veremos si cumple como para grabarla.

 

Gracias a este truquito ahora casi ni se nota al robot (que por cierto ha dejado de molestarme), creo que se ha cansado de que le suelten status: '404' y status: '429'. Los status: '200' los venden caros ahora :P
Espero que os sirva mi aventura y os arregle el día. Un saludo a todos!

 


 

Volver