Una clase de PHP para evitar ataques de fuerza bruta en el acceso a nuestra aplicación web

Tenía este código por casa desde hace tiempo y ahora que lo he vuelto a usar para un nuevo proyecto he pensado que ya era el momento de ponerlo un poco en limpio y compartirlo.

PHP Login Blacklist

Permite detectar intentos de ataques por fuerza bruta en nuestra aplicación guardando en una base de datos SQLite los nombres de usuario para los que haya fallado la autenticación y permitiendo que no ejecutemos el código de autenticación si no han pasado X segundos desde el último intento.

Espero que le resulte útil a alguien, es una forma sencilla de aumentar la seguridad de nuestra aplicación.

Reto para el último trimestre de 2018

Últimamente he leído bastantes artículos por ahí en los que la gente se queja del estado actual del desarrollo web. La principal queja es que aun teniendo conexiones de alta velocidad la páginas siguen cargando lentas. En estos dos artículos lo explican perfectamente:

Leyendo estos artículos me reconocía en la sensación de hartazgo que supone que una página de noticias (que es básicamente texto y fotos) se vea a trompicones en un ordenador de 16GB de RAM obligándome a usar una extensión para desactivar JS en ese tipo de páginas.

Pero también me di cuenta de que yo mismo he contribuido a ese estado de la web actual. Mis últimos proyectos no funcionan sin JS. Usuarios con navegadores antiguos no pueden acceder a la información que se supone que mis páginas deberían ofrecer. Reconozco mi culpa.

No basta con reconocer la culpa, es necesario además tener espíritu de enmienda. Y fue al leer este breve libro, Resilient Web Design, cuando decidí que había llegado el momento de ser coherente y cambiar el enfoque que tengo con el desarrollo web.

Así que me he propuesto un reto para cumplir antes de fin de año. Voy a desarrollar una web que cumpla los siguientes requisitos:

  • Cargue y pueda empezarse a usar en menos de tres segundos.
  • Funcione aunque el usuario desactive JavaScript / CSS en su navegador.
  • Bonus: la web debe funcionar con las versiones más antiguas que pueda encontrar y usar de Netscape Navigator e Internet Explorer.

Escribiré entradas aquí con todo lo que me vaya pareciendo interesante del proceso. ¡Deseadme suerte!

Compilar ficheros vue (single file components) sin usar webpack o browserify

Llevo un tiempo estudiando Vue.js y me gusta bastante. Lo que más me gusta es poder tener los componentes separados en ficheros .vue con su HTML, CSS y JS.

El problema es que estos ficheros .vue no se pueden usar directamente, hay que convertirlos, y para eso se requiere webpack o browserify o algún programa similar. Aprender a usar estos programas no es trivial, y lleva su tiempo.

Hay un paquete de Node, VUE cli, que permite crear un esqueleto de aplicación para Vue que ya tiene configurado webpack para “compilar” los ficheros .vue, pero no me convence porque aunque quizá para una aplicación que empieces desde cero puede valer no tengo muy claro cómo incorporarlo a un proyecto ya existente (quiero usar Vue para hive.ly).

Total, que al final he hecho un pequeño script al que le pasas tres parámetros:

  • La carpeta donde están los ficheros .vue
  • La ruta de un fichero js
  • La ruta de un fichero css

y genera un fichero js y otro css con el código y los estilos de los ficheros .vue. Basta con cargar estos dos ficheros en nuestra página y ya podremos usar los componentes.

El script está disponible en GitHub y requiere que tengamos instalado PHP en nuestro ordenador.

El único requisito que deben cumplir los ficheros .vue es que el parámetro template de la llamada a Vue.component debe ser una cadena vacía con backticks: “

Ejemplo de fichero .vue:

<template>
	<div>
		<button v-on:click="count++">
			You clicked me {{ count }} times.
		</button>
		<image-counter></image-counter>
	</div>
</template>

<script>
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    };
  },
  template: ``
});
</script>

<style>
button {
	background: red;
}
</style>

sonarwhal, un analizador de páginas web de Microsoft

Microsoft ha lanzado sonarwhal, un analizador de páginas web que detecta errores y posibles fallos de seguridad. Es parecido al PageSpeed Insights de Google, pero con la ventaja de que podemos instalarlo en nuestro equipo para hacer el análisis en local.

Una cosa sobre la que avisa y que no conocía es que cuando tenemos links que se abren en una ventana nueva y que tienen como destino páginas externas debemos añadir el atributo rel=”noopener noreferrer”; haciendo esto evitamos que la página a la que enlazamos tenga acceso a nuestra ventana mediante window.opener y también que esa pestaña tenga su propio proceso. Aquí lo explican con detalle.

Reflexiones sobre web components vs plugins de jQuery

Hace unos días estuve investigando los web components, que nos permiten crear elementos HTML que tengan sus propias etiquetas e incluirlos en una página web de la misma forma que usamos cajas de texto o desplegables.

Los estándares van despacio, y de momento Google Chrome es el único navegador que implementa todas las funcionalidades por defecto, pero existen polyfills para el resto de navegadores, así que ya se puede ir haciendo algo. Estuve mirando Polymer y X-Tag, y al final me decidí por este último porque no requiere instalar nada en el equipo para trabajar, basta con incluir un fichero JS con la librería y el polyfill.

Para probar hice un componente que es una valoración en estrellas, como las que usan muchas páginas para valorar productos o películas. Puede verse el resultado final con demos aquí.

La forma de crear el componente me recordó bastante a la de crear un plugin para jQuery. A partir de ciertos valores (atributos en el caso del componente, parámetros de inicialización en el caso de jQuery) se construye un código HTML (el que contiene las estrellas) que se inyecta en el componente padre (el elemento koas-star-rating en el caso del componente, el elemento sobre el que apliquemos el plugin en jQuery). Adicionalmente se responde a eventos del ratón modificando ese HTML (para colorear las estrellas correspondientes) y se pueden emitir eventos a los que el usuario que esté usando nuestro componente / plugin pueda engancharse y ser notificado cuando el valor cambie.

Incluso la forma de hacer que el componente se pueda usar dentro de un formulario y contenga un valor cuando el formulario se envíe (creando un campo input oculto cuyo valor se modifica cada vez que cambia el valor de las estrellas) es la misma que usaríamos si estuviéramos haciendo un plugin de jQuery.

Por este motivo, una vez terminé el componente y lo probé en todos los navegadores y vi que funcionaba bien me pregunté: bueno, vale, has hecho un componente pero, ¿compensa hacer esto en vez de hacer un plugin de jQuery? Esta es la pregunta a la que me gustaría dar respuesta con las siguientes reflexiones.

  • Lo primero que se me viene a la cabeza es que los componentes tienen una gran ventaja: para usarlos no es necesario conocer jQuery. Bien, de acuerdo, es difícil que a día de hoy haya programadores de JS que no conozcan jQuery, pero puede pasar. Y aunque no fuera así, aunque todos los programadores del mundo usaran jQuery, creo que es mucho más elegante tener una solución que no dependa de una librería externa. Esto ya es una opinión personal, soy partidario del Vanilla JS y si bien uso jQuery (y me encanta) hasta ahora nunca he usado (ni he sentido la necesidad de hacerlo) ningún framework ni nada parecido para ningún desarrollo personal ni profesional. Punto para los componentes.
     
  • Respecto a dependencias, si bien es cierto que los componentes no requieren de una librería como jQuery sí que necesitan el polyfill, al menos hasta que todos los navegadores implementen todas las tecnologías necesarias. En este sentido componentes y plugins tienen el mismo “coste”: incluir el polyfill si queremos usar un componente y jQuery si queremos usar el plugin. Sin embargo los componentes tienen una ventaja añadida, porque al usar la tecnología HTML Imports (que nos permite importar un fichero HTML) podemos incluir tantos ficheros JS y CSS como queramos con una única línea de código (el fichero HTML que importemos incluirá las referencias necesarias a los ficheros JS y CSS). En el caso de jQuery si el plugin tiene un fichero CSS deberemos cargarlo también. Por lo general todos los plugin de jQuery tienen su fichero CSS, lo que hace que el número final de ficheros que deberemos cargar en la cabecera (o pie) de nuestra página será de 2 para un componente (el polyfill y el fichero HTML que a su vez cargará el resto de ficheros necesarios) y de (al menos) 3 para un plugin (la librería jQuery, el fichero JS con el código y el fichero CSS con los estilos). Punto para los componentes.
     
  • Supongamos que el componente / plugin es muy muy sencillo y solo consiste en un fichero de código. En ese caso, y si solo tenemos en cuenta el peso de las dependencias, estaríamos añadiendo 69,4 KB en los componentes (el peso del polyfill minimizado) y 84,6 KB (el peso de jQuery 3.2.1 minimizado). Punto para los componentes.
     
  • Respecto a cómo desarrollar el código necesario para la funcionalidad que queremos las dos opciones están igualadas, ya sea usando jQuery o JS a pelo podremos implementar todo lo que necesitemos.
     
  • Finalmente está el asunto de la claridad del código. A la hora de leer el código HTML de una página es mucho más claro ver una etiqueta que diga <koas-star-rating> que ver un div y luego, al final de la página, ver un código JS que hace una llamada al plugin sobre ese div. La etiqueta propia del componente nos dice claramente qué hace ese elemento, esto ya es una gran ventaja, pero además no necesitamos hacer ninguna llamada JS para que “arranque”. Aunque hay plugins en los que esto no es necesario (el código del plugin ya se ocupa de ejecutarse sobre los elementos que tengan por ejemplo una clase determinada) la arquitectura de los componentes es más simple e intuitiva. Punto sin duda para los componentes.
     

En resumen, los plugins de jQuery seguirán teniendo su utilidad en muchos casos, pero si lo que queremos es crear un elemento de interfaz de usuario creo que los componentes web son mucho más interesantes y reutilizables. Espero que el resto de navegadores se pongan las pilas y pronto podamos disfrutar los web components de forma nativa.

Dos trucos para aumentar la productividad con el ordenador

Me he encontrado con este magnífico artículo llamado Avoiding the productivity mouse-traps. Es una lista de consejos para ganar tiempo al usar el ordenador utilizando el teclado en vez del ratón.  Voy a listar aquí dos que no conocía y que me parecen imprescindibles:

  • Aumentar la velocidad de repetición del teclado y disminuir el intervalo de repetición. Esto me ha llamado mucho la atención, en todos los años que llevo trabajando con ordenadores nunca me había dado cuenta. Al seleccionar texto con el teclado pasa un pequeño intervalo de tiempo entre que pulsamos la tecla del cursor y la selección empieza a rellenarse. Reduciendo este tiempo se gana un poco de tiempo (milésimas de segundo, quizá, pero a lo largo de un día entero suma). Igualmente aumentando la velocidad de repetición la selección se lleva a cabo más deprisa. Adjunto aquí una captura de la pantalla de propiedades del teclado para referencia en el futuro:

  • El plugin Ace Jump para Sublime Text 3. Esto también me ha dejado asombrado, me parece genial. Nos permite saltar rápidamente a cualquier línea que tengamos en pantalla. Lo he estado usando diez minutos y creo que ya nunca podré dejarlo.

Eliminar elementos del listado de ventanas en Cinnamon

Me permití un caprichillo en el Black Friday de este año, un monitor de 10 pulgadas que básicamente voy a usar para las ventanas de Developer Tools de Chrome.

Cuando me llegó estuve un rato probándolo y me di cuenta de que como normalmente tengo varias de esas ventanas abiertas se me iba a llenar el panel inferior (donde tengo la lista de ventanas) de botones para esas ventanas. Me acordé de que Cinnamon está escrito en JS así que investigué un poco a ver si podía evitarlo, y efectivamente se puede.

Lo que hay que hacer es editar el fichero /usr/share/cinnamon/applets/window-list@cinnamon.org/applet.js, y añadir este código en la línea 1063 (después de la línea let appButton = new AppMenuButton(this, metaWindow, alert);):

if (appButton._label.text.indexOf("Developer Tools") > -1)
 return;

De esta forma evitamos que se incluyan en la lista de ventanas los botones correspondientes a las ventanas de las Developer Tools. Por supuesto funciona cambiando el texto por cualquier otro si queremos esconder alguna otra ventana de la lista.

Algo que me vino muy bien es tener abierta una ventana de consola con este comando:

tail -f ~/.cinnamon/glass.log

que nos permite ver el log de Cinnamon y escribir en él desde JS con la función global.log(). Para recargar el applet de la lista de ventanas ejecutamos el siguiente comando:

dbus-send --session --dest=org.Cinnamon.LookingGlass --type=method_call /org/Cinnamon/LookingGlass org.Cinnamon.LookingGlass.ReloadExtension string:'window-list@cinnamon.org' string:'APPLET'

Al final después de conseguirlo me di cuenta de que no me hacía falta todo esto. Basta con crear un nuevo panel en el segundo monitor y añadirle el applet de lista de ventanas, y los botones para las ventanas de ese monitor se muestran ahí, liberando la lista de ventanas del monitor principal.

Actualización 8/2/2018: para que las ventanas de Developer Tools se abran siempre en el nuevo monitor he instalado devilspie, un programa que nos permite definir reglas para ejecutar acciones sobre las ventanas que se vayan creando. Con este programa puedo hacer que estas ventanas (y las de la terminal, por ejemplo) se abran siempre en el monitor auxiliar, pero además este programa permite que esas ventanas no aparezcan en la lista de tareas, lo cual es justo lo que quería hacer al principio. ¡Hurra!

Copio aquí la regla, hay que tener en cuenta que el monitor auxiliar lo tengo a la izquierda del principal, por lo que sus coordenadas empiezan en 0,0.

; Regla para Chrome Developer Tools, skip_tasklist es lo que hace que no salga en la lista de ventanas
( if 
( begin 
( contains ( application_name ) "chrome-devtools" )
) 
( begin 
( skip_tasklist )
( geometry "600x800+0+0" )
( maximize )
)
)