<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Pigu_ing</title><description>No description</description><link>https://fuwari.vercel.app/</link><language>es</language><item><title>Por qué tu contraseña &quot;segura&quot; no lo es (y cómo realmente te hackean en 2026)</title><link>https://fuwari.vercel.app/posts/draft/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/draft/</guid><pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;div class=&quot;content-es&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;Si estás leyendo esto, probablemente ya sabés lo básico:
usar mayúsculas, números, símbolos…&lt;/p&gt;
&lt;p&gt;Y aún así, hay una alta probabilidad de que tus contraseñas sean vulnerables.&lt;/p&gt;
&lt;p&gt;No porque sean &quot;malas&quot;.
Sino porque los ataques cambiaron… y la forma de defenderse también.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧠 El problema no es tu contraseña (es el modelo mental)&lt;/h2&gt;
&lt;p&gt;La mayoría imagina al atacante así:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;alguien intentando adivinar tu contraseña manualmente.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pero la realidad es otra.&lt;/p&gt;
&lt;p&gt;Hoy, los ataques funcionan así:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Se filtra una base de datos (millones de usuarios)&lt;/li&gt;
&lt;li&gt;Se automatizan intentos de login&lt;/li&gt;
&lt;li&gt;Se prueban combinaciones a escala masiva&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No sos un objetivo.
Sos parte de un sistema.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🔓 Cómo se rompen contraseñas hoy (lo que nadie te explica)&lt;/h2&gt;
&lt;h3&gt;1. Ataques de diccionario (no son lo que pensás)&lt;/h3&gt;
&lt;p&gt;No usan solo palabras comunes.&lt;/p&gt;
&lt;p&gt;Usan listas como:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Password123&lt;/li&gt;
&lt;li&gt;Admin2024&lt;/li&gt;
&lt;li&gt;Bienvenido1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Y también combinaciones con:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;símbolos&lt;/li&gt;
&lt;li&gt;mayúsculas&lt;/li&gt;
&lt;li&gt;números&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 Es decir: &quot;cumplir las reglas&quot; ya no te salva.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;2. Credential stuffing (el ataque más subestimado)&lt;/h3&gt;
&lt;p&gt;Este es el más importante.&lt;/p&gt;
&lt;p&gt;Funciona así:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Un sitio es hackeado&lt;/li&gt;
&lt;li&gt;Se filtran emails + contraseñas&lt;/li&gt;
&lt;li&gt;Esas credenciales se prueban automáticamente en otros servicios&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Resultado:
👉 si reutilizás contraseñas, un solo leak compromete todo&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;3. Fuerza bruta moderna&lt;/h3&gt;
&lt;p&gt;No es alguien probando combinaciones lentas.&lt;/p&gt;
&lt;p&gt;Son sistemas capaces de:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;probar millones de combinaciones por segundo&lt;/li&gt;
&lt;li&gt;usar GPUs&lt;/li&gt;
&lt;li&gt;optimizar intentos según patrones humanos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 Las contraseñas cortas no tienen chance.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;⚠️ El gran mito: &quot;uso una contraseña compleja, estoy seguro&quot;&lt;/h2&gt;
&lt;p&gt;Ejemplo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;P4ssw0rd!2024&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Parece segura.&lt;/p&gt;
&lt;p&gt;Pero:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sigue un patrón conocido&lt;/li&gt;
&lt;li&gt;está en bases de datos reales&lt;/li&gt;
&lt;li&gt;es fácilmente predecible&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 Complejidad ≠ seguridad&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧩 La clave real: ENTROPÍA&lt;/h2&gt;
&lt;p&gt;Este es el concepto que casi nadie explica.&lt;/p&gt;
&lt;p&gt;La seguridad de una contraseña no depende solo de los caracteres…
sino de cuántas combinaciones posibles existen.&lt;/p&gt;
&lt;p&gt;Más:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;longitud&lt;/li&gt;
&lt;li&gt;aleatoriedad&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;= más entropía = más seguridad&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🔐 Entonces… ¿qué funciona realmente?&lt;/h2&gt;
&lt;h3&gt;✔ Passphrases (pero bien usadas)&lt;/h3&gt;
&lt;p&gt;Ejemplo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Perro!Azul_Come#Sandía99&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Esto funciona porque:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;es larga&lt;/li&gt;
&lt;li&gt;mezcla caracteres&lt;/li&gt;
&lt;li&gt;no sigue patrones comunes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pero ojo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;IloveYou123!&quot; ❌
Sigue siendo predecible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;✔ Contraseñas únicas SIEMPRE&lt;/h3&gt;
&lt;p&gt;Esto es más importante que cualquier otra regla.&lt;/p&gt;
&lt;p&gt;Porque evita:
👉 el efecto dominó de los leaks&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;✔ Gestores de contraseñas (la solución real)&lt;/h3&gt;
&lt;p&gt;Herramientas como Bitwarden, 1Password o KeePass cambian completamente el juego:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;generan contraseñas realmente aleatorias&lt;/li&gt;
&lt;li&gt;eliminan la reutilización&lt;/li&gt;
&lt;li&gt;reducen el error humano&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 Pasás de &quot;recordar contraseñas&quot; a &quot;gestionar acceso&quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;✔ 2FA (tu red de seguridad)&lt;/h3&gt;
&lt;p&gt;Incluso si todo falla:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;phishing&lt;/li&gt;
&lt;li&gt;filtraciones&lt;/li&gt;
&lt;li&gt;errores humanos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;El doble factor puede detener el acceso.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧠 Pensá como atacante (y ganás)&lt;/h2&gt;
&lt;p&gt;Un atacante no piensa:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;¿cómo entro a esta persona?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Piensa:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;¿qué error masivo puedo explotar?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Por eso:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reutilización = oro&lt;/li&gt;
&lt;li&gt;patrones = ventaja&lt;/li&gt;
&lt;li&gt;contraseñas cortas = trivial&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;⚡ Experimento mental (probá esto)&lt;/h2&gt;
&lt;p&gt;Respondé honestamente:&lt;/p&gt;
&lt;p&gt;¿Tu contraseña más importante…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la usás en más de un sitio?&lt;/li&gt;
&lt;li&gt;tiene menos de 12 caracteres?&lt;/li&gt;
&lt;li&gt;sigue un patrón lógico?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si respondiste &quot;sí&quot; a alguna:
👉 ya sos vulnerable a ataques automatizados&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧠 Conclusión&lt;/h2&gt;
&lt;p&gt;La seguridad no se trata de hacer una contraseña &quot;más complicada&quot;.&lt;/p&gt;
&lt;p&gt;Se trata de:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;eliminar patrones&lt;/li&gt;
&lt;li&gt;evitar reutilización&lt;/li&gt;
&lt;li&gt;aumentar entropía&lt;/li&gt;
&lt;li&gt;reducir el error humano&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;🚀 Si aplicás solo esto:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Usá contraseñas largas (16+)&lt;/li&gt;
&lt;li&gt;No las reutilices&lt;/li&gt;
&lt;li&gt;Usá un gestor&lt;/li&gt;
&lt;li&gt;Activá 2FA&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ya estás en el top de usuarios en seguridad.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;La mayoría de los ataques no requieren habilidad avanzada.&lt;/p&gt;
&lt;p&gt;Solo requieren que alguien cometa los errores de siempre.&lt;/p&gt;
&lt;p&gt;La diferencia está en entenderlos… y no repetirlos.&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;content-en&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;If you&apos;re reading this, you probably already know the basics:
uppercase letters, numbers, symbols…&lt;/p&gt;
&lt;p&gt;And yet, there&apos;s a high chance your passwords are still vulnerable.&lt;/p&gt;
&lt;p&gt;Not because they&apos;re &quot;bad&quot;.
But because attacks changed… and so did the way to defend against them.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧠 The problem isn&apos;t your password (it&apos;s the mental model)&lt;/h2&gt;
&lt;p&gt;Most people picture the attacker like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;someone trying to guess your password manually.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But the reality is different.&lt;/p&gt;
&lt;p&gt;Today, attacks work like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A database gets leaked (millions of users)&lt;/li&gt;
&lt;li&gt;Login attempts are automated&lt;/li&gt;
&lt;li&gt;Combinations are tested at massive scale&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&apos;re not a target.
You&apos;re part of a system.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🔓 How passwords are cracked today (what nobody explains)&lt;/h2&gt;
&lt;h3&gt;1. Dictionary attacks (not what you think)&lt;/h3&gt;
&lt;p&gt;They don&apos;t just use common words.&lt;/p&gt;
&lt;p&gt;They use lists like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Password123&lt;/li&gt;
&lt;li&gt;Admin2024&lt;/li&gt;
&lt;li&gt;Welcome1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And also combinations with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;symbols&lt;/li&gt;
&lt;li&gt;uppercase letters&lt;/li&gt;
&lt;li&gt;numbers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 In other words: &quot;following the rules&quot; no longer saves you.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;2. Credential stuffing (the most underrated attack)&lt;/h3&gt;
&lt;p&gt;This is the most important one.&lt;/p&gt;
&lt;p&gt;It works like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A site gets hacked&lt;/li&gt;
&lt;li&gt;Emails + passwords are leaked&lt;/li&gt;
&lt;li&gt;Those credentials are automatically tested on other services&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Result:
👉 if you reuse passwords, a single leak compromises everything&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;3. Modern brute force&lt;/h3&gt;
&lt;p&gt;It&apos;s not someone slowly trying combinations.&lt;/p&gt;
&lt;p&gt;These are systems capable of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;testing millions of combinations per second&lt;/li&gt;
&lt;li&gt;using GPUs&lt;/li&gt;
&lt;li&gt;optimizing attempts based on human patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 Short passwords have no chance.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;⚠️ The big myth: &quot;I use a complex password, I&apos;m safe&quot;&lt;/h2&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;P4ssw0rd!2024&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Looks secure.&lt;/p&gt;
&lt;p&gt;But:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it follows a known pattern&lt;/li&gt;
&lt;li&gt;it&apos;s in real databases&lt;/li&gt;
&lt;li&gt;it&apos;s easily predictable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 Complexity ≠ security&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧩 The real key: ENTROPY&lt;/h2&gt;
&lt;p&gt;This is the concept almost nobody explains.&lt;/p&gt;
&lt;p&gt;A password&apos;s security doesn&apos;t depend only on its characters…
but on how many possible combinations exist.&lt;/p&gt;
&lt;p&gt;More:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;length&lt;/li&gt;
&lt;li&gt;randomness&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;= more entropy = more security&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🔐 So… what actually works?&lt;/h2&gt;
&lt;h3&gt;✔ Passphrases (but used correctly)&lt;/h3&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Blue!Dog_Eats#Watermelon99&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This works because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it&apos;s long&lt;/li&gt;
&lt;li&gt;it mixes characters&lt;/li&gt;
&lt;li&gt;it doesn&apos;t follow common patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But watch out:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;IloveYou123!&quot; ❌
Still predictable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;✔ Unique passwords ALWAYS&lt;/h3&gt;
&lt;p&gt;This is more important than any other rule.&lt;/p&gt;
&lt;p&gt;Because it prevents:
👉 the domino effect of leaks&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;✔ Password managers (the real solution)&lt;/h3&gt;
&lt;p&gt;Tools like Bitwarden, 1Password or KeePass completely change the game:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;they generate truly random passwords&lt;/li&gt;
&lt;li&gt;they eliminate reuse&lt;/li&gt;
&lt;li&gt;they reduce human error&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👉 You go from &quot;remembering passwords&quot; to &quot;managing access&quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;✔ 2FA (your safety net)&lt;/h3&gt;
&lt;p&gt;Even if everything else fails:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;phishing&lt;/li&gt;
&lt;li&gt;leaks&lt;/li&gt;
&lt;li&gt;human errors&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second factor can stop unauthorized access.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧠 Think like an attacker (and win)&lt;/h2&gt;
&lt;p&gt;An attacker doesn&apos;t think:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;how do I get into this person&apos;s account?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They think:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;what massive mistake can I exploit?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&apos;s why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reuse = gold&lt;/li&gt;
&lt;li&gt;patterns = advantage&lt;/li&gt;
&lt;li&gt;short passwords = trivial&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;⚡ Mental experiment (try this)&lt;/h2&gt;
&lt;p&gt;Answer honestly:&lt;/p&gt;
&lt;p&gt;Your most important password…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;do you use it on more than one site?&lt;/li&gt;
&lt;li&gt;does it have fewer than 12 characters?&lt;/li&gt;
&lt;li&gt;does it follow a logical pattern?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you answered &quot;yes&quot; to any of those:
👉 you&apos;re already vulnerable to automated attacks&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;🧠 Conclusion&lt;/h2&gt;
&lt;p&gt;Security isn&apos;t about making a password &quot;more complicated&quot;.&lt;/p&gt;
&lt;p&gt;It&apos;s about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;eliminating patterns&lt;/li&gt;
&lt;li&gt;avoiding reuse&lt;/li&gt;
&lt;li&gt;increasing entropy&lt;/li&gt;
&lt;li&gt;reducing human error&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;🚀 If you do just this:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Use long passwords (16+)&lt;/li&gt;
&lt;li&gt;Don&apos;t reuse them&lt;/li&gt;
&lt;li&gt;Use a password manager&lt;/li&gt;
&lt;li&gt;Enable 2FA&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You&apos;re already in the top tier of security-conscious users.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Most attacks don&apos;t require advanced skills.&lt;/p&gt;
&lt;p&gt;They only require someone to make the same old mistakes.&lt;/p&gt;
&lt;p&gt;The difference is in understanding them… and not repeating them.&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Ciphie: por qué construí mi propio gestor de secretos</title><link>https://fuwari.vercel.app/posts/expressive-code/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/expressive-code/</guid><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;div class=&quot;content-es&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;Hay un archivo que muchos developers tienen y nadie admite. Se llama keys.txt, o env_backup.txt, o simplemente temp — y adentro hay API keys, tokens, contraseñas de bases de datos. Sin cifrar. Sin contraseña. Ahí nomás, en el escritorio.&lt;/p&gt;
&lt;p&gt;Yo lo tuve durante dos años.&lt;/p&gt;
&lt;p&gt;No por ignorancia. Sabía que era mala práctica. Pero los gestores de contraseñas comerciales no están pensados para developers: mezclan credenciales web con tokens de producción, no tienen campos para variables de entorno, y tarde o temprano terminan mandando tus datos a una nube que no controlás.&lt;/p&gt;
&lt;p&gt;Así que un día borré el archivo y empecé a construir algo propio.&lt;/p&gt;
&lt;h2&gt;Qué es Ciphie&lt;/h2&gt;
&lt;p&gt;Ciphie es un gestor de secretos que corre completamente en tu máquina. Sin servidor, sin cuenta, sin suscripción. Lo abrís, guardás tus API keys, tokens y contraseñas, y eso es todo. Por defecto, nada sale de tu computadora — las únicas conexiones de red opcionales son el email de verificación de cuenta y el 2FA por SMS, ambas desactivadas si no las configurás en el .env.&lt;/p&gt;
&lt;p&gt;Tiene interfaz de escritorio con tema oscuro, soporte para varios tipos de secretos con campos específicos por categoría, y segundo factor de autenticación con cuatro métodos distintos para elegir al momento del login.&lt;/p&gt;
&lt;p&gt;Todavía no está publicado — estoy terminando algunos detalles antes de soltar la primera versión. Pero quería contar la historia antes de eso.&lt;/p&gt;
&lt;h2&gt;El problema con las alternativas&lt;/h2&gt;
&lt;p&gt;Antes de construir algo, siempre conviene ver qué existe. En mi caso, las opciones eran:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gestores comerciales (1Password, Bitwarden, Dashlane):&lt;/strong&gt; buenos productos, pero orientados a contraseñas web. Para un developer que maneja decenas de API keys con campos como endpoint, región, scope o environment, la experiencia es torpe. Y dependen de la nube.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Soluciones de infraestructura (HashiCorp Vault, AWS Secrets Manager):&lt;/strong&gt; excelentes para equipos y producción, completamente sobredimensionados para un developer individual que quiere guardar sus keys de forma segura durante el desarrollo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Variables de entorno del sistema:&lt;/strong&gt; válido, pero sin interfaz, sin organización y sin cifrado en reposo.&lt;/p&gt;
&lt;p&gt;Lo que quería era simple: una app de escritorio, local, cifrada, pensada para developers. No encontré exactamente eso, así que lo construí.&lt;/p&gt;
&lt;h2&gt;Las decisiones que importan&lt;/h2&gt;
&lt;p&gt;Construir algo de seguridad obliga a tomar decisiones que en otros proyectos son opcionales. Acá están las que más me marcaron.&lt;/p&gt;
&lt;h3&gt;Una dependencia obligatoria, el resto opcional&lt;/h3&gt;
&lt;p&gt;La primera decisión fue de filosofía: mantener el stack al mínimo absoluto. Ciphie tiene una sola dependencia obligatoria — &lt;code&gt;cryptography&lt;/code&gt;, el paquete de la Python Cryptographic Authority. Todo lo demás que podría necesitar (QR codes para TOTP, SMS vía Twilio, Touch ID en macOS) son extras opcionales que se instalan solo si los querés usar:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install ciphie        # solo lo esencial
pip install ciphie[qr]    # agrega QR codes para el 2FA con app
pip install ciphie[sms]   # agrega 2FA por SMS vía Twilio
pip install ciphie[all]   # todo junto
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La interfaz, la base de datos y el hashing de contraseñas usan módulos que vienen con Python: &lt;code&gt;tkinter&lt;/code&gt;, &lt;code&gt;sqlite3&lt;/code&gt;, &lt;code&gt;hashlib&lt;/code&gt;. Cada dependencia adicional es una superficie de ataque. En un proyecto de seguridad, eso pesa más que la comodidad de una librería extra.&lt;/p&gt;
&lt;h3&gt;Cifrado real, no teatro de seguridad&lt;/h3&gt;
&lt;p&gt;Cada secreto se cifra con AES-256-GCM antes de guardarse. No es solo una decisión de algoritmo — es un modo que importa.&lt;/p&gt;
&lt;p&gt;GCM (Galois/Counter Mode) hace dos cosas: cifra el dato y lo autentica. Si alguien modifica el archivo de la base de datos directamente, el descifrado no devuelve basura silenciosamente: falla con un error explícito. Eso es la diferencia entre un sistema que detecta manipulación y uno que no.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def cifrar(valor: str) -&amp;gt; str:
    clave = _get_clave_aes()
    nonce = os.urandom(12)  # 96 bits — tamaño recomendado para GCM
    aesgcm = AESGCM(clave)
    cifrado = aesgcm.encrypt(nonce, valor.encode(&quot;utf-8&quot;), None)
    return base64.urlsafe_b64encode(nonce + cifrado).decode(&quot;utf-8&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lo otro que importa es el nonce: 12 bytes generados aleatoriamente para cada cifrado individual. Sin eso, dos secretos con el mismo contenido producen el mismo resultado cifrado — y eso rompe la seguridad del esquema completo. Con el nonce aleatorio, cada cifrado es único aunque el contenido sea idéntico.&lt;/p&gt;
&lt;h3&gt;Las contraseñas no se guardan&lt;/h3&gt;
&lt;p&gt;Las contraseñas de los usuarios se hashean con PBKDF2-HMAC-SHA256 con 310.000 iteraciones — la recomendación de OWASP para 2023. Cada iteración extra multiplica el tiempo que le lleva a un atacante probar contraseñas en un ataque offline. Con esta configuración, una GPU moderna tardaría meses en fuerza bruta, no segundos.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_ITERATIONS = 310_000

def _hash_password(password: str) -&amp;gt; str:
    salt = os.urandom(16)
    clave = hashlib.pbkdf2_hmac(
        &quot;sha256&quot;, password.encode(&quot;utf-8&quot;), salt, _ITERATIONS, dklen=64
    )
    return salt.hex() + &quot;:&quot; + clave.hex()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Un detalle que casi ignoro: la comparación del hash usa &lt;code&gt;hmac.compare_digest&lt;/code&gt; en lugar del operador &lt;code&gt;==&lt;/code&gt; de Python. La diferencia es que &lt;code&gt;==&lt;/code&gt; puede terminar antes si los primeros bytes no coinciden, lo que permite medir tiempos y deducir información sobre el hash real. &lt;code&gt;compare_digest&lt;/code&gt; siempre tarda exactamente lo mismo, sin importar el resultado.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ❌ vulnerable a timing attacks
if hash_calculado == hash_guardado:

# ✅ tiempo constante, sin importar cuántos bytes coincidan
if hmac.compare_digest(hash_calculado, hash_guardado):
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;SQLite es suficiente&lt;/h3&gt;
&lt;p&gt;No necesité un servidor de base de datos. SQLite corre en proceso, el archivo vive localmente con permisos restringidos — solo el usuario dueño puede leerlo —, y es más que suficiente para este caso de uso. A veces la solución correcta es la más simple.&lt;/p&gt;
&lt;h2&gt;Lo que sorprende cuando construís algo de seguridad&lt;/h2&gt;
&lt;p&gt;Hay una diferencia enorme entre saber que algo existe y tener que implementarlo correctamente.&lt;/p&gt;
&lt;p&gt;Los timing attacks son un buen ejemplo. Sabía que existían. Pero fue distinto tener que pensar: &quot;si uso &lt;code&gt;==&lt;/code&gt; acá, ¿estoy filtrando información?&quot; y tener que buscar la alternativa correcta. La seguridad está llena de esos momentos: detalles pequeños con consecuencias grandes.&lt;/p&gt;
&lt;p&gt;Lo mismo con los nonces. O con la diferencia entre cifrado autenticado y no autenticado. O con la cantidad de iteraciones del hash. Ninguno de esos detalles aparece en un tutorial introductorio, pero todos importan en producción.&lt;/p&gt;
&lt;p&gt;Construir Ciphie fue, entre otras cosas, un ejercicio de ir más allá de la superficie de cada concepto.&lt;/p&gt;
&lt;h2&gt;Lo que viene&lt;/h2&gt;
&lt;p&gt;Antes de publicar la primera versión, estoy terminando algunos ajustes. Cuando esté lista, va a estar disponible en GitHub bajo licencia MIT. Una sola línea para instalar, otra para abrirlo.&lt;/p&gt;
&lt;p&gt;Si manejás secretos como developer y te interesa probarlo cuando esté disponible, seguime acá — voy a publicar el lanzamiento en cuanto esté listo.&lt;/p&gt;
&lt;p&gt;Y si tenés un keys.txt en el escritorio, borralo ya. No esperés a que salga Ciphie.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Ciphie está construido con Python 3.11+, SQLite, Tkinter y la librería &lt;code&gt;cryptography&lt;/code&gt;. El código va a estar disponible en GitHub bajo licencia MIT.&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;content-en&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;There&apos;s a file many developers have and nobody admits to. It&apos;s called keys.txt, or env_backup.txt, or just temp — and inside there are API keys, tokens, database passwords. Unencrypted. No password. Just sitting there on the desktop.&lt;/p&gt;
&lt;p&gt;I had one for two years.&lt;/p&gt;
&lt;p&gt;Not out of ignorance. I knew it was bad practice. But commercial password managers aren&apos;t built for developers: they mix web credentials with production tokens, have no fields for environment variables, and sooner or later end up sending your data to a cloud you don&apos;t control.&lt;/p&gt;
&lt;p&gt;So one day I deleted the file and started building something of my own.&lt;/p&gt;
&lt;h2&gt;What is Ciphie&lt;/h2&gt;
&lt;p&gt;Ciphie is a secrets manager that runs entirely on your machine. No server, no account, no subscription. You open it, save your API keys, tokens and passwords, and that&apos;s it. By default, nothing leaves your computer — the only optional network connections are account verification email and 2FA via SMS, both disabled unless you configure them in the .env.&lt;/p&gt;
&lt;p&gt;It has a desktop UI with dark theme, support for multiple secret types with category-specific fields, and two-factor authentication with four different methods to choose from at login.&lt;/p&gt;
&lt;p&gt;It&apos;s not published yet — I&apos;m finishing some details before releasing the first version. But I wanted to tell the story before that.&lt;/p&gt;
&lt;h2&gt;The problem with alternatives&lt;/h2&gt;
&lt;p&gt;Before building something, it&apos;s always worth seeing what exists. In my case, the options were:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Commercial managers (1Password, Bitwarden, Dashlane):&lt;/strong&gt; good products, but oriented toward web passwords. For a developer managing dozens of API keys with fields like endpoint, region, scope or environment, the experience is clunky. And they depend on the cloud.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Infrastructure solutions (HashiCorp Vault, AWS Secrets Manager):&lt;/strong&gt; excellent for teams and production, completely oversized for an individual developer who wants to store their keys securely during development.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;System environment variables:&lt;/strong&gt; valid, but no UI, no organization and no encryption at rest.&lt;/p&gt;
&lt;p&gt;What I wanted was simple: a desktop app, local, encrypted, built for developers. I didn&apos;t find exactly that, so I built it.&lt;/p&gt;
&lt;h2&gt;The decisions that matter&lt;/h2&gt;
&lt;p&gt;Building something security-related forces you to make decisions that are optional in other projects. Here are the ones that impacted me the most.&lt;/p&gt;
&lt;h3&gt;One mandatory dependency, the rest optional&lt;/h3&gt;
&lt;p&gt;The first decision was philosophical: keep the stack to the absolute minimum. Ciphie has one mandatory dependency — &lt;code&gt;cryptography&lt;/code&gt;, the Python Cryptographic Authority package. Everything else it might need (QR codes for TOTP, SMS via Twilio, Touch ID on macOS) are optional extras installed only if you want them:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install ciphie        # just the essentials
pip install ciphie[qr]    # adds QR codes for app-based 2FA
pip install ciphie[sms]   # adds 2FA via SMS through Twilio
pip install ciphie[all]   # everything together
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The UI, database and password hashing use modules that ship with Python: &lt;code&gt;tkinter&lt;/code&gt;, &lt;code&gt;sqlite3&lt;/code&gt;, &lt;code&gt;hashlib&lt;/code&gt;. Every additional dependency is an attack surface. In a security project, that weighs more than the convenience of an extra library.&lt;/p&gt;
&lt;h3&gt;Real encryption, not security theater&lt;/h3&gt;
&lt;p&gt;Each secret is encrypted with AES-256-GCM before being stored. It&apos;s not just an algorithm choice — it&apos;s a mode that matters.&lt;/p&gt;
&lt;p&gt;GCM (Galois/Counter Mode) does two things: it encrypts the data and authenticates it. If someone modifies the database file directly, decryption doesn&apos;t silently return garbage: it fails with an explicit error. That&apos;s the difference between a system that detects tampering and one that doesn&apos;t.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def encrypt(value: str) -&amp;gt; str:
    key = _get_aes_key()
    nonce = os.urandom(12)  # 96 bits — recommended size for GCM
    aesgcm = AESGCM(key)
    encrypted = aesgcm.encrypt(nonce, value.encode(&quot;utf-8&quot;), None)
    return base64.urlsafe_b64encode(nonce + encrypted).decode(&quot;utf-8&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other thing that matters is the nonce: 12 randomly generated bytes for each individual encryption. Without it, two secrets with the same content produce the same encrypted result — and that breaks the security of the entire scheme. With the random nonce, each encryption is unique even if the content is identical.&lt;/p&gt;
&lt;h3&gt;Passwords are never stored&lt;/h3&gt;
&lt;p&gt;User passwords are hashed with PBKDF2-HMAC-SHA256 with 310,000 iterations — OWASP&apos;s recommendation for 2023. Each extra iteration multiplies the time it takes an attacker to try passwords in an offline attack. With this configuration, a modern GPU would take months to brute-force, not seconds.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_ITERATIONS = 310_000

def _hash_password(password: str) -&amp;gt; str:
    salt = os.urandom(16)
    key = hashlib.pbkdf2_hmac(
        &quot;sha256&quot;, password.encode(&quot;utf-8&quot;), salt, _ITERATIONS, dklen=64
    )
    return salt.hex() + &quot;:&quot; + key.hex()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A detail I almost overlooked: hash comparison uses &lt;code&gt;hmac.compare_digest&lt;/code&gt; instead of Python&apos;s &lt;code&gt;==&lt;/code&gt; operator. The difference is that &lt;code&gt;==&lt;/code&gt; can terminate early if the first bytes don&apos;t match, which allows timing measurement and leaking information about the real hash. &lt;code&gt;compare_digest&lt;/code&gt; always takes exactly the same time, regardless of the result.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ❌ vulnerable to timing attacks
if calculated_hash == stored_hash:

# ✅ constant time, regardless of how many bytes match
if hmac.compare_digest(calculated_hash, stored_hash):
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;SQLite is enough&lt;/h3&gt;
&lt;p&gt;I didn&apos;t need a database server. SQLite runs in-process, the file lives locally with restricted permissions — only the owner can read it —, and it&apos;s more than enough for this use case. Sometimes the right solution is the simplest one.&lt;/p&gt;
&lt;h2&gt;What surprises you when building something security-related&lt;/h2&gt;
&lt;p&gt;There&apos;s a huge difference between knowing something exists and having to implement it correctly.&lt;/p&gt;
&lt;p&gt;Timing attacks are a good example. I knew they existed. But it was different to have to think: &quot;if I use &lt;code&gt;==&lt;/code&gt; here, am I leaking information?&quot; and have to find the correct alternative. Security is full of those moments: small details with large consequences.&lt;/p&gt;
&lt;p&gt;Same with nonces. Or with the difference between authenticated and unauthenticated encryption. Or with the number of hash iterations. None of those details appear in an introductory tutorial, but all of them matter in production.&lt;/p&gt;
&lt;p&gt;Building Ciphie was, among other things, an exercise in going beyond the surface of each concept.&lt;/p&gt;
&lt;h2&gt;What&apos;s next&lt;/h2&gt;
&lt;p&gt;Before publishing the first version, I&apos;m finishing some adjustments. When it&apos;s ready, it will be available on GitHub under MIT license. One line to install, another to open it.&lt;/p&gt;
&lt;p&gt;If you manage secrets as a developer and are interested in trying it when it&apos;s available, follow me here — I&apos;ll publish the launch as soon as it&apos;s ready.&lt;/p&gt;
&lt;p&gt;And if you have a keys.txt on your desktop, delete it now. Don&apos;t wait for Ciphie.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Ciphie is built with Python 3.11+, SQLite, Tkinter and the &lt;code&gt;cryptography&lt;/code&gt; library. The code will be available on GitHub under MIT license.&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Le pedí a Claude que escribiera mi endpoint de login. Estaba roto de cuatro maneras distintas.</title><link>https://fuwari.vercel.app/posts/parley-seguridad-codigo-ia/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/parley-seguridad-codigo-ia/</guid><description>Construí Parley para que eso no le pase a nadie más.</description><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;div class=&quot;content-es&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;Le pedí a Claude que escribiera mi endpoint de login. Estaba roto de cuatro maneras distintas.&lt;/p&gt;
&lt;p&gt;No era obvio. El código se veía limpio, estaba bien formateado, tenía comentarios útiles. Pero tenía SQL injection, JWT sin verificar, y las contraseñas hasheadas con MD5. Construí Parley para que eso no le pase a nadie más.&lt;/p&gt;
&lt;p&gt;Fue en un proyecto de lado, un sábado a la tarde. Necesitaba un endpoint de autenticación rápido en Python. Le pasé el contexto a Claude, me devolvió 80 líneas prolijas, lo copié, lo pegué, funcionó en el primer intento.&lt;/p&gt;
&lt;p&gt;Tres días después, mirando el código más despacio antes de hacer el deploy, noté algo raro en la query. El modelo había armado el SQL concatenando strings. Directamente. Sin prepared statements. El tipo de error que cualquier tutorial de seguridad web menciona en el primer capítulo.&lt;/p&gt;
&lt;p&gt;Lo peor no fue encontrar eso. Lo peor fue que, si no lo buscaba activamente, nunca lo hubiera visto. El código era prolijo, estaba bien indentado, tenía nombres de variables descriptivos. Transmitía confianza. Y esa confianza era el problema real.&lt;/p&gt;
&lt;p&gt;El problema no es que la IA sea mala generando código. El problema es que fue entrenada con millones de líneas de código histórico — y ese código histórico está lleno de vulnerabilidades que en su momento nadie cuestionó. El modelo aprendió los patrones incorrectos con la misma confianza con la que aprendió los correctos. No distingue entre código seguro y código que simplemente funciona.&lt;/p&gt;
&lt;p&gt;Busqué herramientas para auditarlo sistemáticamente. Snyk requería cuenta en la nube y estaba pensado para integrar en pipelines de CI de equipos medianos. Semgrep era potente pero genérico, con una curva de configuración que no tenía sentido para un proyecto chico. Ninguna herramienta estaba especializada en los patrones específicos que producen los LLMs — porque hasta hace poco ese no era un problema que existiera a esta escala.&lt;/p&gt;
&lt;p&gt;Así nació Parley.&lt;/p&gt;
&lt;h2&gt;Qué es&lt;/h2&gt;
&lt;p&gt;Parley es un CLI que actúa como tu equipo de seguridad personal para código generado con IA. La idea es simple: generás código con Claude, ChatGPT o Copilot, lo pegás en tu proyecto, y antes de hacer commit corrés Parley. Él te dice si hay problemas de seguridad, sin mandar nada a internet, sin cuentas, sin configuración previa.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ parley scan auth.py

[CRITICAL] SQL injection — línea 34
[HIGH]     JWT sin verificar — línea 67
[HIGH]     Hash inseguro (MD5) — línea 89
[INFO]     Error expuesto al cliente — línea 102

4 findings en 1 archivo (2 críticos, 2 altos, 0 medios)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Treinta segundos. Sin fricción. Sin tener que recordar un checklist mental cada vez que copiás código de un chat.&lt;/p&gt;
&lt;h2&gt;Cómo funciona por dentro&lt;/h2&gt;
&lt;p&gt;Tiene dos capas que se activan en orden:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Capa 1 — Análisis estático (siempre activa, instantánea)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;24 reglas en YAML comparan el código contra patrones conocidos de vulnerabilidades. Es como un corrector ortográfico pero para seguridad. No necesita internet ni modelos de IA para funcionar — corre en milisegundos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Capa 2 — Análisis con LLM local (opcional, &lt;code&gt;--llm&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Usa un modelo corriendo en tu propia máquina via Ollama para entender el contexto de cada finding y explicarte exactamente por qué es peligroso y cómo arreglarlo. Esta capa agrega el &quot;por qué&quot; que el análisis estático no puede dar.&lt;/p&gt;
&lt;p&gt;La decisión de usar un modelo local para la capa 2 fue deliberada. Si el código que estás auditando es código propietario o de autenticación, mandarlo a un servidor externo para analizarlo introduce exactamente el tipo de riesgo que querés evitar. Con Ollama todo queda en tu máquina.&lt;/p&gt;
&lt;h2&gt;Las 24 reglas, agrupadas en 8 categorías&lt;/h2&gt;
&lt;p&gt;Definimos las reglas cubriendo los patrones más frecuentes que aparecen en código AI-generado, no vulnerabilidades en abstracto:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Categoría&lt;/th&gt;
&lt;th&gt;Reglas&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Inyección&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validación de entrada&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secretos hardcodeados&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memoria y buffers&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deserialización&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manejo de errores&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autenticación&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config insegura&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Cada regla es un archivo YAML simple y legible. No hace falta entender el motor en Go para contribuir una nueva — alcanza con conocer el patrón de vulnerabilidad que querés cubrir.&lt;/p&gt;
&lt;h2&gt;Así se ven los findings en detalle&lt;/h2&gt;
&lt;p&gt;Una decisión de diseño importante: Parley es conservador con los falsos positivos. Preferimos avisarte de menos cosas con alta confianza que llenarte de alertas que no son reales. Si hay duda, el finding se marca como INFO en lugar de HIGH. La idea es que cuando Parley dice CRITICAL, vos lo tratés como crítico de verdad.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CRITICAL&lt;/strong&gt; SQL injection por concatenación de strings&lt;/p&gt;
&lt;p&gt;&lt;code&gt;auth.py:34&lt;/code&gt; — La query arma el WHERE pegando directamente el valor del parámetro username. Un atacante puede cerrar la query e inyectar cualquier SQL arbitrario, incluyendo lecturas de otras tablas o eliminación de datos. Usá prepared statements: &lt;code&gt;cursor.execute(&quot;SELECT * FROM users WHERE username = %s&quot;, (username,))&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;HIGH&lt;/strong&gt; JWT aceptado sin verificar la firma&lt;/p&gt;
&lt;p&gt;&lt;code&gt;auth.py:67&lt;/code&gt; — El token se decodifica con &lt;code&gt;verify=False&lt;/code&gt;. Esto significa que cualquier persona puede construir un token con el payload que quiera — por ejemplo, con &lt;code&gt;role: admin&lt;/code&gt; — y el sistema lo va a aceptar. Siempre verificá la firma con tu clave secreta antes de confiar en el contenido del token.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;HIGH&lt;/strong&gt; Contraseña hasheada con MD5&lt;/p&gt;
&lt;p&gt;&lt;code&gt;auth.py:89&lt;/code&gt; — MD5 fue roto hace décadas y existen tablas rainbow que permiten revertir hashes comunes en segundos. Para passwords usá bcrypt, argon2 o scrypt, que están diseñados específicamente para ser lentos y resistentes a fuerza bruta.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt; Stack trace expuesto al cliente&lt;/p&gt;
&lt;p&gt;&lt;code&gt;auth.py:102&lt;/code&gt; — El bloque except devuelve &lt;code&gt;str(e)&lt;/code&gt; directamente en la respuesta HTTP. Dependiendo del error, eso puede filtrar rutas internas del servidor, nombres de tablas de la base de datos o strings de conexión. Loggeá el detalle internamente y devolvé un mensaje genérico al cliente.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Por qué open source y sin telemetría&lt;/h2&gt;
&lt;p&gt;El código que Parley escanea puede ser código propietario, puede tener lógica de negocio sensible, puede ser exactamente el código de autenticación que no querés que salga de tu entorno. La decisión de no mandar nada a ningún servidor externo no es un feature — es el punto de partida.&lt;/p&gt;
&lt;p&gt;El motor está escrito en Go porque compila en un solo binario ejecutable sin dependencias. Instalación en segundos, funciona igual en Mac, Linux y Windows. Las reglas están en YAML para que sean legibles y fáciles de contribuir. Python aparece únicamente en el módulo de integración con Ollama, porque es el entorno más natural para ese tipo de integración.&lt;/p&gt;
&lt;p&gt;El código es público en GitHub bajo licencia MIT. Sin telemetría, sin analytics, sin ningún tipo de comunicación con servidores externos.&lt;/p&gt;
&lt;h2&gt;Qué sigue y cómo podés ayudar&lt;/h2&gt;
&lt;p&gt;Parley está en etapa de prueba de concepto. Las 24 reglas cubren los patrones más comunes que encontramos en código AI-generado, pero el espacio es mucho más amplio. Cada lenguaje tiene sus propios antipatrones. Cada framework tiene sus propias trampas. Y los modelos evolucionan — los patrones que generan hoy no son exactamente los mismos que generaban hace un año.&lt;/p&gt;
&lt;p&gt;Hay tres formas concretas de contribuir:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nuevas reglas YAML&lt;/strong&gt; — si encontrás un patrón de vulnerabilidad que Parley no detecta, podés abrir un issue describiendo el patrón o mandar directamente una PR con la regla. No hace falta tocar Go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Testing en proyectos reales&lt;/strong&gt; — si tenés proyectos con código AI-generado, corré Parley y contanos qué encontró, qué se perdió y qué generó falsos positivos. Ese feedback es lo más valioso que podemos recibir ahora mismo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Soporte para más lenguajes&lt;/strong&gt; — las reglas actuales cubren Python y Go principalmente. Hay mucho trabajo por hacer en JavaScript, TypeScript, Java y Rust.&lt;/p&gt;
&lt;p&gt;Si usás IA para escribir código — y en 2025 casi todos lo hacemos — Parley es esa segunda mirada que deberías darle antes de hacer deploy. No reemplaza una auditoría de seguridad seria. Pero sí reemplaza el &quot;seguro que está bien, lo generó la IA&quot;. Y eso, resulta, es bastante.&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Ethical Hacking y Ciberseguridad: entendiendo cómo se protege el mundo digital hoy</title><link>https://fuwari.vercel.app/posts/ethical-hacking-ciberseguridad/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/ethical-hacking-ciberseguridad/</guid><pubDate>Mon, 02 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;div class=&quot;content-es&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;Cuando se habla de ciberseguridad, muchas veces se la presenta como algo técnico, lejano o incluso complicado. Firewalls, cifrado, ataques, sistemas… todo suena bastante abstracto.&lt;/p&gt;
&lt;p&gt;Pero si lo bajamos a algo simple, la idea central es esta:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;todo sistema digital puede fallar, y alguien puede intentar aprovecharlo&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Y a partir de eso aparece una necesidad bastante lógica: no solo proteger, sino también anticiparse.&lt;/p&gt;
&lt;p&gt;Este enfoque es justamente el que explora el paper &lt;em&gt;&quot;Ethical Hacking and Cybersecurity: Evaluating Best Practices, Challenges and Synergies&quot;&lt;/em&gt;, analizando cómo la seguridad moderna ya no puede ser solo defensiva, sino que necesita incorporar prácticas activas como el ethical hacking.&lt;/p&gt;
&lt;h2&gt;🔐 La ciberseguridad ya no alcanza por sí sola&lt;/h2&gt;
&lt;p&gt;Tradicionalmente, la ciberseguridad se enfocó en construir barreras:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sistemas de autenticación&lt;/li&gt;
&lt;li&gt;firewalls&lt;/li&gt;
&lt;li&gt;monitoreo de actividad&lt;/li&gt;
&lt;li&gt;cifrado de datos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Todo esto sigue siendo fundamental. Pero el problema es que estos mecanismos parten de una lógica bastante clara: reaccionar o prevenir dentro de ciertos límites conocidos.&lt;/p&gt;
&lt;p&gt;El contexto actual rompe un poco esa lógica.&lt;/p&gt;
&lt;p&gt;Hoy los sistemas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;están más conectados que nunca&lt;/li&gt;
&lt;li&gt;dependen unos de otros&lt;/li&gt;
&lt;li&gt;manejan grandes volúmenes de datos&lt;/li&gt;
&lt;li&gt;evolucionan constantemente&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Y eso genera algo inevitable: más puntos de entrada posibles.&lt;/p&gt;
&lt;p&gt;El paper destaca que, en este escenario, los atacantes no solo buscan vulnerabilidades, sino que desarrollan estrategias cada vez más sofisticadas para encontrarlas.&lt;/p&gt;
&lt;p&gt;Por eso, quedarse únicamente en una postura defensiva deja un espacio peligroso: el de las fallas que todavía no fueron descubiertas.&lt;/p&gt;
&lt;h2&gt;🧑‍💻 Ethical Hacking: de reaccionar a anticiparse&lt;/h2&gt;
&lt;p&gt;Acá es donde entra el ethical hacking, que cambia la lógica de seguridad.&lt;/p&gt;
&lt;p&gt;En lugar de esperar a que ocurra un ataque, propone algo distinto:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;simular esos ataques de forma controlada para descubrir vulnerabilidades antes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Es importante entender que no se trata de un enfoque improvisado ni caótico. El ethical hacking sigue metodologías bastante estructuradas que permiten evaluar un sistema de forma ordenada y segura.&lt;/p&gt;
&lt;p&gt;Estas metodologías incluyen desde la recolección de información inicial hasta la explotación controlada de vulnerabilidades y, finalmente, la elaboración de informes detallados.&lt;/p&gt;
&lt;p&gt;Este último punto es clave: el objetivo no es &quot;romper&quot; el sistema, sino entender cómo mejorarlo.&lt;/p&gt;
&lt;h2&gt;🤝 La relación entre ambos enfoques&lt;/h2&gt;
&lt;p&gt;Uno de los aportes más interesantes del paper es mostrar que la ciberseguridad y el ethical hacking no son enfoques opuestos, sino complementarios.&lt;/p&gt;
&lt;p&gt;Podríamos pensarlo así:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la ciberseguridad construye y protege&lt;/li&gt;
&lt;li&gt;el ethical hacking prueba y desafía&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cuando ambos trabajan juntos, el resultado es un sistema más robusto.&lt;/p&gt;
&lt;p&gt;El paper señala que muchas organizaciones ya están integrando estas prácticas dentro de sus estrategias de seguridad, especialmente en áreas como:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;gestión de incidentes&lt;/li&gt;
&lt;li&gt;evaluación de riesgos&lt;/li&gt;
&lt;li&gt;planificación de contingencias&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Este cambio refleja una transición importante: pasar de una seguridad reactiva a una seguridad proactiva.&lt;/p&gt;
&lt;h2&gt;⚖️ Los desafíos: no todo es técnico&lt;/h2&gt;
&lt;p&gt;Aunque gran parte del tema parece técnico, el paper hace bastante énfasis en algo que a veces se pasa por alto: los aspectos éticos y legales.&lt;/p&gt;
&lt;p&gt;El ethical hacking solo es válido cuando:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;existe autorización explícita&lt;/li&gt;
&lt;li&gt;hay un alcance definido&lt;/li&gt;
&lt;li&gt;se respetan límites claros&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Esto es fundamental porque, en muchos casos, las pruebas implican acceder a sistemas sensibles o información crítica.&lt;/p&gt;
&lt;p&gt;Además, también existen riesgos operativos. Una prueba mal ejecutada puede generar interrupciones o incluso daños en el sistema.&lt;/p&gt;
&lt;p&gt;Por eso, el paper insiste en la necesidad de combinar habilidades técnicas con criterio profesional y responsabilidad.&lt;/p&gt;
&lt;h2&gt;🧠 Capacitación y profesionalización&lt;/h2&gt;
&lt;p&gt;Otro punto relevante es el crecimiento del campo profesional.&lt;/p&gt;
&lt;p&gt;A medida que aumenta la complejidad de los sistemas, también lo hace la demanda de personas capacitadas en estas áreas. El paper menciona la importancia de la formación continua y certificaciones específicas, que ayudan a estandarizar conocimientos y prácticas.&lt;/p&gt;
&lt;p&gt;Pero más allá de las certificaciones, hay una idea que atraviesa todo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;la ciberseguridad es un campo en constante cambio&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Esto implica que el aprendizaje no es algo puntual, sino continuo.&lt;/p&gt;
&lt;h2&gt;🚀 Nuevas tecnologías, nuevos desafíos&lt;/h2&gt;
&lt;p&gt;El paper también aborda cómo ciertas tecnologías emergentes están redefiniendo el panorama de la seguridad.&lt;/p&gt;
&lt;p&gt;Entre ellas se destacan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;el uso de inteligencia artificial para detectar amenazas&lt;/li&gt;
&lt;li&gt;la expansión de dispositivos IoT (Internet of Things)&lt;/li&gt;
&lt;li&gt;la migración hacia servicios en la nube&lt;/li&gt;
&lt;li&gt;la automatización de procesos de ataque y defensa&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Estas tecnologías no solo mejoran la seguridad, sino que también abren nuevas superficies de ataque, lo que vuelve aún más importante el enfoque proactivo.&lt;/p&gt;
&lt;h2&gt;🧠 Una forma distinta de pensar la seguridad&lt;/h2&gt;
&lt;p&gt;Más allá de lo técnico, lo que deja este análisis es un cambio de perspectiva.&lt;/p&gt;
&lt;p&gt;La seguridad ya no puede pensarse como algo estático o definitivo. No existe un sistema completamente seguro, sino sistemas que se adaptan, se prueban y se mejoran constantemente.&lt;/p&gt;
&lt;p&gt;El ethical hacking, en este sentido, no es solo una herramienta, sino una forma de pensar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cuestionar lo que parece seguro&lt;/li&gt;
&lt;li&gt;asumir que puede haber fallas&lt;/li&gt;
&lt;li&gt;buscar esas fallas activamente&lt;/li&gt;
&lt;li&gt;aprender de ellas&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;💬 Conclusión&lt;/h2&gt;
&lt;p&gt;El paper muestra con bastante claridad que la ciberseguridad moderna necesita evolucionar junto con las amenazas que enfrenta.&lt;/p&gt;
&lt;p&gt;Integrar el ethical hacking dentro de las estrategias de seguridad permite a las organizaciones anticiparse, detectar vulnerabilidades y fortalecer sus sistemas de forma continua.&lt;/p&gt;
&lt;p&gt;Pero también deja una enseñanza más general:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;la seguridad no se trata de evitar todos los errores, sino de detectarlos y corregirlos a tiempo&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;En un entorno digital que cambia constantemente, esa capacidad de adaptación es, probablemente, la herramienta más importante de todas.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ijcsmc.com/docs/papers/August2025/V14I8202506.pdf&quot;&gt;Link al paper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Antes de escribir código, dibujé Ciphie en papel</title><link>https://fuwari.vercel.app/posts/markdown-extended/</link><guid isPermaLink="true">https://fuwari.vercel.app/posts/markdown-extended/</guid><pubDate>Fri, 13 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;div class=&quot;content-es&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;Hay una tentación enorme cuando tenés una idea: abrir el editor y empezar a escribir código. La adrenalina de ver algo funcionar rápido es difícil de resistir.&lt;/p&gt;
&lt;p&gt;Con Ciphie no lo hice.&lt;/p&gt;
&lt;p&gt;No porque tenga una disciplina especial. Sino porque me di cuenta de que no sabía exactamente qué quería construir. Tenía una dirección — un gestor de secretos local, cifrado, sin dependencias de la nube — pero no tenía claridad sobre cómo las piezas encajaban entre sí. Y en un proyecto de seguridad, empezar a codear sin esa claridad es una forma segura de construir algo con agujeros que no vas a ver hasta que sea tarde.&lt;/p&gt;
&lt;p&gt;Así que antes de escribir una sola línea, me senté con papel y dibujé el sistema.&lt;/p&gt;
&lt;h2&gt;La pregunta que ordenó todo&lt;/h2&gt;
&lt;p&gt;El primer ejercicio fue simple: escribir en una sola oración qué hacía Ciphie.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Un gestor de secretos que cifra cada entrada individualmente, corre sin servidor central y requiere autenticación para acceder.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Esa frase parece obvia. Pero escribirla me obligó a tomar tres decisiones que no había tomado todavía: cifrado por entrada (no del archivo completo), sin servidor central (toda la lógica y los datos viven en la máquina del usuario), y autenticación (usuarios, contraseñas, sesiones). Ciphie sí puede hacer llamadas de red para features opcionales — verificación de cuenta por email, SMS via Twilio, TOTP — pero ninguna de esas integraciones es requerida para que el núcleo funcione.&lt;/p&gt;
&lt;p&gt;Cada una de esas palabras abría preguntas nuevas. ¿Cómo se deriva la clave de cifrado? ¿Dónde vive la base de datos? ¿Qué pasa si alguien falla el login cinco veces seguidas?&lt;/p&gt;
&lt;p&gt;Antes de tocar el teclado, tenía una página llena de preguntas.&lt;/p&gt;
&lt;h2&gt;Dibujar el flujo, no el código&lt;/h2&gt;
&lt;p&gt;Lo primero que dibujé no fue una arquitectura técnica. Fue el recorrido de un usuario hipotético a través de la aplicación.&lt;/p&gt;
&lt;p&gt;Alguien abre Ciphie. Ingresa su contraseña. Pasa el segundo factor. Ve su lista de secretos. Agrega uno nuevo. Lo recupera cuando lo necesita. Cierra la app.&lt;/p&gt;
&lt;p&gt;Ese flujo parece trivial. Pero cuando lo dibujás paso a paso, aparecen las preguntas que importan: ¿qué pasa si la contraseña es incorrecta? ¿Cuántas veces puede fallar antes de bloquearse? ¿Cómo se maneja una sesión? ¿Qué sucede si la app queda abierta sin actividad?&lt;/p&gt;
&lt;p&gt;Cada bifurcación en el flujo era una decisión de diseño. Y es mucho más fácil tomar esas decisiones en papel, donde borrar y rehacer no cuesta nada, que en código, donde cada cambio arrastra consecuencias.&lt;/p&gt;
&lt;h2&gt;Las tres capas que aparecieron solas&lt;/h2&gt;
&lt;p&gt;Cuando terminé de dibujar el flujo, algo interesante pasó: el sistema se organizó naturalmente en tres capas sin que yo lo planeara explícitamente.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La capa de autenticación.&lt;/strong&gt; Todo lo que tiene que ver con usuarios: registro, login, hashing de contraseñas, segundo factor, bloqueo por intentos fallidos, cierre de sesión automático. Esta capa no sabe nada de secretos — solo sabe quién está adentro y quién no.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La capa de datos.&lt;/strong&gt; Todo lo que tiene que ver con secretos: guardarlos, cifrarlos, recuperarlos, organizarlos por categoría, asociarlos a un usuario. Esta capa no sabe nada de autenticación — recibe un usuario ya verificado y opera sobre sus datos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La capa de interfaz.&lt;/strong&gt; Todo lo visual: la ventana, los campos, los botones, los mensajes de error. Esta capa no sabe nada de cifrado ni de autenticación — recibe información para mostrar y devuelve acciones del usuario.&lt;/p&gt;
&lt;p&gt;Esa separación no fue una decisión arquitectónica deliberada. Emergió de dibujar el flujo y preguntarme: ¿quién sabe qué acá?&lt;/p&gt;
&lt;h2&gt;Lo que el papel reveló que el código hubiera ocultado&lt;/h2&gt;
&lt;p&gt;Hubo un momento específico en el diseño que me alegra haber resuelto antes de codear.&lt;/p&gt;
&lt;p&gt;Estaba dibujando el flujo de cifrado y me pregunté: ¿la clave de cifrado viene de la contraseña del usuario o de una clave maestra separada?&lt;/p&gt;
&lt;p&gt;Si viene de la contraseña, cambiar la contraseña implica recifrar todos los secretos. Si viene de una clave maestra, esa clave necesita estar guardada en algún lugar — y ese lugar se convierte en el punto más sensible del sistema.&lt;/p&gt;
&lt;p&gt;Ninguna de las dos opciones es perfecta. Pero es un trade-off que necesitaba entender antes de empezar a construir, porque afecta toda la arquitectura. Si hubiera empezado a codear sin pensar en esto, hubiera tomado una decisión implícita sin darme cuenta — probablemente la más conveniente en ese momento, no la más correcta.&lt;/p&gt;
&lt;p&gt;En papel, pude ver el trade-off completo antes de comprometerme con una dirección.&lt;/p&gt;
&lt;h2&gt;Cuándo el papel se termina&lt;/h2&gt;
&lt;p&gt;Hay un punto en el que seguir diseñando en papel se convierte en una forma de no empezar. Ese punto llegó cuando las preguntas que quedaban solo podían responderse escribiendo código.&lt;/p&gt;
&lt;p&gt;¿Cómo se va a sentir el flujo de login? ¿El segundo factor va a ser lo suficientemente fluido? ¿La interfaz va a comunicar bien el estado del sistema?&lt;/p&gt;
&lt;p&gt;Esas preguntas no tienen respuesta en papel. Solo se responden cuando hay algo corriendo.&lt;/p&gt;
&lt;p&gt;El diseño previo no reemplaza la experimentación — la hace más eficiente. Llegás al editor sabiendo qué estás construyendo, con las decisiones grandes ya tomadas, y podés concentrarte en las preguntas que solo el código puede responder.&lt;/p&gt;
&lt;h2&gt;Lo que me llevaría a cualquier proyecto nuevo&lt;/h2&gt;
&lt;p&gt;Si tuviera que resumir lo que aprendí de este proceso en algo concreto, sería esto:&lt;/p&gt;
&lt;p&gt;Antes de abrir el editor, escribí en una sola oración qué hace el proyecto. Después dibujá el recorrido completo de un usuario. Después preguntate, en cada paso: ¿quién sabe qué acá?&lt;/p&gt;
&lt;p&gt;Esas tres cosas no garantizan un buen proyecto. Pero garantizan que cuando escribas la primera línea de código, sabés por qué la estás escribiendo.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Ciphie todavía no está publicado — estoy terminando los últimos detalles antes de la primera versión.&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&quot;content-en&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;There&apos;s an enormous temptation when you have an idea: open the editor and start writing code. The adrenaline of seeing something work quickly is hard to resist.&lt;/p&gt;
&lt;p&gt;With Ciphie I didn&apos;t do that.&lt;/p&gt;
&lt;p&gt;Not because I have special discipline. But because I realized I didn&apos;t know exactly what I wanted to build. I had a direction — a local secrets manager, encrypted, with no cloud dependencies — but I didn&apos;t have clarity on how the pieces fit together. And in a security project, starting to code without that clarity is a sure way to build something with holes you won&apos;t see until it&apos;s too late.&lt;/p&gt;
&lt;p&gt;So before writing a single line, I sat down with paper and drew the system.&lt;/p&gt;
&lt;h2&gt;The question that organized everything&lt;/h2&gt;
&lt;p&gt;The first exercise was simple: write in a single sentence what Ciphie did.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;A secrets manager that encrypts each entry individually, runs without a central server, and requires authentication to access.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That sentence seems obvious. But writing it forced me to make three decisions I hadn&apos;t made yet: per-entry encryption (not the whole file), no central server (all logic and data live on the user&apos;s machine), and authentication (users, passwords, sessions). Ciphie can make network calls for optional features — email account verification, SMS via Twilio, TOTP — but none of those integrations are required for the core to work.&lt;/p&gt;
&lt;p&gt;Each of those words opened new questions. How is the encryption key derived? Where does the database live? What happens if someone fails the login five times in a row?&lt;/p&gt;
&lt;p&gt;Before touching the keyboard, I had a page full of questions.&lt;/p&gt;
&lt;h2&gt;Drawing the flow, not the code&lt;/h2&gt;
&lt;p&gt;The first thing I drew wasn&apos;t a technical architecture. It was the journey of a hypothetical user through the application.&lt;/p&gt;
&lt;p&gt;Someone opens Ciphie. Enters their password. Passes the second factor. Sees their list of secrets. Adds a new one. Retrieves it when needed. Closes the app.&lt;/p&gt;
&lt;p&gt;That flow seems trivial. But when you draw it step by step, the questions that matter appear: what happens if the password is wrong? How many times can it fail before locking? How is a session managed? What happens if the app is left open without activity?&lt;/p&gt;
&lt;p&gt;Every branch in the flow was a design decision. And it&apos;s much easier to make those decisions on paper, where erasing and redoing costs nothing, than in code, where every change drags consequences.&lt;/p&gt;
&lt;h2&gt;The three layers that appeared on their own&lt;/h2&gt;
&lt;p&gt;When I finished drawing the flow, something interesting happened: the system naturally organized itself into three layers without me explicitly planning it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The authentication layer.&lt;/strong&gt; Everything related to users: registration, login, password hashing, second factor, lockout on failed attempts, automatic session logout. This layer knows nothing about secrets — it only knows who&apos;s in and who&apos;s not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The data layer.&lt;/strong&gt; Everything related to secrets: storing them, encrypting them, retrieving them, organizing them by category, associating them with a user. This layer knows nothing about authentication — it receives an already-verified user and operates on their data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The interface layer.&lt;/strong&gt; Everything visual: the window, the fields, the buttons, the error messages. This layer knows nothing about encryption or authentication — it receives information to display and returns user actions.&lt;/p&gt;
&lt;p&gt;That separation wasn&apos;t a deliberate architectural decision. It emerged from drawing the flow and asking myself: who knows what here?&lt;/p&gt;
&lt;h2&gt;What the paper revealed that the code would have hidden&lt;/h2&gt;
&lt;p&gt;There was a specific moment in the design that I&apos;m glad I resolved before coding.&lt;/p&gt;
&lt;p&gt;I was drawing the encryption flow and asked myself: does the encryption key come from the user&apos;s password or from a separate master key?&lt;/p&gt;
&lt;p&gt;If it comes from the password, changing the password means re-encrypting all secrets. If it comes from a master key, that key needs to be stored somewhere — and that place becomes the most sensitive point in the system.&lt;/p&gt;
&lt;p&gt;Neither option is perfect. But it&apos;s a trade-off I needed to understand before starting to build, because it affects the entire architecture. If I had started coding without thinking about this, I would have made an implicit decision without realizing it — probably the most convenient one at the time, not the most correct.&lt;/p&gt;
&lt;p&gt;On paper, I could see the complete trade-off before committing to a direction.&lt;/p&gt;
&lt;h2&gt;When the paper runs out&lt;/h2&gt;
&lt;p&gt;There&apos;s a point where continuing to design on paper becomes a way of not starting. That point came when the remaining questions could only be answered by writing code.&lt;/p&gt;
&lt;p&gt;How will the login flow feel? Will the second factor be smooth enough? Will the interface communicate the system&apos;s state well?&lt;/p&gt;
&lt;p&gt;Those questions have no answer on paper. They&apos;re only answered when something is running.&lt;/p&gt;
&lt;p&gt;Prior design doesn&apos;t replace experimentation — it makes it more efficient. You arrive at the editor knowing what you&apos;re building, with the big decisions already made, and you can focus on the questions that only code can answer.&lt;/p&gt;
&lt;h2&gt;What I&apos;d take to any new project&lt;/h2&gt;
&lt;p&gt;If I had to summarize what I learned from this process into something concrete, it would be this:&lt;/p&gt;
&lt;p&gt;Before opening the editor, write in a single sentence what the project does. Then draw the complete journey of a user. Then ask yourself, at every step: who knows what here?&lt;/p&gt;
&lt;p&gt;Those three things don&apos;t guarantee a good project. But they guarantee that when you write the first line of code, you know why you&apos;re writing it.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Ciphie isn&apos;t published yet — I&apos;m finishing the last details before the first version.&lt;/p&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
</content:encoded></item></channel></rss>