Recientemente tuve tiempo para reflexionar nuevamente sobre cómo debería funcionar la función de restablecimiento seguro de contraseñas, primero cuando integré esta funcionalidad en , y luego cuando ayudé a hacer algo similar a otra persona. En el segundo caso, quería darle un enlace a un recurso canónico con todos los detalles sobre la implementación segura de la función de restablecimiento. Sin embargo, el problema es que no existe tal recurso, al menos no uno que describa todo lo que considero importante. Así que decidí escribirlo yo mismo.
Verá, el mundo de las contraseñas olvidadas es en realidad bastante enigmático. Hay numerosas perspectivas aceptables y muchas que son bastante peligrosas. Es probable que haya encontrado muchas de ellas como usuario final; por lo tanto, intentaré aprovechar estos ejemplos para mostrar quién está haciendo todo bien y quién no, y en qué deberíamos enfocarnos para implementar correctamente la función en nuestra aplicación.

Almacenamiento de contraseñas: hash, cifrado y (¡oh!) texto plano
No podemos discutir qué hacer con las contraseñas olvidadas antes de hablar sobre cómo se almacenan. En la base de datos, las contraseñas se almacenan en uno de los tres tipos principales:
- Texto plano. Hay una columna con la contraseña que se almacena en texto sin formato.
- Cifrada. Generalmente mediante cifrado simétrico (una clave se utiliza tanto para cifrar como para descifrar), y las contraseñas cifradas también se almacenan en una sola columna.
- Hasheada. Proceso unidireccional (se puede hashear una contraseña, pero no se puede deshashear); la contraseña, se espera, va acompañada de una sal, y cada una se encuentra en su propia columna.
Vamos a aclarar inmediatamente la pregunta más sencilla: ¡nunca almacene contraseñas en texto plano! Nunca. Una sola vulnerabilidad a , una copia de seguridad imprudente o uno de los muchos otros errores simples, y eso es todo, fin del juego, todas sus contraseñas—es decir, perdón, las contraseñas de todos sus clientes se convertirán en de dominio público. Por supuesto, esto significará una enorme probabilidad de que se hagan públicas de todas sus cuentas en otros sistemas. Y eso será culpa suya.
El cifrado es mejor, pero tiene sus debilidades. El problema del cifrado radica en la descifrado; se pueden tomar estos esquemas absurdos y convertirlos de nuevo en texto plano, y cuando eso sucede, volvemos a la situación con contraseñas legibles. ¿Cómo ocurre esto? Un pequeño fallo se infiltra en el código que se encarga de descifrar la contraseña, haciéndola accesible públicamente; esa es una forma. Hackers obtienen acceso a la máquina que almacena los datos cifrados; esa es la segunda forma. Otra forma es que se roba una copia de seguridad de la base de datos, y alguien también obtiene la clave de cifrado, que a menudo se almacena de manera muy poco segura.
Y esto nos lleva a la hashing. La idea de hashing es que se realiza en una sola dirección; la única forma de comparar la contraseña ingresada por el usuario con su versión hash es hasheando la entrada y comparándola. Para prevenir ataques utilizando herramientas como las "tablas arcoíris", introducimos aleatoriedad en el proceso con una sal (para más contexto, lee mi sobre almacenamiento criptográfico). En última instancia, con la implementación correcta, podemos tener un alto grado de confianza en que las contraseñas hash nunca volverán a ser texto plano (los beneficios de los diferentes algoritmos de hashing los discutiré en otra publicación).
Un breve argumento sobre hashing y cifrado: la única razón por la que alguna vez necesitarás cifrar en lugar de hashear una contraseña es cuando necesitas ver la contraseña en texto plano, y nunca deberías querer eso, al menos en un escenario de un sitio web estándar. Si lo necesitas, lo más probable es que estés haciendo algo mal.
¡Atención!
Un poco más abajo en el texto de la publicación hay una parte de una captura de pantalla del sitio web pornográfico AlotPorn. Está cuidadosamente recortada, y no hay nada que no se pueda ver en la playa, pero si eso aún puede causar problemas, entonces no desplazas hacia abajo.
Siempre restablece tu contraseña, nunca no la recuerdes
¿Alguna vez te han pedido que crees una función de recordatorio? ¿Olvidó su contraseña? Dé un paso atrás y reflexione sobre esta solicitud en sentido inverso: ¿por qué necesitamos este "recordatorio"? Porque el usuario olvidó su contraseña. ¿Qué es lo que realmente queremos hacer? Ayudarle a volver a acceder a su cuenta.
Entiendo que la palabra "recordatorio" se usa (a menudo) en un sentido coloquial, pero en realidad estamos tratando de ayudar al usuario a estar en línea de manera segura. Dado que necesitamos seguridad, hay dos razones por las cuales un recordatorio (es decir, enviarle su contraseña al usuario) no es adecuado:
- El correo electrónico es un canal inseguro. Al igual que no enviaríamos nada confidencial por HTTP (usaríamos HTTPS), no deberíamos enviar nada por correo electrónico porque su capa de transporte no es segura. De hecho, es mucho peor que simplemente transmitir información a través de un protocolo de transporte no seguro, porque los correos suelen ser almacenados, accesibles para administradores del sistema, reenviados y distribuidos, y expuestos a software malicioso, etc. El correo no cifrado es un canal extremadamente inseguro.
- De todos modos, no debería tener acceso a la contraseña. Relea la sección anterior sobre almacenamiento: debe tener un hash de la contraseña (con una buena sal resistente), es decir, de ninguna manera debería poder extraer la contraseña y enviarla por correo.
Permítame demostrar el problema con el ejemplo de : Aquí hay una típica página de inicio de sesión:

Obviamente, el primer problema es que la página de inicio de sesión no se carga a través de HTTPS, pero el sitio también ofrece enviar la contraseña ("Enviar contraseña"). Esto podría ser un ejemplo de la aplicación coloquial mencionada anteriormente, así que vamos a dar otro paso y ver qué sucede:

Desafortunadamente, no se ve mucho mejor; y el correo confirma la existencia del problema:

Esto nos dice dos aspectos importantes sobre usoutdoor.com:
- El sitio no hace hash de las contraseñas. En el mejor de los casos, están cifradas, pero es muy probable que se almacenen en texto plano; no hay evidencia en contrario.
- El sitio envía una contraseña a largo plazo (podemos volver a usarla una y otra vez) a través de un canal no seguro.
Una vez que hayamos aclarado esto, necesitamos verificar si el proceso de restablecimiento se realiza de manera segura. Primero, debemos asegurarnos de que el solicitante tenga derecho a realizar el restablecimiento. En otras palabras, antes de esto, necesitamos una verificación de identificación; veamos qué sucede cuando la identidad se confirma sin una verificación previa de que el solicitante es, de hecho, el propietario de la cuenta.
La enumeración de nombres de usuario y su impacto en el anonimato
Este problema se puede ilustrar mejor visualmente. Problema:

¿Lo ves? Observa el mensaje 'There is no user registered with this email address' ('No hay ningún usuario registrado con esta dirección de correo electrónico'). El problema, evidentemente, surge si un sitio como este confirma presencia de la existencia de un usuario registrado con esa dirección de correo electrónico. ¡Bingo! ¡Acabas de descubrir el fetiche pornográfico de tu esposo/jefe/vecino!
Por supuesto, la pornografía es un ejemplo bastante canónico de la importancia de la privacidad, sin embargo, el peligro de vincular una identidad a un sitio web específico es mucho más amplio que la potencialmente incómoda situación descrita anteriormente. Uno de los peligros es la ingeniería social; si un atacante puede vincular a una persona con un servicio, obtendrá información que puede comenzar a utilizar. Por ejemplo, puede contactar a la persona haciéndose pasar por un representante del sitio web y solicitar más información, intentando realizar .
Prácticas como estas también dan lugar al riesgo de 'enumeración de nombres de usuario', donde se puede verificar la existencia en un sitio web de toda una colección de nombres de usuario o direcciones de correo electrónico mediante consultas grupales simples y el estudio de las respuestas. ¿Tienes una lista de direcciones de correo electrónico de todos los empleados y unos minutos para escribir un script? Entonces ya ves cuál es el problema.
¿Cuál es la alternativa? De hecho, es bastante simple y está muy bien implementada en :

Aquí, Entropay no revela nada sobre la existencia de una dirección de correo electrónico en su sistema para quienes no poseen esta dirección. Si tú posees si esta dirección no existe en el sistema, recibirás un correo electrónico como este:

Por supuesto, hay situaciones aceptables en las que alguien piensa, que se registró en el sitio web. pero no es así, o lo hizo desde otra dirección de correo electrónico. El ejemplo anterior maneja ambas situaciones con éxito. Obviamente, si la dirección coincide, recibirás un correo que facilita el restablecimiento de la contraseña.
La sutileza de la solución de Entropay elegida es que la verificación de identidad se realiza a través de correo electrónico antes de cualquier verificación en línea. Algunos sitios piden a los usuarios que respondan a una pregunta secreta (más sobre esto a continuación) hasta sobre cómo puede comenzar el restablecimiento; sin embargo, el problema con esto es que se debe responder a la pregunta proporcionando algún tipo de identificación (correo o nombre de usuario), lo que hace que sea casi imposible responder intuitivamente sin revelar la existencia de una cuenta de usuario anónimo.
Con este enfoque hay una pequeña reducción de usabilidad, porque en caso de intentar restablecer una cuenta que no existe no hay retroalimentación instantánea. Por supuesto, ese es todo el sentido de enviar un correo electrónico, pero desde la perspectiva del usuario final real, si introduce una dirección incorrecta, solo se dará cuenta de ello al recibir el correo. Esto puede causar cierta tensión por su parte, pero es un pequeño precio a pagar por un proceso tan raro.
Otra observación, un poco fuera del tema: las funciones de ayuda para iniciar sesión que revelan la validez del nombre de usuario o de la dirección de correo electrónico tienen el mismo problema. Siempre responde al usuario con el mensaje «Combinación de nombre de usuario y contraseña incorrecta» (Your username and password combination is invalid), y no confirmes explícitamente la existencia de información de identificación (por ejemplo, «el nombre de usuario es correcto, pero la contraseña introducida es incorrecta»).
Envío de la contraseña de restablecimiento frente al envío de URL de restablecimiento
El siguiente concepto que necesitamos discutir está relacionado con la forma de restablecer la contraseña. Hay dos soluciones populares:
- Generación de una nueva contraseña en el servidor y su envío por correo electrónico
- Enviar un correo electrónico con una URL única que simplifique el proceso de restablecimiento
A pesar de , el primer punto nunca debe usarse. Su problema es que significa que hay una contraseña almacenada, a la que se puede regresar y volver a usar en cualquier momento; ha sido transmitida por un canal no seguro y permanece en su buzón. Hay una probabilidad de que los mensajes entrantes se sincronicen con dispositivos móviles y clientes de correo electrónico, además pueden almacenarse en línea en un servicio de correo electrónico durante mucho tiempo. La cuestión es que la bandeja de entrada no se puede considerar un medio confiable para el almacenamiento a largo plazo.
Pero además de esto, el primer punto tiene otro problema serio: él facilita en gran medida el bloqueo de cuentas de manera maliciosa. Si conozco la dirección de correo electrónico de quien posee la cuenta en el sitio web, puedo bloquearla en cualquier momento, simplemente restableciendo su contraseña; ¡es un ataque de denegación de servicio presentado en una bandeja con borde azul! Por esta razón, el restablecimiento debe realizarse solo después de una verificación exitosa de los derechos del solicitante sobre él.
Cuando hablamos de la URL de restablecimiento, nos referimos a la dirección del sitio web que es única para este caso específico de proceso de restablecimiento. Por supuesto, debe ser aleatoria, no debe ser fácil de adivinar y no debe contener ningún enlace externo a la cuenta que facilite el restablecimiento. Por ejemplo, la URL de restablecimiento no debe ser simplemente una ruta como «Reset/?username=JohnSmith».
Queremos crear un token único que se pueda enviar por correo como URL de restablecimiento y luego verificarlo con el registro en el servidor de la cuenta del usuario, confirmando así que el propietario de la cuenta es realmente la misma persona que intenta restablecer la contraseña. Por ejemplo, el token podría ser «3ce7854015cd38c862cb9e14a1ae552b» y almacenarse en una tabla junto con el ID del usuario que realiza el restablecimiento y el tiempo de generación del token (más detalles sobre esto a continuación). Al enviar el correo, contiene una URL como «Reset/?id=3ce7854015cd38c862cb9e14a1ae552b», y cuando el usuario la carga, la página solicita la existencia del token, luego confirma la información del usuario y permite cambiar la contraseña.
Por supuesto, dado que el proceso descrito anteriormente (esperemos) permite al usuario crear una nueva contraseña, debe garantizarse la carga de la URL a través de HTTPS. No, , esta URL con el token debe utilizar la seguridad de la capa de transporte para que no se pueda realizar un ataque y la contraseña creada por el usuario se transfiera a través de una conexión segura.
También para la URL de restablecimiento es necesario agregar un límite de tiempo al token, de modo que el proceso de restablecimiento se pueda realizar dentro de un intervalo determinado, digamos, en el transcurso de una hora. Esto garantiza que la ventana de tiempo de restablecimiento sea mínima, para que quien reciba esta URL de restablecimiento solo pueda actuar dentro de esta pequeña ventana. Por supuesto, un atacante puede reiniciar el proceso de restablecimiento, pero necesitará obtener otra URL de restablecimiento única.
Finalmente, debemos garantizar que este proceso sea de un solo uso. Una vez completado el proceso de restablecimiento, el token debe eliminarse para que la URL de restablecimiento ya no sea funcional. El punto anterior es necesario para que un atacante tenga una ventana de tiempo muy pequeña en la que pueda manipular la URL de restablecimiento. Además, por supuesto, después de completar con éxito el restablecimiento, el token ya no es necesario.
Algunos de estos pasos pueden parecer excesivos, pero no afectan en absoluto a la usabilidad y realmente aumentan la seguridad, aunque en situaciones que, esperamos, serán raras. En el 99% de los casos, el usuario llevará a cabo el restablecimiento en un período de tiempo muy corto y no restablecerá la contraseña nuevamente en el futuro cercano.
El rol de CAPTCHA
¡Oh, CAPTCHA, esa herramienta de protección que todos amamos odiar! En realidad, CAPTCHA no es tanto una medida de protección, sino de identificación: si eres humano o un robot (o un script automatizado). Su propósito es evitar el envío automático de formularios, que, por supuesto, puede puede ser un intento de romper la protección. En el contexto del restablecimiento de contraseñas, CAPTCHA significa que la función de restablecimiento no podrá ser hackeada mediante un ataque de fuerza bruta, para luego hacer spam al usuario o intentar determinar la existencia de cuentas (lo cual, por supuesto, será imposible si sigues los consejos de la sección sobre verificación de identidad).
Por supuesto, el CAPTCHA por sí mismo no es perfecto; hay muchos precedentes de su "hackeo" y de lograr tasas de éxito suficientes (60-70%). Además, existe una solución, mostrada en mi publicación sobre , donde se puede pagar a las personas fracciones de centavo para resolver cada CAPTCHA y alcanzar una tasa de éxito del 94%. Es decir, es vulnerable, pero (ligeramente) aumenta la barrera de entrada.
Veamos el ejemplo de PayPal:

En este caso, el proceso de restablecimiento no puede comenzar hasta que se resuelva el CAPTCHA, por lo que teóricamente automatizar el proceso es imposible. Teóricamente.
Sin embargo, para la mayoría de las aplicaciones web, esto sería excesivo y sin duda representa una disminución en la usabilidad; a la gente simplemente no le gustan los CAPTCHA. Además, el CAPTCHA es algo a lo que se puede volver fácilmente si es necesario. Si el servicio comienza a ser atacado (aquí se requiere el registro, pero hablaremos de eso más adelante), es muy fácil añadir un CAPTCHA.
Preguntas y respuestas secretas
Con todos los métodos que hemos considerado, hemos podido restablecer la contraseña, solo teniendo acceso a la cuenta de correo electrónico. Digo "solo", pero, por supuesto, obtener ilegalmente acceso a la cuenta de correo de alguien debe puede ser un proceso complicado. Sin embargo .
De hecho, el enlace presentado anteriormente sobre el hackeo de la cuenta de Sarah Palin en Yahoo! cumple con dos propósitos; primero, ilustra lo fácil que es hackear (algunas) cuentas de correo, y segundo, muestra cómo se pueden utilizar preguntas secretas defectuosas de forma malintencionada. Pero volveremos a esto más adelante.
El problema con el restablecimiento de contraseñas que depende completamente del correo electrónico es que la integridad de la cuenta del sitio, cuya contraseña intentas restablecer, se vuelve totalmente dependiente de la integridad de la cuenta de correo electrónico. Cualquiera que tenga acceso a tu correo electrónico, tiene acceso a cualquier cuenta que se pueda restablecer simplemente recibiendo un correo electrónico. Para tales cuentas, el correo electrónico es "la llave de todas las puertas" de tu vida en línea.
Una de las formas de reducir este riesgo es implementar el patrón de pregunta y respuesta secreta. Sin duda, ya los has visto: eliges una pregunta a la que solo tú deben sabes la respuesta, después de lo cual, al restablecer la contraseña, te la hacen. Esto añade confianza en que la persona que intenta restablecer realmente es el propietario de la cuenta.
Regresando a Sarah Palin: el error fue que las respuestas a su pregunta/preguntas secretas eran fáciles de encontrar. En particular, cuando eres una figura pública tan significativa, información sobre el apellido de soltera de su madre, su historia educativa o dónde alguien pudo haber vivido en el pasado no es tan secreta. De hecho, la mayor parte puede ser encontrada prácticamente por cualquiera. Así sucedió con Sarah:
El hacker David Kernell accedió a la cuenta de Palin al encontrar detalles de su biografía, como su universidad y fecha de nacimiento, y luego usar la función de recuperación de contraseñas olvidadas de las cuentas de Yahoo!.
En primer lugar, es un error de diseño por parte de Yahoo! — al establecer preguntas tan simples, la compañía en esencia socavó el valor de la pregunta secreta, y por lo tanto, la seguridad de su sistema. Por supuesto, restablecer las contraseñas de una cuenta de correo electrónico siempre es más complicado, ya que no puedes confirmar su propiedad enviando un correo electrónico al propietario (sin tener una segunda dirección), pero, afortunadamente, hoy en día no hay tantas maneras de implementar un sistema como ese.
Regresando a las preguntas secretas — existe la opción de permitir al usuario crear sus propias preguntas. El problema es que como resultado se obtendrán preguntas terriblemente obvias:
¿De qué color es el cielo?
Preguntas que ponen a las personas en una situación incómoda, cuando para la identificación se utiliza la pregunta secreta una persona (por ejemplo, en un centro de llamadas):
¿Con quién pasé la noche de Navidad?
O preguntas francamente absurdas:
¿Cómo se escribe 'contraseña'?
Cuando se trata de preguntas secretas, ¡hay que salvar a los usuarios de sí mismos! En otras palabras, la pregunta secreta debe ser determinada por el propio sitio, y aún mejor, plantear una serie de preguntas secretas, de las cuales el usuario puede elegir. Y no simplemente elegir uno; idealmente, el usuario debería seleccionar dos o más preguntas secretas al momento de registrarse en la cuenta., que luego se utilizarán como un segundo canal de identificación. Tener múltiples preguntas aumenta la confianza en el proceso de verificación y también permite añadir un poco de aleatoriedad (no siempre mostrar la misma pregunta), además de proporcionar algo de redundancia en caso de que el usuario real haya olvidado su contraseña.
¿Cómo debe ser una buena pregunta secreta? Varios factores influyen en esto:
- Debe ser breve — la pregunta debe ser clara y sin ambigüedades.
- La respuesta debe ser específica — no necesitamos una pregunta a la que una persona pueda responder de diferentes maneras.
- Las posibles respuestas deben ser variadas — una pregunta sobre el color favorito de alguien ofrece un conjunto muy pequeño de respuestas posibles.
- Búsqueda la respuesta debe ser compleja — si la respuesta se puede encontrar fácilmente, cualquier (pensemos en personas en posiciones elevadas), entonces es una mala pregunta.
- La respuesta debe ser período constante a lo largo del tiempo — si se pregunta sobre la película favorita de alguien, con el tiempo la respuesta puede cambiar.
Como suele suceder, hay un sitio web dedicado a buenas preguntas, llamado . Algunas preguntas parecen bastante decentes, otras no pasan la prueba de "facilidad de búsqueda" descrita anteriormente.
Déjame mostrarte cómo se implementan las preguntas secretas en PayPal y, en particular, qué esfuerzos hace el sitio para la identificación. Anteriormente vimos la página de inicio del proceso (con CAPTCHA), y aquí mostraremos lo que sucede después de que introduces la dirección de correo y completas el CAPTCHA:

Como resultado, el usuario recibe un correo como este:

Hasta aquí todo es bastante normal, pero esto es lo que se oculta detrás de esta URL de restablecimiento:

Así que entran en juego las preguntas secretas. De hecho, PayPal también permite restablecer la contraseña confirmando el número de la tarjeta de crédito, así que existe un canal adicional que muchos sitios no tienen. Simplemente no puedo cambiar mi contraseña sin responder a ambas preguntas secretas (o sin conocer el número de la tarjeta). Incluso si alguien captura mi correo electrónico, no podrá restablecer la contraseña de mi cuenta de PayPal a menos que sepa un poco más de información personal sobre mí. ¿Qué información? Aquí están las opciones de preguntas secretas ofrecidas por PayPal:

La cuestión de la escuela y el hospital puede ser un poco dudosa en términos de facilidad de búsqueda, pero las demás no son tan malas. Sin embargo, para mejorar la seguridad, PayPal requiere una identificación adicional para cambios responder a las preguntas secretas:

PayPal es un ejemplo bastante utópico de un método seguro para restablecer la contraseña: implementa CAPTCHA para reducir el riesgo de ataques de fuerza bruta, requiere dos preguntas secretas y luego exige otro tipo de identificación completamente diferente solo para cambiar las respuestas, y esto después de que el usuario ya ha iniciado sesión. Lo que esperábamos de PayPal; es una organización financiera que maneja grandes sumas de dinero. Esto no significa que cada restablecimiento de contraseña deba seguir estos pasos; en la mayoría de los casos, es excesivo; sin embargo, es un buen ejemplo para situaciones en las que la seguridad es un asunto serio. La conveniencia del sistema de preguntas secretas es que si no lo implementaste de inmediato, puedes agregarlo más tarde si lo exige el nivel de protección del recurso. Un buen ejemplo de esto es Apple, que recientemente implementó este mecanismo
[artículo escrito en 2012] . Una vez que comencé a actualizar la aplicación en el iPad, vi la siguiente solicitud:Luego vi una pantalla donde podía elegir varias pares de preguntas secretas y respuestas, así como una dirección de correo electrónico de rescate:

En el caso de PayPal, las preguntas son seleccionadas de antemano y algunas de ellas son bastante buenas:

Cada uno de los tres pares de preguntas y respuestas representa un conjunto distinto de preguntas posibles, por lo que hay suficientes formas de configurar la cuenta.

Otro aspecto a considerar respecto a la respuesta a la pregunta secreta es el almacenamiento. Tener en la base de datos texto plano representa casi las mismas amenazas que en el caso de la contraseña, ya que la revelación de la base de datos expone instantáneamente el valor y pone en riesgo no solo la aplicación, sino potencialmente otras aplicaciones que utilizan las mismas preguntas secretas (esto nuevamente
es una cuestión de baya de açaí. ). Una de las opciones es el hash seguro (algoritmo resistente y sal criptográficamente aleatoria), aunque a diferencia de la mayoría de los casos de almacenamiento de contraseñas, aquí puede haber una razón legítima para que la respuesta sea visible como texto simple. Un escenario típico es la verificación de identidad por un operador en vivo por teléfono. Por supuesto, en este caso también se puede aplicar el hashing (el operador puede simplemente introducir la respuesta dada por el cliente), pero en el peor de los casos, la respuesta secreta debe residir en algún nivel de almacenamiento criptográfico, aunque sea solo un cifrado simétrico. En resumen: ¡trata los secretos como secretos!
Y el último aspecto de las preguntas y respuestas secretas es que son más vulnerables al ingenio social. Tratar de sondear directamente la contraseña de la cuenta de otra persona es una cosa, pero entablar una conversación sobre su educación (una pregunta secreta popular) es algo completamente diferente. De hecho, puedes estar hablando con alguien sobre muchos aspectos de su vida que pueden representar una pregunta secreta y no generar sospechas. Por supuesto, la esencia misma de la pregunta secreta es que está relacionada con la experiencia de vida de alguien, por lo que se recuerda, y precisamente ahí radica el problema — ¡a la gente le encanta hablar sobre su experiencia de vida! Poco se puede hacer al respecto, a menos que elijas opciones de preguntas secretas que tengan menor probabilidad de ser extraídas mediante ingenio social.
[Continuará.]
Publicidad
VDSina ofrece servidores fiables , cada servidor está conectado a un canal de internet de 500 Megabits y protegido gratuitamente contra ataques DDoS.
Fuente: habr.com
