No lo hagas por tu cuenta …
(susam.net)- El principio Don't Roll Your Own ... se aplica no solo a la criptografía sino también a la UI web, y no conviene reemplazar sin necesidad funciones que el navegador ya ofrece de forma confiable
- Reemplazar comportamientos básicos como el scroll, el manejo de enlaces, la selección de texto o copiar y pegar rompe respuestas de entrada familiares y hace que el usuario tenga que volver a prestar atención a cómo operar la interfaz
- Cuando JavaScript intercepta la navegación de enlaces, como en los enlaces de archivos o issues de GitHub, a veces abrir el enlace en una pestaña nueva es más rápido que esperar a que se procese en la pestaña actual
- El campo de contraseña nativo y
<input type="date">colaboran con autocompletado, administradores de contraseñas, herramientas de accesibilidad y teclados móviles, por lo que sustituirlos por una UI falsa puede romper funciones - Los layouts y controles de formulario que cambian cada pocos meses hacen que los usuarios gasten tiempo reaprendiendo en vez de hacer su trabajo, por lo que conviene mantener los comportamientos básicos estables del navegador
Aplicación del principio “No lo hagas por tu cuenta” a la UI web
- La regla de no implementar criptografía por cuenta propia significa que en software operativo que protege datos sensibles no se debe depender de implementaciones privadas no verificadas
- No significa que nadie deba escribir código criptográfico, sino más bien que, siempre que sea posible, deben usarse paquetes y herramientas revisados y validados
- Hace unos 20 años existían implementaciones caseras de RC4 con problemas reales, como vectores de inicialización inapropiados, flujos de clave predecibles o filtraciones parciales de texto plano
- Hoy en día, los grandes sitios de comercio electrónico o los bancos por lo general no usan criptografía propia en sus servicios web, y en sectores regulados como pagos, salud o tratamiento de datos personales, incumplir requisitos fuertes de cifrado puede llevar a multas importantes
- El diseño de sitios web no es lo mismo que la criptografía, pero volver a implementar funciones que el navegador ya resuelve bien y de las que los usuarios dependen a diario puede empeorar la experiencia de uso
Problemas que surgen al reemplazar funciones nativas del navegador
- Si implementas por tu cuenta el scroll de la página, puedes romper la respuesta habitual al mouse, touchpad o teclado
- Si sobrescribes el comportamiento de scroll nativo, la página puede moverse demasiado lento o demasiado rápido, y el scroll con teclado incluso podría dejar de funcionar
- Cuando una acción que el usuario hacía sin pensarlo cambia por un comportamiento extraño, tiene que volver a prestar atención a la propia manipulación de la página
- Entre las funciones representativas que no conviene reimplementar están la navegación de enlaces, la selección de texto, el menú contextual, copiar y pegar, los campos de contraseña y el selector de fecha
- Al agregar funciones de interfaz en un sitio web de trabajo serio, conviene decidir con cautela si realmente hace falta añadir algo vistoso o dejarlo en manos del comportamiento nativo del navegador
Navegación de enlaces y el caso de GitHub
- El navegador web ya resuelve bien el seguimiento de enlaces, y la navegación por enlaces es una función central del navegador
- Si sientes que debes interferir con el comportamiento normal de un enlace, vale la pena revisar si el objetivo que buscas realmente justifica romper la navegación de enlaces común
- En GitHub, al hacer clic en enlaces de archivos o issues, una gran funcionalidad implementada en JavaScript toma el control del clic
- En Firefox o Chrome puedes comprobar este comportamiento abriendo las herramientas de desarrollador con
F12, y luego seleccionandoclickdentro deMouseenEvent Listener Breakpointsde la pestañaDebuggeroSources, antes de hacer clic en un enlace de GitHub - A veces es más rápido abrir un enlace en una pestaña nueva que esperar a que GitHub procese la navegación por JavaScript en la pestaña actual
Entrada de contraseña y selector de fecha
- El campo de entrada de contraseña del navegador puede ofrecer guardado de contraseñas, autocompletado y generación de contraseñas fuertes para cuentas nuevas
- El campo de contraseña nativo también advierte cuando una contraseña se envía por una conexión HTTP insegura, y coopera con administradores de contraseñas, autocompletado, teclados móviles y herramientas de accesibilidad
- Si se reemplaza por un campo de contraseña falso, estas funciones pueden romperse; y si se enmascara manualmente un campo de texto normal, el navegador, el sistema operativo y las herramientas auxiliares pueden tratar la contraseña como texto visible normal
<input type="date">no admite de forma nativa la selección de un rango de fechas, pero si se ofrecen dos campos, uno para fecha de inicio y otro para fecha de fin, puede mantenerse el selector de fecha nativo del navegador- Los selectores de fecha personalizados varían según la implementación: puede que haya que ampliar a una vista anual, presionar decenas de veces el botón del año anterior para elegir una fecha de nacimiento, o incluso que se bloquee la entrada manual de la fecha
- Si se necesita un widget de calendario para navegadores con soporte insuficiente del selector de fecha nativo, es mejor añadirlo como widget auxiliar que manipule el mismo campo, en lugar de reemplazar
<input type="date">
El costo de los cambios frecuentes en la UI
- Cambiar controles de formulario sin mucho cuidado casi siempre resuelve problemas existentes al mismo tiempo que introduce otros nuevos
- Si el layout y la interfaz de un sitio web cambian cada pocos meses, algunos usuarios se adaptarán, pero los usuarios mayores pueden sentir la carga como si tuvieran que aprender una herramienta nueva cada vez
- Si muchos sitios web siguen cambiando su interfaz, los usuarios terminan gastando bastante tiempo reaprendiendo lo que ya conocían sin obtener un beneficio funcional real
- Igual que si una distribución de Linux rediseñara cada pocos meses todos los comandos principales y sus opciones de línea de comandos, o como si la disposición de los botones de una lavadora cambiara cada mañana, las reorganizaciones repetidas de la UI resultan una experiencia desagradable
- La UI web es una herramienta que el usuario usa para terminar su trabajo, así que conviene no reemplazar sin necesidad comportamientos familiares y estables que el navegador ya ofrece
2 comentarios
No creo que haya muchos países como el nuestro con tanta encriptación propia y tantos programas de seguridad desarrollados internamente.
Opiniones en Lobste.rs
Estoy de acuerdo con no implementar el desplazamiento de página por cuenta propia. No se puede hacer tan bien como el nativo, y la única excepción que aceptaría sería algo como los mapas, donde existe la convención de mapear el scroll al zoom.
Estoy totalmente en desacuerdo con convertir en una regla el no implementar la navegación por enlaces por cuenta propia. En un sitio de contenido general no recomendaría el enrutamiento del lado del cliente (CSR), pero en algunas apps incluso podría recomendarse activamente, y servicios como GitHub están en un punto intermedio.
Aun así, siempre se debe usar un elemento real de `` para que funcionen las capacidades nativas del navegador. En apps como un cliente de correo web sí tiene sentido usar CSR, y en GitHub también fue una mejora cuando antes lo aplicaban de forma ligera, pero su enfoque reciente de frontend ha empeorado bastante.
El problema es que CSR con demasiada frecuencia se implementa de manera descuidada y no se hace robusto ante malas condiciones de red. El navegador sí es resistente en esas situaciones, y optimizaciones como el indicador de carga de pestaña o el bfcache también pueden verse obstaculizadas por CSR.
Implementar la selección de texto por cuenta propia solo me parece aceptable en casos muy específicos, como una app de anotaciones en móvil donde el dedo se usa como si fuera un resaltador. De hecho, hasta agregaría que tampoco debería usarse
::selection. Que con solo añadir::selection{}a una hoja de estilos el área seleccionada pueda volverse invisible es un mal diseño.No estoy de acuerdo con prohibir implementar menús contextuales por cuenta propia. En apps como clientes de correo, administradores de archivos o procesadores de texto se necesitan opciones propias, y como el navegador no ofrece una forma de extenderlos, un menú completamente personalizado es hoy una opción práctica. Por suerte, en Firefox se puede forzar la apertura del menú nativo con Shift+clic derecho.
La prohibición de implementar copiar/pegar por cuenta propia me parece algo con lo que podría estar de acuerdo o no, según cómo se interprete, así que debería ser más clara.
Casi no recuerdo haber visto implementaciones propias de campos de contraseña fuera de demos técnicas. Cambiar `` de
passwordatextcon un botón de mostrar/ocultar no me parece que entre en esa categoría.Tampoco estoy de acuerdo con decir que no se debe implementar un selector de fecha propio. Me gustaría recomendar los controles nativos, pero sus limitaciones e inconsistencias son grandes y en los últimos 10 años casi no ha habido interés en corregirlas. No se puede agregar información al selector, y elegir fechas muy antiguas, como una fecha de nacimiento, es terrible en algunas plataformas. Ej.: Safari's date-picker is the cause of 1/3 of our customer support issues
Los selectores de fecha personalizados tienen muchos problemas de accesibilidad, pero aun así con frecuencia son mejores para el usuario promedio, y muchas veces no se puede usar el control nativo porque hace falta funcionalidad que no tiene. Para elegir una fecha simple prefiero el nativo porque en el navegador que uso permite escribirla directamente, pero para muchos usuarios lo nativo simplemente no es lo bastante bueno. Para rangos de fechas, hacerlo con `` probablemente sea mucho peor para la mayoría.
Cuando hace falta considerar accesibilidad o a las personas que se benefician de ella, expresarlo como si estuvieran en contraste con la “gente normal” puede excluir a algunos lectores. Me dieron ganas de señalarlo justo porque parece que de verdad te importa bastante la experiencia y las necesidades de quienes usan ayudas de accesibilidad.
Después de probar directamente el selector de fecha de Safari entendí lo limitado que es. Pero siempre me he preguntado por qué los sitios reemplazan el selector nativo de fecha con un widget de calendario.
¿No se podría poner el widget de calendario junto al widget nativo? La UI podría volverse confusa al parecer que hay dos formas de entrada, pero con una etiqueta adecuada que marque uno como selector de fecha avanzado, parece que debería haber alguna forma de resolverlo. Así no se perdería a quienes usan cómodamente el selector nativo, y también se ayudaría a quienes el selector del navegador les queda corto.
Entiendo que en webapps como herramientas de documentación o editores de diagramas se necesite un menú contextual, pero sigue siendo molesto que al hacer clic derecho desaparezca el menú general del navegador. Por eso normalmente dejo
dom.event.contextmenu.enabled = falseen la configuración de Firefox. Así aparece encima el menú de Firefox y detrás el de la webapp, pero como el menú nativo funciona, termina siendo una solución aceptable. Si es posible, es mejor usar la barra de menús de la webapp y no tocar el menú contextual nativo del navegador. El tip de Shift+clic derecho también es una buena solución.La gente que necesita controles accesibles también es gente normal.
Se pueden ver casos de campos de contraseña implementados por cuenta propia en casi todos los bancos de Perú.
Me gustaría usar selectores de fecha nativos, pero del lado de quienes los implementan no parece haber mucho interés en mejorarlos. Firefox tiene problemas abiertos sobre la UI de selección de hora/reloj y avanzan lento: https://bugzilla.mozilla.org/show_bug.cgi?id=datetime
En formularios web, es un buen punto. Confiar en el navegador es la forma más simple, rápida y casi siempre la más consistente.
Pero en el caso del código criptográfico es distinto. Escribir código criptográfico correcto no es fácil, pero tampoco es imposible. En algunas situaciones hay tan pocas opciones que hacerlo uno mismo puede ser lo mejor.
El problema de la ortodoxia de seguridad aquí es la tendencia a asumir que para escribir nuevo código criptográfico tienes que pertenecer a su círculo interno. Como si no pudieras escribir código cripto a menos que mostraras un doctorado en criptografía o una pasantía con DJB o Dan Boneh. “Para aprender” está bien, pero aplicar en la práctica lo aprendido ya no. Incluso a veces parecen tener dificultades para reconocer la capacidad real de gente fuera de ese grupo. Curiosamente, la superposición entre esos ortodoxos de seguridad y los criptógrafos reales que publican papers parece ser muy pequeña.
Ahora eso incluso se está extendiendo a decir que no se debería escribir nada en lenguajes que no sean memory-safe. Aunque el 70% de las vulnerabilidades críticas sean de ese tipo, ¿cuál fue la causa real? Yo diría que la mayoría vino de usar
malloc()onewexplícito para cada objeto pequeño que no estaba en el stack, o de manejar cadenas terminadas en null. Si hubieran usado arenas y slices, esos problemas habrían sido mucho menos frecuentes. Claro, en algunos escenarios de alto riesgo sí hay que eliminar por completo ciertas clases de bugs, y ahí la seguridad de memoria es prioridad.¿Lo siguiente será no escribir nada que procese entrada no confiable? ¿No volver a inventar la rueda aunque todas las ruedas existentes sean cuadradas? Aun así, si evitas inflar JavaScript y usas los formularios que ofrece el navegador, no creo que haya mucho problema incluso en hacer tu propio framework web.
Creo que el pecado original de C está en que al pasar arreglos se pierde la información del límite superior y colapsan a punteros.
Siempre entendí “no implementes tu propia criptografía” no como un mandato absoluto, sino como una advertencia fuerte. Es verdad que se puede implementar con seguridad sin tener un doctorado, pero aun así hace falta aprender muchísimo.
Si solo se trata de implementar una especificación con cuidado, tal vez haga falta bastante menos. Pero la mayoría del software quiere implementaciones criptográficas rápidas, y entonces la complejidad sube muchísimo. La vulnerabilidad de Monocypher enlazada también es un buen ejemplo. De repente necesitas entender cómo se conectan la equivalencia birracional, los puntos Edwards y la Montgomery ladder.
Credenciales como un doctorado ayudan a que otros confíen en que sabes lo que haces. Las auditorías son otra vía. Monocypher, por lo visto, fue auditado por dos doctores de Cure53. El problema es que la mayoría de los programadores no está preparada para juzgar si una librería criptográfica es segura, así que terminan dependiendo de señales no técnicas como las credenciales o las credenciales de los auditores. Ojalá hubiera una forma más directa, pero las credenciales funcionan bastante bien.
Claro que es posible escribir criptografía propia. Si no lo fuera, no existirían las librerías criptográficas. La cuestión no es si se puede hacer, sino si tú o yo podríamos confiar en criptografía hecha a mano por nosotros mismos en un entorno de producción donde se hashean contraseñas de usuarios y se protegen datos privados. Yo no confiaría.
En un trabajo anterior, código viejo usaba MD5 para validación de licencias, y como había que verificarlo en un entorno donde no se podía ejecutar el viejo código C++, tuve que reimplementar MD5. Encontré librerías existentes, pero ninguna soportaba cambiar el IV.
Yo no tendría el valor de escribir criptografía propia, pero sí me parece que la industria de seguridad ahora se está yendo un poco al extremo al decir que ni siquiera deberías hacer tu propia autenticación.
Ojalá los navegadores ofrecieran un campo de selección múltiple usable sin tener que implementarlo uno mismo.
Recibir fecha de inicio y fecha de fin con dos `` es engorroso para un rango de fechas y tampoco es intuitivo. Divide algo que conceptualmente es uno solo en dos vistas separadas que visualmente ni siquiera parecen relacionadas.
Que no haya rangos de fechas es solo uno de varios problemas de ``. Por ejemplo, no se pueden excluir fechas específicas, así que en casi cualquier servicio de reservas ya queda descartado desde el arranque.
Dudo que la postura dominante sea aceptar el pequeño costo de dos inputs para tener fechas escritas de la misma forma en todas partes. Al usuario promedio no le gustan los campos, y si uno ya es malo, dos son peor. Tampoco me convence mucho el argumento de la familiaridad. En mi experiencia, la entrada nativa de fechas en la web es rara.
He visto varios sitios con dos widgets de calendario personalizados que ni siquiera funcionaban bien por separado para la fecha de inicio y la de fin. Peor todavía.
Yo tampoco estaba de acuerdo con la parte del rango de fechas. Suelo usar los rangos de fechas como ejemplo de un control que conceptualmente es único, pero que en la práctica puede ser muy complejo. El lema de “usa siempre controles nativos” puede empeorar la experiencia de usuario cuando puedes ofrecer un control mejor, más específico para el problema.
Una función útil en controles de fecha/rango de fechas que no se puede implementar de forma nativa es mostrar precios. Cuando buscas vuelos u hoteles, es muy útil ver directamente en el selector qué días son más baratos o más caros. Con un control nativo tendrías que hacer muchos más clics o mirar una tabla aparte para ver esa información, mientras que un control personalizado puede adjuntar ese tipo de metadatos a cada fecha.
El ejemplo clásico es ingresar fecha de nacimiento. Los selectores de fecha normalmente muestran por defecto el mes actual, que casi no tiene relación con la fecha buscada, así que es pésimo. Aquí podrías usar un control personalizado, pero muchas veces una combinación de cajas de texto es mejor. No es tanto un control totalmente propio como una combinación de controles nativos, pero el punto es que no existe un selector de fecha “universal” que resuelva bien todos los casos.
Tendría que volver a revisar porque fue hace años, pero había una razón lamentable por la que no quedaba otra que implementar en lugar de usar el selector de fecha de html5. La UI de `` en algunos navegadores era realmente horrible.
Implementar un menú contextual propio es raro, pero cuando hace falta es muy útil. Por ejemplo, si haces un editor de diagramas dentro de una página web, me gustaría que hubiera un menú contextual personalizado al hacer clic sobre los nodos del diagrama para poder realizar acciones útiles. No está bueno meter toda la interacción en una UI de clic izquierdo, por ejemplo alternando entre una paleta de acciones y los nodos.
Con el resto de la lista estoy muy de acuerdo.
No sé bien cómo interpretar juntos el ejemplo de criptografía y el problema del comportamiento del scroll. Me parecen ámbitos muy distintos.
Sí estoy de acuerdo con la idea general de que los sitios web hacen demasiadas cosas. Pero ese comportamiento depende de los objetivos del usuario y del sitio.
Tal vez algo como prefers-reduced-motion, pero para
prefers-user-scroll, podría ser una solución intermedia.No hay ningún caso de uso legítimo para usar scrolljacking al implementar un área de scroll vertical. Ese código nunca debió escribirse.
Dicho eso, esto aplica específicamente a áreas de scroll vertical. Cuando se remapea el scroll a un comportamiento que no es scroll, sí hay casos de uso, y aunque sigue siendo muy problemático, también podría discutirse el caso de mapear vertical a horizontal en sistemas de escritura vertical. Además de eso, quizá haya uno o dos casos legítimos más, pero la forma en que normalmente se implementa sigue estando mal.
Estoy muy de acuerdo con no implementar el desplazamiento de página por cuenta propia. En KotlinConf escuché una charla interesante sobre las dificultades de implementar scroll en Compose Multiplatform for Web.
Uno de los problemas era que los navegadores web envían menos eventos de scroll que una app nativa, así que falló el algoritmo para calcular la dirección del scroll. Dibujaban una parábola que pasaba por todos los puntos y usaban la pendiente en el último punto, pero si había muy pocos puntos, la dirección del scroll podía salir invertida.
Al portar desde otra plataforma o al reimplementar este tipo de interacción, es fácil partir de supuestos incorrectos u olvidarse de comportamientos “raros” que el navegador sí trae por defecto.
El consejo de “apóyate en la plataforma” es correcto, pero seguirle el ritmo a la plataforma es difícil. Hay cosas como
enterkeyhintoinputmodecuya existencia más o menos uno recuerda, pero se olvida del efecto.Esta semana nuestro equipo publicó [0] para ayudar con eso. Ofrece buenas prácticas de implementación en forma de skills. La documentación también se deja leer bastante bien. Ej.: [1]
[0] https://github.com/GoogleChrome/modern-web-guidance [1] https://github.com/GoogleChrome/modern-web-guidance/…
El tono del texto no encaja. Sería mucho más productivo explicar lo suficiente para que la gente entienda cuándo y por qué no hace falta reinventar la rueda.
El texto explica bien las razones, pero empeora por la forma tajante de decir “no lo hagas tú mismo”.
El lema de “no implementes tu propia criptografía” también termina sonando a dogma. ¿Quiénes son los expertos autorizados para decir eso y quién los nombró? ¿Miraron el código ellos mismos antes de afirmarlo? Si vemos vulnerabilidades como Heartbleed, ¿no queda claro que en la práctica eran errores bastante básicos?
Son personas que le han dedicado su vida a la criptografía. Nadie las nombró: se ganaron esa autoridad publicando investigación útil y pasando por la validación de quienes conocen el área.
Los algoritmos son públicos, se revisan, se atacan públicamente, se mejoran y se estandarizan. No es algo que ocurra a puerta cerrada. Los papers son públicos y el código también. Puedes mirarlo cuando quieras. Que tú no lo hayas visto no significa que nadie lo haya hecho. La gente lo revisa e intenta romperlo. La razón por la que lo usamos es que ha resistido ataques.
Si al ver Heartbleed tu solución es reimplementar OpenSSL por tu cuenta, te garantizo que tu OpenSSL tendría cincuenta Heartbleeds por cada uno del OpenSSL real. La diferencia es que el OpenSSL real lo revisa gente que sabe, lo prueba, lo audita, lo ataca y lo corrige. El tuyo simplemente quedará mal hecho en privado.
La cuestión no es que exista un experto perfecto capaz de invocar AES sin miedo. Es que si usas un wrapper popular que funciona de forma segura, si aparece un bug puede descubrirse y corregirse en un solo lugar.
Incluso si se descubre un nuevo ataque por canal lateral, se puede responder en un solo lugar. Lo que hiciste por tu cuenta no recibe ese tipo de mejoras a menos que dediques tiempo completo a seguir cada ataque nuevo.
Esto se parece más a una queja contra gente que usa muy mal las herramientas web. Habría sido más interesante si también tratara casos en los que implementar por cuenta propia sí es válido. Así el lector podría aprender algo útil, en vez de quedarse con el modelo infantil de “nunca lo hagas tú mismo”.
La pericia consiste en tener el conocimiento y la habilidad para construirlo uno mismo, y a la vez la sabiduría para saber cuándo no hacerlo.
Aun así, simpatizo con la frustración. Yo también he tenido quejas parecidas. El problema es que no ha habido mucho esfuerzo por documentar las interacciones web de forma lo bastante exhaustiva y completa como para que los desarrolladores web puedan consultarlas fácilmente. Hay un problema serio con el conocimiento adyacente a la programación: no se documenta bien ni se transmite a la siguiente generación, así que seguimos redescubriendo los mismos problemas. Normalmente dentro de la industria se termina imponiendo un conjunto estándar de comportamientos e interacciones, pero nadie lo deja por escrito.