2012-07-16 13 views
9

Proporciono un servicio web para mis clientes que le permite agregar un registro a la base de datos de producción.Evitar llamadas a un servicio web demasiadas veces

Tuve un incidente últimamente, en el que el programador de mi cliente llamó al servicio en un bucle, repetido para llamar a mi servicio miles de veces.

Mi pregunta es cuál sería la mejor manera de prevenir tal cosa.

Pensé de algunas maneras: 1. En la entrada del servicio, puedo actualizar los contadores para cada cliente que llama al servicio, pero eso parece demasiado clumbsy. 2.Verifique la IP del cliente que llamó a este servicio, y levante una bandera cada vez que llame al servicio, y luego reinicie la bandera cada hora.

Estoy seguro de que hay mejores formas y agradecería cualquier sugerencia.

Gracias, David

+0

Otra idea, Actualización de la sesión de este usuario: –

+0

supongo que tiene algún tipo de "a granel" "agregar método? – Phil

+0

Sí, hay ... –

Respuesta

3

La forma es la de almacenar en la sesión de un contador y utilizar el contador para evitar demasiadas llamadas por hora.

Pero si su usuario puede tratar de evitar eso y enviar una cookie diferente cada vez *, entonces necesita crear una tabla personalizada que actúe como la sesión pero conecte al usuario con la ip y no con la cookie.

Una más aquí es que si bloquea basic en la ip, puede bloquear una empresa completa que se salga de un proxy. Por lo tanto, la forma correcta final, pero más complicada es tener tanto en la interfaz de usuario como en la cookie conectados con el usuario y saber si el navegador permite cookies o no. Si no, entonces bloquea con el ip. La parte difícil aquí es saber sobre la cookie. Bueno, en cada llamada puede obligarlo a enviar una cookie válida que esté conectada con una sesión existente. De lo contrario, el navegador no tenía cookies.

[*] Las cookies están conectadas con la sesión.
[*] Al crear una nueva tabla para mantener los contadores desconectados de la sesión, también puede evitar el bloqueo de la sesión.

En el pasado he utilizado un código que se usa para DosAttack, pero ninguno de ellos funciona bien cuando tiene muchos pools y aplicaciones difíciles, así que ahora uso una tabla personalizada como la describo. Estos son los dos código que tengo prueba y el uso

Dos attacks in your web app

Block Dos attacks easily on asp.net

¿Cómo encontrar los clics por segundo guardados en una tabla. Aquí está la parte de mi SQL que calcula los clics por segundo. Uno de los trucos es que sigo agregando clics y hago el cálculo del promedio si tengo 6 o más segundos desde la última verificación. Este es un código snipped del cálculo como una idea

set @cDos_TotalCalls = @cDos_TotalCalls + @NewCallsCounter 

SET @cMilSecDif = ABS(DATEDIFF(millisecond, @FirstDate, @UtpNow)) 

-- I left 6sec diferent to make the calculation 
IF @cMilSecDif > 6000 
    SET @cClickPerSeconds = (@cDos_TotalCalls * 1000/@cMilSecDif) 
else 
    SET @cClickPerSeconds = 0 

IF @cMilSecDif > 30000 
    UPDATE ATMP_LiveUserInfo SET cDos_TotalCalls = @NewCallsCounter, cDos_TotalCallsChecksOn = @UtpNow WHERE [email protected]   
ELSE IF @cMilSecDif > 16000 
    UPDATE ATMP_LiveUserInfo SET cDos_TotalCalls = (cDos_TotalCalls/2), 
    cDos_TotalCallsChecksOn = DATEADD(millisecond, @cMilSecDif/2, cDos_TotalCallsChecksOn) 
     WHERE [email protected] 
+0

Gracias por su respuesta, digamos que actualizo la sesión: Session ["ServiceInvoked"] = true; y pregunte si lo preguntamos al comienzo de la sesión: if ((bool) Session ["ServiceInvoked"]) ... Evitaré la llamada. PERO, ¿cómo lo reiniciaría después, digamos, una hora? –

+0

Si insertaré la fecha y hora, puedo trabajar, ya que puedo verificar la fecha y hora de la sesión Subscribir el DateTime.Now y permitir que se invoque el servicio ... –

+0

@DavidRasuli Utiliza un campo DateTime de la última actualización junto con el contador y usted realiza un cálculo promedio; verá, por ejemplo, en el último DateTime que la última pregunta fue antes de 1 segundo y todo listo tiene 10 llamadas. En otras palabras, lo cortas para las últimas llamadas, no para la última. – Aristos

3

primero que hay que echar un vistazo a las aspectos legales de su situación: si el contrato con su cliente le permiten restringir el acceso del cliente?

Esta pregunta está fuera del alcance de SO, pero debe encontrar una manera de responderla. Porque si estás legalmente obligado a procesar todas las solicitudes, entonces no hay forma de evitarlo.Además, el análisis legal de su situación puede incluir algunas limitaciones, de modo que puede restringir el acceso. Eso, a su vez, tendrá un impacto en su solución.

Dejando a un lado todas estas cuestiones, y simplemente centrándose en los aspectos técnicos , ¿utiliza algún tipo de autenticación de usuario? (En caso negativo, ¿por qué no?) Si lo hace, puede implementar cualquier esquema que decida usar por usuario, que creo que sería la solución más limpia (no necesita confiar en las direcciones IP, que es una de alguna manera fea solución).

Una vez que tenga su forma de identificar a un solo usuario, puede implementar varias restricciones. Los puño que vienen a la mente son los siguientes:

  1. procesamiento síncrono
    Sólo iniciar el procesamiento de una solicitud después de que todas las solicitudes anteriores han sido procesados. Esto incluso puede implementarse con nada más que una declaración lock en su método de procesamiento principal. Si opta por este tipo de enfoque,
  2. Demora de tiempo entre las solicitudes de procesamiento
    Requiere que después de una llamada de proceso, se pase un tiempo específico antes de que se permita la próxima llamada. La solución más fácil es almacenar una marca de tiempo LastProcessed en la sesión del usuario. Si opta por este enfoque, debe comenzar a pensar en cómo responder cuando ingrese una nueva solicitud antes de permitir su procesamiento: ¿envía un mensaje de error a la persona que llama? Creo que deberías ...

EDITAR
La declaración lock, explicó brevemente:

Está destinado a ser utilizado para la seguridad de las operaciones de rosca. la sintaxis es la siguiente:

lock(lockObject) 
{ 
    // do stuff 
} 

Los lockObject tiene que ser un objeto, normalmente un miembro privado de la clase actual. El efecto es que si tiene 2 hilos que desean ejecutar este código, el primero en llegar a la declaración lock bloquea el lockObject. Mientras hace sus cosas, el segundo hilo no puede adquirir un bloqueo, ya que el objeto ya está bloqueado. Así que simplemente se queda allí y espera hasta que el primer hilo suelta el bloqueo cuando sale del bloque en el }. Solo entonces puede el segundo hilo bloquear el lockObject y hacer sus cosas, bloqueando el lockObject para cualquier tercer hilo que se presente, hasta que también salga del bloque.

Cuidado, todo el tema de la seguridad de hilos no es nada trivial. (Se podría decir que la única cosa trivial de ello son los numerosos errores triviales un programador puede hacer ;-) See here para una introducción a rosca en C#

+0

Respuesta excelente Treb, ¿Puede explicar un poco más acerca de la declaración de "bloqueo" ya que no estoy familiarizado con ella? –

+1

@David: 'lock' está documentado aquí http://msdn.microsoft.com/en-us/library/c5kehkcz(v=vs.100).aspx – Grhm

0

Get IP del usuario e insertarlo en la caché durante una hora después de usar Web servicio, este se almacena en caché en el servidor:

HttpContext.Current.Cache.Insert("UserIp", true, null,DateTime.Now.AddHours(1),System.Web.Caching.Cache.NoSlidingExpiration); 

Cuando es necesario comprobar si el usuario introduce en la última hora:

if(HttpContext.Current.Cache["UserIp"] != null) 
{ 
//means user entered in last hour 
} 
Cuestiones relacionadas