Feeds, sitemap y una cabecera que sobra: pequeña auditoría de un sitio WordPress con curl

curl

Valencia, 08/09/2026, G.B.
Hay comandos que uno lanza casi por rutina y que, sin embargo, acaban destapando cosas interesantes. La semana pasada me tocó revisar el sitemap nativo de uno de mis sitios en WordPress y, de paso, aproveché para repasar algo que tenía pendiente desde hace tiempo: los feeds del sitio y una cabecera HTTP que no debería estar ahí.

Qué es el feed de un sitio en WordPress

El feed es una versión del contenido en XML —normalmente RSS 2.0, aunque WordPress también sabe hablar Atom— pensada para que lectores de noticias, agregadores o scripts consuman las entradas sin tener que «leer» el HTML de la página. Es una de esas piezas del núcleo de WordPress que llevan ahí desde siempre y que casi nadie mira hasta que algo deja de funcionar (a mí me pasó hace poco con un gadget de Blogger de terceros que dejó de refrescar entradas porque un Disallow: */feed/ en el robots.txt se lo estaba impidiendo).

Lo interesante es que WordPress no genera un único feed, sino uno por cada «vista» relevante del sitio:

  • Feed general, con todas las entradas: /feed/
  • Feed de comentarios de todo el sitio: /comments/feed/
  • Feed de una categoría: /category/nombre-categoria/feed/
  • Feed de una etiqueta: /tag/nombre-etiqueta/feed/
  • Feed de un autor: /author/nombre-autor/feed/
  • Feed de comentarios de una entrada concreta: /nombre-entrada/feed/
  • Feed de una búsqueda: /?s=termino&feed=rss2
  • Feed de un tipo de contenido personalizado, si el CPT lo soporta: /tipo-contenido/feed/

Y todavía hay una capa más: dentro de cada uno de esos ámbitos, el formato de salida se puede forzar con el parámetro ?feed=, con hasta cuatro variantes: rss2 (el que usa WordPress por defecto), rss (RSS 0.92, un formato ya legado), atom y rdf (RSS 1.0). En total, contando ámbitos y formatos, un sitio WordPress típico expone bastantes más «puertas de entrada» XML de las que uno recuerda a primera vista.

El sitemap no es un feed

Conviene no confundir los feeds con el sitemap. Desde WordPress 5.5 (2020), el núcleo genera automáticamente un sitemap XML nativo en /wp-sitemap.xml, sin necesidad de plugins de SEO. No es RSS ni Atom: es un índice que agrupa entradas, páginas, taxonomías y usuarios en sub-sitemaps independientes (wp-sitemap-posts-post-1.xml, wp-sitemap-users-1.xml, etc.), pensado para que los buscadores rastreen el sitio de forma eficiente.

Para comprobar rápidamente si el sitemap responde bien, sin descargarlo entero, uso el comando curl:

curl -I https://midominio.com/wp-sitemap.xml

El -I fuerza una petición HEAD: solo pide las cabeceras HTTP de la respuesta, no el cuerpo. Es la forma más rápida de saber si una URL existe, qué código de estado devuelve y qué tipo de contenido sirve, sin gastar ancho de banda en el XML completo.

Lo que las cabeceras cuentan (y lo que delatan)

Al lanzar ese curl -I contra uno de mis sitios, obtuve algo así (he sustituido la versión de PHP que aparecía por X.X.XX en el código que adjunto por motivos de seguridad):

HTTP/2 200
content-type: text/xml;charset=UTF-8
date: Fri, 04 Sep 2026 06:42:34 GMT
server: Apache
x-powered-by: PHP/X.X.XX

Todo correcto salvo un detalle: x-powered-by: PHP/X.X.XX está anunciando al mundo, con número de versión exacto, qué motor PHP corre detrás. No es una vulnerabilidad en sí misma, pero sí información gratuita para cualquiera que esté buscando qué CVEs probar contra esa versión concreta. Es el tipo de cabecera que no aporta nada al visitante legítimo y sí algo a quien está reconociendo el terreno.

La buena noticia es que server: Apache ya venía sin número de versión, así que esa parte no hacía falta tocarla.

Cómo quitar la cabecera con php.ini

Yo tengo creado el archivo php.ini (o .user.ini) propio en el directorio del sitio. El mío ya incluía algunos ajustes habituales:

upload_max_filesize = 128M
post_max_size = 128M
max_execution_time = 300
memory_limit = 512M
zlib.output_compression = 1
zlib.output_compression_level = 9

Simplemente basta con añadir una línea más:

expose_php = Off

Tras guardar el archivo -y en algunos casos esperar unos minutos a que el hosting recargue la configuración- un nuevo curl -I me ha confirmado que la cabecera x-powered-by había desaparecido. Un cambio de una sola línea, pero de esos que conviene no dejar pendientes.

Resumiendo

  • Un sitio WordPress puede exponer más de media docena de feeds distintos, cada uno con hasta cuatro formatos posibles.
  • El sitemap nativo (/wp-sitemap.xml) es una pieza distinta, propia del núcleo desde la versión 5.5.
  • curl -I es la herramienta de cabecera rápida para auditar cualquier URL sin descargar su contenido.
  • Si tu hosting lo permite, expose_php = Off en tu php.ini o .user.ini es un cambio mínimo con un beneficio de seguridad nada despreciable.

Un plugin propio para aprender comandos básicos de Linux en WordPress

plugin comandos linux

Tal y como comentaba aquí, he preparado un pequeño plugin para mostrar comandos de Linux, para aprender, vaya. Insertaré el shortcode en una nueva página, en vez de en una entrada o post

Valencia, 06/09/2026, G.B.
Llevo tiempo trabajando en plugins a medida, sin dependencias externas, para cubrir necesidades muy concretas sin cargar el sitio con librerías de terceros. El último que he montado va dirigido a quien empieza con Linux: Comandos Linux, un plugin que permite gestionar una pequeña base de datos de comandos —con su explicación y un ejemplo práctico— y mostrarla en el front end mediante un shortcode.

Qué hace

El plugin crea su propia tabla en la base de datos con cuatro campos por registro:

  • Nombre del comando (ls, grep, chmod…)
  • Explicación, en lenguaje sencillo
  • Ejemplo práctico, listo para copiar y probar en terminal

Desde el panel de administración se pueden crear, editar y eliminar comandos con un formulario simple, y el listado incluye un buscador y paginación para cuando la lista crezca.

El shortcode

Para mostrarlo en cualquier entrada o página basta con insertar, entre corchetes []:

comandos_linux

El front end reproduce la misma lógica que el panel: buscador propio y resultados paginados, sin necesidad de recargar toda la página gracias a los parámetros por URL. Si se quiere ajustar cuántos comandos se muestran por página, se puede indicar con (entre corchetes []:

comandos_linux por_pagina="10"

Por qué así

Como en el resto de plugins que he ido publicando aquí, la idea es mantenerlo ligero: sin librerías externas, con consultas preparadas contra la base de datos, y siguiendo el patrón POST/Redirect/GET para evitar reenvíos accidentales de formularios. Es la misma filosofía que ya apliqué en el plugin de recursos o en el de autores: cubrir una necesidad concreta con el menor peso posible.

De momento arranca con comandos básicos como ls, cd, grep o chmod, pero la idea es irlo ampliando poco a poco a medida que vaya cubriendo más terreno, desde gestión de permisos hasta redes o procesos.

Así queda insertado el shortcode en una página  (iré añadiendo más y mejorándolo): Comandos Linux


Descargar el plugin desde mi cuenta de pCloud

Hooks, actions y filters en WordPress: la diferencia que todo el mundo confunde

Valencia, 05/09/2026, G.B.
Si llevas un tiempo tocando el functions.php de WordPress o escribiendo plugins, seguro que te has encontrado con add_action() y add_filter() mil veces. Pero cuando hay que explicar la diferencia entre ambos, es fácil quedarse en un «bueno, son parecidos». No lo son tanto, y entender bien la diferencia te ahorra bugs raros el día menos pensado.

Hook es el concepto general

Lo primero es aclarar la terminología. En español solemos traducir hook como «gancho», y es el término general que engloba a los otros dos: cualquier punto del código de WordPress donde puedes «engancharte» para ejecutar tu propia función. Ese término general se divide en dos tipos:

  • Actions (acciones)
  • Filters (filtros)

Todo lo demás son matices de estos dos tipos.

Actions: «haz algo aquí»

Una acción es un punto del código donde WordPress simplemente dice: «en este momento ha pasado algo, si quieres, ejecuta tu función». No espera que le devuelvas nada.

// Se ejecuta cada vez que se publica una entrada
add_action( 'publish_post', function( $post_id ) {
    wp_mail( 'admin@midominio.com', 'Nueva entrada publicada', 'ID: ' . $post_id );
});

Aquí no hay ningún dato que recoger de vuelta. La función hace su trabajo (enviar un correo, escribir un log, mostrar algo en pantalla) y punto.

Filters: «toma este dato, modifícalo y devuélvemelo»

Un filtro, en cambio, existe porque WordPress necesita un valor para seguir funcionando: un título, un contenido, un booleano que decide qué hacer. Tu función recibe ese valor, opcionalmente lo cambia, y tiene que devolverlo siempre.

// Añade un emoji al final de cada título
add_filter( 'the_title', function( $title ) {
    return $title . ' 🚀';
});

Si te olvidas del return, rompes el filtro para todo el sitio — es el error clásico de quien empieza con filtros viniendo de acciones.

La tabla que lo resume

ActionFilter
¿Qué hace?Ejecuta código en un punto concretoModifica un dato y lo devuelve
¿Recibe un valor?Opcionalmente, como parámetrosSí, el dato a modificar
¿Debe devolver algo?NoSiempre
Ejemplo típicoEnviar un email al publicar una entradaCambiar el texto de un título

Una forma rápida de identificarlos si estás leyendo código fuente de WordPress: si ves do_action(...), es un hook de tipo acción; si ves apply_filters(...), es un filtro. Y add_action() / add_filter() son las funciones que usas tú para «engancharte» a esos puntos.

Un ejemplo real: desactivar el editor de bloques

El otro día leí un artículo de Ayudawordpress.com (Fernando Tellado) sobre cómo desactivar el editor de bloques de WordPress (Gutenberg) para desactivarlo en una instalación multisitio. El filtro que se usa es un buen ejemplo de por qué tiene que ser un filter y no una action:

add_filter( 'use_block_editor_for_post_type', '__return_false' );
add_filter( 'use_widgets_block_editor', '__return_false' );

WordPress necesita saber, para cada tipo de contenido, si debe cargar el editor de bloques o el clásico — y eso es exactamente un booleano que hay que devolver. Por eso no podría implementarse como acción: una acción no tiene forma de decirle a WordPress «no, usa esto otro en su lugar». Necesita el mecanismo de ida y vuelta que ofrece el filtro.

Por qué merece la pena tenerlo claro

Más allá de la teoría, esto tiene una consecuencia práctica muy directa: si alguna vez te preguntas «¿por qué mi función no está haciendo efecto?», una de las primeras cosas que hay que revisar es si te has enganchado a una acción cuando en realidad necesitabas un filtro (o viceversa). Es un error tonto, pero muy común, y entender la diferencia de raíz evita perder tiempo depurando algo que en realidad es un fallo de concepto, no de sintaxis.

Once in a lifetime, again…

Momentos musicales…

De vez en cuando, dependiendo de mi estado de ánimo, me gusta («necesito»…) volver  a ecuchar esta canción de Talking Heads, en concreto Once in a Lifetime

¿Por qué? Porque ya soy muy mayor y estoy bastante desilusionado de como van las cosas. Pero la música es, y siempre será, una vacuna contra la insidia de la vida cotidiana, de la rutina,. Y sí, sé que no debemos quejarnos….

Aquí va de nuevo. Disfrutadla los que estéis en mi estado emocional, y los que no también… Esto es  un momento especial para mí; momentos musicales. Ahora sí, aquí va:

PD. Un pequeño artículo en Focus on Learning English sobre la expresión «into the blue again«, Spoiler: esto es crossblogging…

GentleOS: el sistema operativo que resucita ordenadores de los años 80

GentleOS es un proyecto creado por el desarrollador Luke S. (luke8086) capaz de arrancar un escritorio gráfico completo en PCs de hace más de 40 años. Existen dos variantes: GentleOS/32, para máquinas i386 con solo 4 MB de RAM, y GentleOS/16, aún más ligero, que funciona en procesadores 8086/80186 de 1978-1982 con apenas 192 KB de RAM y gráficos CGA.

No requiere disco duro ni conexión a internet: todo corre en memoria y arranca casi al instante, a costa de renunciar a multitarea, red o almacenamiento persistente. Es software libre bajo licencia GPLv2.

📥 Descarga:
GentleOS/32
GentleOS/16

🔗 Fuente: ComputerHoy (20minutos)

De solución casera a plugin: Indaga Menu Search ya funciona también en Puntocomunica.com

Valencia, 03/09/2026, G.B.
Ayer os contaba cómo había sustituido Ivory Search por un buscador propio, integrado directamente en el menú mediante unas pocas líneas en el functions.php del child theme de INDAGA.net. Funcionaba bien, pero tenía una limitación evidente: estaba atado a este sitio en concreto. Si quería el mismo buscador en otra web, tocaba copiar y pegar código a mano, sitio por sitio.

Así que le he dado una vuelta y lo he convertido en un plugin independiente: Indaga Menu Search.

Por qué merecía la pena convertirlo en plugin

El código en sí no cambia demasiado —sigue usando exclusivamente el buscador nativo de WordPress, sin dependencias externas ni llamadas remotas—, pero empaquetarlo como plugin da varias ventajas:

  • Se activa y desactiva desde el panel, sin tocar el functions.php de ningún tema.
  • Sobrevive a un cambio de tema, porque el código ya no vive dentro del child theme.
  • Es reutilizable en cualquier proyecto WordPress, no solo en los que usan Twenty Seventeen.
  • La ubicación del menú se elige desde una pantalla de ajustes (Ajustes → Buscador en el menú), con un desplegable que muestra las ubicaciones que registra el tema activo y qué menú tiene asignado cada una. Nada de shortcodes ni de editar código: se elige la ubicación y el icono aparece automáticamente en todo el sitio.

Para quien quiera forzarlo por código en un proyecto concreto, sigue existiendo el filtro indaga_menu_search_location, que tiene prioridad sobre lo que se elija en el panel.

Primera instalación real: Puntocomunica.com

La primera prueba fuera de INDAGA.net ha sido en Puntocomunica.com, donde lo he instalado y activado sin ningún ajuste adicional más allá de seleccionar la ubicación del menú correspondiente desde el panel. En cuestión de minutos, el buscador nativo de WordPress estaba ya funcionando ahí también, con el mismo comportamiento: icono discreto en el menú que despliega el formulario de búsqueda al pulsarlo.

Poder instalar el mismo plugin en dos sitios completamente distintos, sin adaptar una sola línea de código más allá de un clic en un desplegable, es exactamente el objetivo de convertir una solución puntual en una herramienta reutilizable.

Descargar plugin de mi cuenta de pCloud

Adiós a Ivory Search: cómo he puesto un buscador propio en el menú de INDAGA.net

Valencia, 02/09/2026, G.B.
Desde hace tiempo, el buscador de INDAGA.net dependía de un plugin llamado Ivory Search. Funcionaba bien… hasta que ha dejado de hacerlo. Empezó a fallar sin motivo aparente, y en vez de perder horas depurando un plugin de terceros, decidí hacer lo que suelo hacer con este tipo de problemas: prescindir de él y montar algo propio, ligero y sin dependencias externas. Aquí os cuento el proceso completo, con sus vueltas incluidas.

El punto de partida

WordPress trae de serie un buscador nativo perfectamente funcional: el clásico ?s= que consulta directamente la base de datos a través de WP_Query. No necesita ningún plugin. Lo único que hacía falta era darle un sitio visible en la web, concretamente un icono en el menú de navegación que, al pulsarlo, desplegara el cuadro de búsqueda.

Como ya tengo un child theme de Twenty Seventeen (Indaga Child lo he llamado) con código PHP propio, la solución más limpia era añadir el buscador ahí mismo, aprovechando los hooks que ofrece WordPress para modificar el menú.

El código: un filtro y un poco de CSS

WordPress permite enganchar contenido extra a cualquier menú mediante el filtro wp_nav_menu_items. Con esto añadí un elemento más a la lista del menú: un botón con el icono de lupa (usando Dashicons, la librería de iconos que trae WordPress) y, justo debajo, el formulario de búsqueda nativo oculto por defecto:

add_filter('wp_nav_menu_items', 'indaga_add_search_to_menu', 10, 2);
function indaga_add_search_to_menu($items, $args) {
    if (isset($args->theme_location) && $args->theme_location === 'top') {
        $search_html  = '<li>';
        $search_html .= '<button type="button" aria-expanded="false" aria-controls="menu-search-form" aria-label="Abrir buscador">';
        $search_html .= '<span class="dashicons dashicons-search"></span>';
        $search_html .= '</button>';
        $search_html .= '<div id="menu-search-form">';
        $search_html .= get_search_form(false);
        $search_html .= '</div>';
        $search_html .= '</li>';

        $items .= $search_html;
    }
    return $items;
}

Este filtro lo añadí directamente al functions.php de mi child theme, junto al resto de funciones personalizadas que ya tenía (como el aviso de tiempo de lectura o la notificación por correo al publicar). Es el mismo archivo donde centralizo todo el código propio del tema.

El CSS se encarga de que el formulario permanezca oculto hasta que se pulsa el icono. Para el comportamiento de abrir y cerrar (toggle), en vez de meter el JavaScript directamente en el footer, preferí crear un archivo aparte: assets/js/menu-search-toggle.js, dentro de la carpeta del child theme. Mantener el JS en su propio archivo, en vez de incrustarlo en línea, hace que sea más fácil de mantener y que el navegador pueda cachearlo por separado.

document.addEventListener('DOMContentLoaded', function () {
    var toggleBtn = document.querySelector('.search-toggle-btn');
    var searchForm = document.querySelector('.menu-search-form');

    if (!toggleBtn || !searchForm) return;

    toggleBtn.addEventListener('click', function () {
        var isOpen = searchForm.classList.toggle('is-open');
        toggleBtn.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
        if (isOpen) {
            var input = searchForm.querySelector('input[type="search"]');
            if (input) input.focus();
        }
    });

    document.addEventListener('click', function (e) {
        if (!searchForm.contains(e.target) && !toggleBtn.contains(e.target)) {
            searchForm.classList.remove('is-open');
            toggleBtn.setAttribute('aria-expanded', 'false');
        }
    });
});

Para que WordPress cargue ese archivo, hace falta encolarlo correctamente, también desde functions.php, en vez de simplemente enlazarlo a mano:

add_action('wp_enqueue_scripts', 'indaga_enqueue_search_toggle_script');
function indaga_enqueue_search_toggle_script() {
    wp_enqueue_script(
        'indaga-menu-search-toggle',
        get_stylesheet_directory_uri() . '/assets/js/menu-search-toggle.js',
        array(),
        wp_get_theme()->get('Version'),
        true
    );
}

Usar wp_get_theme()->get('Version') como número de versión del script tiene una ventaja práctica: cada vez que subo cambios al JS y actualizo la versión del child theme, WordPress invalida automáticamente la caché del navegador para ese archivo, evitando que se quede una versión antigua cacheada, tal y como ya hacía con el CSS.

El primer obstáculo: identificar el menú correcto

WordPress diferencia entre el nombre visible de un menú (el que ve el administrador en el panel, en mi caso «Principal (2)») y su theme_location, que es el identificador interno que usa el tema para saber dónde pintarlo. Son cosas distintas, y confundirlas es un error habitual.

Como Twenty Seventeen solo registra dos ubicaciones —top (menú superior) y social (redes sociales)— y mi child theme no añade ninguna ubicación propia, bastaba con usar top en el filtro. Lo confirmé revisando directamente el código fuente del tema en su repositorio oficial, sin necesidad de tocar nada en el servidor.

El segundo obstáculo: el icono invisible

Con el código subido, el HTML del icono aparecía correctamente en el código fuente de la página (lo comprobé viendo el código fuente del navegador), pero visualmente no se veía nada en el menú. Aquí es donde toca ser metódico:

¿Está el HTML presente? Sí, confirmado.

¿Puede ser la caché? Casi seguro. Uso Autoptimize para combinar y minificar CSS y JS, y si no se regenera bien después de subir cambios, el navegador sigue sirviendo la versión antigua.

¿Y si el icono está ahí pero es «invisible» por color? Bingo. El icono de la lupa (Dashicons) no heredaba el color blanco del resto del menú, así que se confundía con el fondo. Solo se veía al pasar el ratón por encima, porque el estado hover sí forzaba un cambio de color.

Intentar arreglarlo fijando color: #ffffff en el botón no fue suficiente: el pseudo-elemento que dibuja el icono de la fuente Dashicons no siempre hereda el color tan limpiamente como cabría esperar, sobre todo cuando hay otras reglas CSS con más peso de por medio. La solución definitiva y más robusta fue añadir directamente un fondo oscuro al botón en el CSS personalizado del tema:

button {
    background: #000000;
    border: none;
    cursor: pointer;
    padding: 8px 12px;
    line-height: 1;
    color: #ffffff;
}

button .dashicons {
    color: inherit;
    font-size: 20px;
    width: 20px;
    height: 20px;
}

Con el fondo negro y el icono en blanco, el contraste queda garantizado sin depender de si el navegador hereda bien o mal el color de un pseudo-elemento de fuente.

El resultado

Un buscador funcional, integrado en el menú «Principal (2)», que usa exclusivamente el motor de búsqueda nativo de WordPress. Sin plugins de terceros que mantener, sin sorpresas de compatibilidad, y con el código totalmente bajo mi control para poder ajustarlo cuando quiera.

Brave Accounts y Email Aliases: contraseñas que nunca viajan y correos que nunca se revelan

brave

Valencia, 01/09/2026, G.B.
Brave acaba de presentar Brave Accounts, un nuevo sistema para iniciar sesión en sus servicios que cambia por completo la forma en que se gestionan las contraseñas. La promesa, resumida en una frase: tu contraseña nunca llega a los servidores de Brave. Ni cifrada, ni convertida en hash, ni «guardada un instante en memoria y luego descartada». Directamente, no se transmite.

Sobre esa base ha llegado ya el primer servicio propio: Email Aliases, que permite registrarte en cualquier web sin dar tu correo real. En este artículo vamos a ver cómo funciona la criptografía detrás de Brave Accounts y qué ofrece exactamente Email Aliases.

El problema de siempre: el instante en que tu contraseña queda expuesta

Cuando inicias sesión en cualquier web convencional, el navegador abre una conexión TLS que cifra la contraseña mientras viaja por la red. Hasta ahí, todo bien. El problema aparece cuando esa contraseña llega al servidor: en algún punto —a menudo en un balanceador de carga o un CDN, antes incluso de que la aplicación la vea— la conexión se descifra y la contraseña queda en texto plano, aunque sea solo por una fracción de segundo.

Ese instante es la grieta. Ahí es donde puede colarse cualquier cosa: un log mal configurado que escribe cuerpos de petición en disco, una dependencia comprometida en la ruta de autenticación, un empleado malintencionado, un atacante haciendo scraping de memoria.

Podrías pensar: ¿y si el navegador calcula el hash y solo envía eso? El problema es que, si haces eso, el hash se convierte en la contraseña: cualquiera que robe la base de datos podría reenviar ese hash directamente al servidor y autenticarse sin saber la contraseña real. La verificación tiene que hacerse contra el valor auténtico, así que ese valor auténtico tiene que entregarse en algún momento. O eso se creía.

Y luego está el escenario de filtración masiva. El caso de LinkedIn en 2012 sigue siendo el ejemplo de manual: contraseñas guardadas como SHA-1 sin sal (salt), un hash rápido y sin ninguna variación entre usuarios. La filtración inicial se estimó en 6,5 millones de cuentas; cuatro años después, al aparecer el volcado completo, resultaron ser 117 millones, y prácticamente todas se descifraron en cuestión de días porque contraseñas idénticas producían hashes idénticos.

La solución: el protocolo OPAQUE

Brave Accounts se apoya en OPAQUE, un protocolo de intercambio de claves autenticado por contraseña (aPAKE, por sus siglas en inglés) desarrollado por los investigadores Jarecki, Krawczyk y Xu, estandarizado por el IRTF y publicado como RFC 9807 en julio de 2025. Cuenta con una prueba formal de seguridad en un modelo criptográfico robusto (universally composable).

La idea central: cliente y servidor ejecutan una especie de «baile» criptográfico en el que el cliente demuestra que conoce la contraseña sin revelarla en ningún momento, y ambas partes terminan compartiendo una clave de sesión nueva. Todo esto se apoya en curvas elípticas, así que es rápido y transparente para el usuario.

Cómo funciona

Registro. Cuando eliges tu contraseña, tu dispositivo y el servidor ejecutan conjuntamente una función pseudoaleatoria oblivious (OPRF): tú «enmascaras» tu contraseña con un valor aleatorio y envías esa versión enmascarada; el servidor aplica una clave secreta propia y te devuelve el resultado; tu dispositivo lo desenmascara. El valor final depende tanto de tu contraseña como del secreto del servidor, pero ninguno de los dos ha visto el dato del otro.

Tu dispositivo pasa después ese valor por Argon2id (una función de derivación resistente a fuerza bruta) y lo combina con un nonce aleatorio para generar un par de claves de autenticación. Lo único que se envía al servidor es una clave pública, una clave de enmascarado y un pequeño «sobre» (envelope) con el nonce y una etiqueta de autenticación. Nada de eso sirve de nada sin la contraseña original.

Inicio de sesión. Al volver a escribir la contraseña, el mismo baile OPRF reproduce el mismo valor si la contraseña es correcta. El servidor devuelve el envelope guardado; el dispositivo lo desenmascara, regenera el par de claves y comprueba la etiqueta de autenticación. Si la contraseña era correcta, todo encaja y ambas partes negocian una clave de sesión mediante un intercambio autenticado. Si era incorrecta, las claves derivadas simplemente no cuadran, y nada sensible llega a viajar por la red.

Por qué es importante

  1. No hay contraseña en texto plano en ningún momento, así que se eliminan de raíz los escenarios de logs filtrados, memoria comprometida o insiders curiosos.
  2. Se acaba la precomputación de diccionarios. Como parte de la derivación depende de un secreto que solo tiene el servidor, un atacante no puede preparar tablas de contraseñas por adelantado: necesita robar la base de datos y el secreto del servidor, y aun así el ataque tiene que hacerse cuenta por cuenta, contra una función de derivación costosa en memoria (Argon2id).
  3. OPAQUE no es solo un login: es una primitiva de acuerdo de claves. El protocolo también genera una export key, un secreto derivado de la contraseña que el servidor jamás llega a conocer. Esa clave se puede usar para cifrado extremo a extremo — es, de hecho, un mecanismo parecido al que usa WhatsApp para cifrar las copias de seguridad de chats protegidas con contraseña.

Brave ya apunta a construir sobre esto su próxima versión de Sync: en lugar del actual emparejamiento por código QR, será posible iniciar sesión con la cuenta de Brave para sincronizar un dispositivo nuevo con cifrado extremo a extremo. Eso sí, la sincronización sin cuenta seguirá disponible para quien no quiera crear una.

Lo que OPAQUE no resuelve

Conviene ser honestos con las limitaciones, que Brave reconoce en su propio anuncio:

  • No protege frente al phishing. Si el atacante controla la página o la app donde escribes tu contraseña, puede capturarla antes de que el protocolo entre en juego.
  • No convierte una contraseña débil en una fuerte. «password123» sigue cayendo ante un ataque de fuerza bruta online, de ahí que Brave Accounts limite los intentos y exija contraseñas razonablemente robustas.
  • Un compromiso total del servidor sigue siendo un riesgo. Un atacante decidido podría, en ese escenario, intentar un ataque de diccionario offline cuenta por cuenta. OPAQUE lo hace mucho más lento y no paralelizable entre usuarios, pero no lo hace imposible.

El primer servicio construido sobre Brave Accounts: Email Aliases

Brave Accounts no es un fin en sí mismo, sino la base sobre la que Brave empieza a construir servicios propios. El primero en llegar, integrado directamente en el navegador desde la versión 1.94.117 (27 de agosto de 2026), es Email Aliases.

La idea es sencilla y no del todo nueva —servicios como SimpleLogin, Firefox Relay o Hide My Email de Apple llevan tiempo ofreciendo algo parecido—, pero aquí llega sin necesidad de extensión ni suscripción: al rellenar el campo de correo de cualquier formulario de registro, Brave ofrece generar una dirección de alias de un solo uso para ese sitio. Los mensajes que lleguen a esa dirección se reenvían automáticamente a tu correo real, que el sitio web nunca llega a conocer.

¿Por qué importa esto? Porque, a diferencia de una cookie, el correo electrónico es un identificador que te sigue entre dispositivos, navegadores y servicios. Aunque Brave ya aísla lo que cada web puede almacenar en el navegador (cookies y caché particionados por sitio), eso no evita que dos empresas crucen datos por su cuenta usando tu email como nexo común. Ahí es donde entra este servicio: al usar una dirección distinta para cada sitio, rompe ese enlace de rastreo entre servicios y, de paso, facilita cortar el grifo si una dirección empieza a recibir spam — basta con desactivar ese alias concreto sin tocar tu bandeja principal.

Cómo funciona en la práctica:

  • Hace falta una cuenta de Brave (gratuita) con tu correo real vinculado.
  • Los alias se generan al pulsar sobre un campo de email en una web, o eligiendo «Nuevo alias de correo» desde el menú contextual.
  • Se gestionan desde Configuración → Autocompletar y contraseñas → Email Aliases. También escribiendo en la barra de direcciones brave://settings/email-aliases
  • Brave ofrece cinco alias gratuitos por ahora; la compañía ha anunciado que llegará un nivel de pago sin ese límite, además de soporte para móvil próximamente.
  • Los mensajes reenviados pasan por un filtro automático de spam y malware, y se borran de los servidores de Brave a los pocos segundos de entregarse.
  • Las notas que añadas a cada alias se guardan solo en local, salvo que actives Brave Sync, en cuyo caso viajan cifradas de extremo a extremo.

Vale la pena avisar de un matiz práctico: al ser un servicio de correo nuevo, es posible que durante los primeros tiempos algunos mensajes reenviados caigan en la carpeta de spam del destinatario, mientras Brave construye reputación como remitente.

email aliases

Cómo probarlo

Ambas funciones ya están disponibles en el canal estable de escritorio, pero solo a partir de la versión 1.94.117. Si tu Brave es más antiguo (como me pasó a mí, que estaba en la 1.93.136), no verás el banner de creación de cuenta ni la opción de alias hasta actualizar: ve a brave://settings/help para forzar la comprobación de actualizaciones, reinicia el navegador y después entra en brave://settings/getStarted para crear tu cuenta. Desde ahí, el alias de correo se ofrece directamente al rellenar cualquier formulario de registro.

La versión de escritorio es la misma para Windows, macOS y Linux —solo cambia el empaquetado (.exe, .dmg/.pkg, .deb/.rpm)—, así que la actualización llega a todos por igual, aunque en Linux con paquetes de terceros (Flatpak, Snap) el ritmo puede variar algo respecto al repositorio oficial APT.


Fuentes: Blog oficial de Brave — Brave Accounts y Blog oficial de Brave — Email Aliases

Clementine, mi reproductor de música en Linux

clementine
  • Ahora mismo escuchando una canción en Clementine que grabé con mi hermano Gianni: «Tasmanian Blues»… Igual se me ocurre algún día subirla algún repositorio de música gratuito. Tendré que consultarlo. Ya veremos…

Valencia, 31/08/2026, G.B.
Llevo tiempo usando Clementine en mi Ubuntu MATE 22.04, y sigue siendo mi opción de cabecera para gestionar música local. Es un reproductor multiplataforma, gratuito y de código abierto, que nació en 2010 como bifurcación de Amarok 1.4, cuando ese proyecto dio el salto a una interfaz que a muchos no nos habría convencido.

Lo que más valoro de Clementine es justamente eso: mantiene una interfaz clásica, ligera y muy funcional, sin florituras innecesarias. Para quien viene de iTunes o del Amarok de toda la vida, resulta muy intuitivo.

Lo que ofrece:

  • Gestión de biblioteca musical local con portadas y etiquetas
  • Reproducción de streaming (SoundCloud, Jamendo, radios de internet)
  • Compatible con MP3, FLAC, OGG, WMA y más formatos habituales
  • Ecualizador, letras de canciones y sincronización con dispositivos MP3/iPod
  • Consumo de recursos muy contenido, algo que se agradece en equipos más modestos

Es software libre bajo licencia GPL, y aunque su ritmo de desarrollo se ha ralentizado respecto a sus años de mayor actividad (2010-2015), sigue recibiendo actualizaciones puntuales y cuenta con una comunidad fiel, sobre todo en el mundo Linux.

Web oficial: clementine-player.org