Qué tener en cuenta en seguridad — no confiar en la entrada y proteger los secretos

Este artículo forma parte del curso Fundamentos de informática, que construye desde cero los conocimientos prácticos de informática que necesitas como mínimo para programar y hacer vibe coding.
Hay dos puntos básicos: no confiar en lo que introduce el usuario y proteger la información secreta. Con diagramas comprobamos cómo se producen la inyección SQL y el XSS.

Este artículo trata dos de los puntos que hay que tener en cuenta en seguridad.

Uno es no usar tal cual el texto que escribe el usuario y el otro es no poner valores secretos en lugares donde más gente puede leerlos.

  • Por qué la validación de la entrada se hace en el servidor
  • La inyección SQL, que se produce al unir la entrada a una sentencia, y los marcadores de posición
  • El XSS, que se evita con el escapado justo antes de mostrar el texto en la pantalla
  • Dónde puedes guardar la información secreta, como las claves de API y las contraseñas

Cualquiera de estas cosas, si ocurre después de publicar, no se puede deshacer, y los datos que ya se leyeron no se recuperan.

«No hay validación de la entrada» significa usar el valor tal como llega

La validación de la entrada (input validation) consiste en comprobar, antes de usar un valor que ha llegado, que tiene el formato, la longitud y el rango previstos.

Para cada campo fijas una condición: el nombre, hasta 50 caracteres; el número de estrellas, de 1 a 5.

Valor que llegaCondición fijada de antemanoLo que hace el servidor
Campo nombre: AnaHasta 50 caracteres → encajaPasa a guardarse
Estrellas: 7Un número de 1 a 5 → no encajaLo rechaza sin guardarlo
Texto: vacíoUn carácter o más → no encajaLo rechaza sin guardarlo

Solo la primera fila cumple la condición y pasa a guardarse; las otras dos no se guardan y el servidor devuelve qué parte no encaja.

El control de la pantalla lo ejecuta el JavaScript (un programa que se ejecuta dentro del navegador) que llegó al dispositivo del usuario.

El usuario puede quitarlo y también puede enviar los datos directamente al servidor sin usar un navegador.

El mismo 7 se separa en dos caminos según cómo se envíe
Enviar un 7 enlas estrellasEnviarlo desdeel formularioQuitar el controly enviarloEl control de lapantalla lo frenaLlega al servidorsin ese controlEl servidor lorechaza al validar
El único valor de la izquierda se separa hacia arriba o hacia abajo según cómo se envíe. El camino de abajo no pasa por el control de la pantalla, así que sin validación en el servidor se guarda tal cual.

El control de la pantalla está para que el usuario vuelva a escribir la entrada, y lo único que decide si un valor se puede usar es la validación del servidor.

Si guardas sin validar, los valores que no cumplen las condiciones se quedan tal cual en la base de datos.

Un número de estrellas fuera de 1 a 5 descuadra las medias y el orden, y un valor que no se puede leer como número detiene el cálculo de los totales.

Para arreglar los valores que ya han entrado hay que revisar uno a uno los datos que quedan.

Comprueba en el servidor el valor que llega, antes de usarlo

La validación de la entrada consiste en mirar, antes de usar un valor que ha llegado, si cumple las condiciones que fijaste.

El control de la pantalla está para que el usuario reescriba la entrada en el momento y se puede quitar antes de enviar, así que compruebas lo mismo otra vez en el servidor.

Si unes la entrada a una sentencia, el texto escrito se ejecuta como una orden

Cuando busca por nombre las reseñas guardadas, el servidor arma una sentencia en SQL (Structured Query Language, el lenguaje con el que se dan órdenes a una base de datos).

Al unir el texto de la entrada a esa cadena, el conjunto se pasa como una sola.

Lo que hay dentro de la cadena que llega a la base de datos
Una sola cadena: la que recibe la base de datos
La parte que escribió el desarrollador
  • SELECT * FROM reviews WHERE name =
  • Una orden para sacar de la tabla reviews las filas cuyo name coincide
  • Esta forma ya está escrita de antemano en el código
La parte que vino del campo del nombre
  • Ana — un nombre corriente
  • ' OR '1'='1 — texto con símbolos
  • Lo que escribió el usuario entra tal cual en esta posición
El marco exterior es la cadena que pasa del servidor a la base de datos, ya unida en una sola. Una vez que ha pasado, las dos partes de dentro ya no se distinguen.

Una vez que ha pasado, la parte que escribió el desarrollador y la que vino del campo del nombre son partes de una misma cadena.

La base de datos lee entera, como una orden, la cadena que recibe.

Texto puesto en el campo del nombreSentencia que resulta de unirlosLo que devuelve la base de datos
Ananame = 'Ana'Solo las reseñas de Ana
Ana'name = 'Ana''La sentencia se rompe y da error
' OR '1'='1name = '' OR '1'='1'Todas las reseñas

Que el texto introducido se ejecute como una orden en lugar de como un valor es una inyección (injection), y la que se produce en la base de datos es la inyección SQL (SQL injection).

La forma de escribirlo que lo evita es el marcador de posición (placeholder, una forma de escribir en la que dentro de la sentencia solo se marca con un símbolo la posición donde va el valor y el valor se pasa aparte).

La misma entrada se separa en dos según cómo esté escrito el servidor
En el nombre:' OR '1'='1Unido tal cuala la sentenciaSentencia y valorpor separadoLee una cadenacomo sentenciaSolo busca elvalor como nombreDevuelve todaslas reseñasTermina en 0 filas
La única entrada de la izquierda se separa hacia arriba o hacia abajo según cómo esté escrita. Si la orden y el valor se pasan por separado, incluso el texto con símbolos se trata como un nombre.

Si se pasan por separado, la base de datos no lee el valor como una orden: busca ese texto como nombre y termina en 0 filas.

La validación comprueba el formato del valor y el marcador de posición hace que el valor se trate como valor sea cual sea su formato.

Como cumplen funciones distintas, se hacen las dos cosas.

No unas la sentencia y el texto de la entrada en una sola cadena

Al unir el texto de la entrada a una sentencia, hasta los símbolos escritos se leen como parte de la orden.

Si pasas la orden y el valor por separado, el texto con símbolos se trata como un simple nombre, así que mantienes las dos cosas: la validación que comprueba el formato y la forma de escribir que hace que el valor se trate como valor sea cual sea su formato.

Si no lo cambias justo antes de mostrarlo, lo publicado se ejecuta en el navegador de otro usuario

Lo mismo ocurre en el punto donde lo publicado sale a la pantalla.

Que el texto introducido se ejecute como JavaScript en el navegador de otro usuario es el XSS (Cross-Site Scripting).

La misma entrada recibe dos nombres según dónde se mezcle
Texto escritopor el usuarioSe mezcla en unasentencia SQLLa base de datoslo lee como ordenPasar sentenciay valor aparteSe mezcla en elHTML de la páginaOtro usuario lo veen su navegadorEscapar justoantes de mostrar
A la izquierda está lo que escribió el usuario. El camino de arriba es cuando se mezcla en una sentencia SQL y el de abajo cuando se mezcla en el HTML de la pantalla. Como quien lo lee es distinto, la solución también lo es.

En los dos casos la entrada se lee como una orden y lo único que cambia es quién la lee.

La solución del lado de la pantalla es el escapado (escape, convertir los caracteres que tienen un significado especial a una forma que se muestra como caracteres corrientes).

El punto que lo separa no está en el momento de guardar, sino justo antes de mostrarlo en la pantalla.

Carácter con significado especial en HTMLCómo se escribe tras la sustituciónCarácter que se ve en la pantalla
<&lt;<
>&gt;>
&&amp;&
"&quot;"
'&#x27;'

Si lo sustituyes justo antes de mostrarlo, lo publicado se queda en texto

Si sacas a la pantalla lo publicado tal cual, lo que llevaba mezclado dentro se ejecuta en el navegador de otro usuario.

Lo que detiene esto es la sustitución que se hace justo antes de mostrarlo y, como solo se sustituyen los símbolos, el texto que ve quien lee no cambia.

Los valores secretos no pasan al punto donde más gente puede leerlos

El otro punto es dónde se guarda la información secreta.

Lo que se mira aquí es cuánta gente puede leer el sitio donde la pusiste.

Hasta dónde llegan los archivos de my-app
Carpeta de trabajo de tu computadora
No se registra en Git (queda solo en tu computadora)
  • .env — los valores de las claves de API y las contraseñas
  • Archivos de configuración que solo usas en tu computadora
Se registra en Git (llega a todo el que reciba el código)
  • server.js — el código que se ejecuta en el servidor
  • .gitignore — la lista de archivos que no se registran
  • .env.example — un modelo con solo los nombres
Llega al navegador (lo lee cualquiera que abra la URL)
  • index.html — la pantalla de las reseñas
  • script.js — el código que se ejecuta en la pantalla
El marco exterior es la carpeta de trabajo de tu computadora. Cuanto más adentro está el marco en el que cae un archivo, más gente puede leerlo, así que en los marcos interiores no se escriben valores secretos.

Cuanto más adentro está el marco, más gente puede leerlo: script.js lo lee cualquiera y server.js, en cuanto se registra en Git, lo lee todo el que reciba el código.

Si escribes .env en .gitignore (un archivo que enumera los nombres de los archivos que Git no debe registrar), los valores no entran en el historial, pero

una vez registrados ya no se borran del historial pasado, así que se vuelven a generar los valores mismos.

Hasta dónde llega en GitHub un archivo registrado en Git
Registrar soloel códigoRepositoriopúblico en GitHubCualquiera en elmundo lo lee.env acabaregistrado tambiénEl archivo quedaen el historialAun borrado, sigueen el historialEscribirlo en.gitignoreNo entra enel historialQueda solo entu computadora
La fila de arriba es el código puesto en un repositorio público, la del medio es cuando también se registró el .env y la de abajo es cuando se escribió en .gitignore. De izquierda a derecha, dónde se pone determina quién puede leerlo.

Un valor que ha entrado en un repositorio público lo puede leer cualquiera en el mundo.

Dónde se guarda una clave de API y el círculo de gente que puede leerla
Lo lee cualquiera que abra la URL
  • script.js — el código que llega al navegador
  • El final de la URL a la que llamas
  • Los mensajes de error que salen en la pantalla
Lo lee todo el que reciba el código
  • server.js — el código que se registra en Git
  • .env una vez registrado — queda en el historial
Solo lo leen quienes pueden operar el servidor
  • Las variables de entorno del servidor — aquí van las claves de API y las contraseñas
Cuanto más afuera está el círculo, más gente puede leerlo. Los únicos sitios donde puedes poner un valor son los que están en el círculo más interior.

Lo único que entra en el círculo más interior son las variables de entorno del servidor.

No se escriben en los sitios de los dos círculos exteriores ni en los logs (el registro de la actividad que deja el servidor), que a veces se sacan fuera.

El my-app que se ejecuta dentro del recuadro de la derecha carga el valor de las variables de entorno.

Ese valor no entra en los dos recuadros de la izquierda, así que no aumenta la gente que puede leerlo.

Dónde guardarlo lo decide cuánta gente puede leerlo

El sitio donde puedes poner un valor secreto lo decide cuánta gente puede leer ese sitio.

Un archivo que llega al navegador lo lee cualquiera y un archivo registrado en Git llega a todo el que reciba el código, así que no lo escribes en ninguno de los dos y lo pones en las variables de entorno del servidor.

QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Por qué se valida también en el servidor, si los valores del formulario ya se comprueban en la pantalla?

Pregunta 2¿Qué hace el marcador de posición que evita la inyección SQL?

Pregunta 3¿Cuál es el sitio correcto para guardar la clave de API de un servicio externo?