Este artículo analiza lo que sucede cuando un usuario envía un formulario:
¿a dónde van los datos y cómo lo manejamos cuando llega? También analizamos
algunas de las inquietudes de seguridad asociadas con el envío de datos del
formulario.
Requisitos previos: alfabetización básica en informática, comprensión de
HTML y conocimiento básico de HTTP y programación del lado del servidor.
Objetivo: comprender qué sucede cuando se envían los datos del formulario,
incluida la obtención de una idea básica de cómo se procesan los datos en el
servidor
¿A dónde van los datos?
Aquí discutiremos qué sucede con los datos cuando se envía un formulario.
La web se basa en una arquitectura cliente / servidor muy básica que se
puede resumir de la siguiente manera: un cliente (generalmente un navegador
web) envía una solicitud a un servidor (la mayoría de las veces un servidor web
como Apache, Nginx, IIS, Tomcat, etc.), usando el protocolo HTTP. El servidor
responde la solicitud utilizando el mismo protocolo.
En el lado del cliente, un formulario HTML no es más que una forma
conveniente y fácil de usar para configurar una solicitud HTTP para enviar
datos a un servidor. Esto permite al usuario proporcionar información para ser
entregada en la solicitud HTTP.
Nota: Para tener una mejor idea de cómo funcionan las arquitecturas
cliente-servidor, lea el módulo de primeros pasos de programación del lado del servidor.
Del lado del cliente: definir cómo enviar los datos
El elemento
<form> define cómo se enviarán los datos. Todos sus
atributos están diseñados para permitirle configurar la solicitud que se
enviará cuando un usuario presione un botón de enviar. Los dos atributos más
importantes son
action
y
method
.
El atributo action
Este atributo define dónde se envían los datos. Su valor debe ser una URL válida. Si no se proporciona este atributo, los datos se enviarán a la URL de la página que contiene el formulario.
En este ejemplo, los datos se envían a una URL absoluta -
http://foo.com:
<fom action="http://foo.com">
Aquí, usamos una URL relativa: los datos se envían a una URL diferente en el servidor:
<fom action="/somewhere_else">
Cuando se especifica sin atributos, como se muestra a continuación, los datos de
<form> se envían a la misma página donde está presente el formulario:
<form>
Muchas páginas anteriores usan la siguiente notación para indicar que los datos deben enviarse a la misma página que contiene el formulario; esto fue necesario porque hasta HTML5, se requería el atributo de acción. Esto ya no es necesario.
<form action="#">
Nota: Es posible especificar una URL que utiliza el protocolo HTTPS (HTTP seguro). Cuando hace esto, los datos se cifran junto con el resto de la solicitud, incluso si el formulario en sí está alojado en una página insegura a la que se accede mediante HTTP. Por otro lado, si el formulario está alojado en una página segura pero especifica una URL HTTP insegura con el atributo de acción, todos los navegadores muestran una advertencia de seguridad al usuario cada vez que intentan enviar datos porque los datos no se cifrarán.
El atributo method
Este atributo define cómo se envían los datos. El
protocolo HTTP proporciona varias formas de realizar una solicitud; Los datos del formulario HTML pueden transmitirse a través de varios diferentes, los más comunes son el método GET y el método POST.
Para entender la diferencia entre esos dos métodos, retrocedamos y examinemos cómo funciona HTTP. Cada vez que desee llegar a un recurso en la Web, el navegador envía una solicitud a una URL. Una solicitud HTTP consta de dos partes: un encabezado que contiene un conjunto de metadatos globales sobre las capacidades del navegador y un cuerpo que puede contener la información necesaria para que el servidor procese la solicitud específica.
El método GET
El método GET es el método utilizado por el navegador para pedirle al servidor que le devuelva un recurso determinado: "Hola, servidor, quiero obtener este recurso". En este caso, el navegador envía un cuerpo vacío. Como el cuerpo está vacío, si se envía un formulario con este método, los datos enviados al servidor se anexan a la URL.
Considere la siguiente forma:
<form action="http://foo.com" method="get">
<div>
<label for="say">What greeting do you want to say?</label>
<input name="say" id="say" value="Hi">
</div>
<div>
<label for="to">Who do you want to say it to?</label>
<input name="to" value="Mom">
</div>
<div>
<button>Send my greetings</button>
</div>
</form>
Dado que se ha utilizado el método GET, verá que la URL
www.foo.com/?say=Hi&to=Mom aparece en la barra de direcciones del navegador cuando envía el formulario.
Los datos se anexan a la URL como una serie de pares nombre/valor. Después de que la dirección web de la URL haya finalizado, incluimos un signo de interrogación (?) Seguido de los pares nombre/valor, cada uno separado por un símbolo comercial (&). En este caso, estamos pasando dos datos al servidor:
- say, que tiene un valor de Hi
- to, que tiene un valor de Mom
La solicitud HTTP se ve así:
GET /?say=Hi&to=Mom HTTP/1.1
Host foo.com
Puede encontrar este ejemplo en
GitHub - get-method.html
El método POST
El método POST es un poco diferente. Es el método que utiliza el navegador para comunicarse con el servidor cuando solicita una respuesta que tenga en cuenta los datos proporcionados en el cuerpo de la solicitud HTTP: "Hola, servidor, eche un vistazo a estos datos y envíeme un resultado apropiado". Si se envía un formulario utilizando este método, los datos se anexan al cuerpo de la solicitud HTTP.
Veamos un ejemplo: esta es la misma forma que vimos en la sección GET anterior, pero con el atributo method establecido en POST.
<form action="http://foo.com" method="post">
<div>
<label for="say">What greeting do you want to say?</label>
<input name="say" id="say" value="Hi">
</div>
<div>
<label for="to">Who do you want to say it to?</label>
<input name="to" value="Mom">
</div>
<div>
<button>Send my greetings</button>
</div>
</form>
Cuando el formulario se envía utilizando el método POST, no obtiene datos agregados a la URL, y la solicitud HTTP se ve así, con los datos incluidos en el cuerpo de la solicitud en su lugar:
POST / HTTP/1.1
Host: foo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
say=Hi&to=Mom
El encabezado Content-Length indica el tamaño del cuerpo y el encabezado Content-Type indica el tipo de recurso enviado al servidor. Discutiremos estos encabezados más adelante.
Nota: Puede encontrar este ejemplo en
GitHub - post-method.html
Ver solicitudes HTTP
Las solicitudes HTTP nunca se muestran al usuario (si desea verlas, debe usar herramientas como
Firefox Network Monitor o
Chrome Developer Tools). Como ejemplo, los datos de su formulario se mostrarán de la siguiente manera en la pestaña Red de Chrome:
Lo único que se muestra al usuario es la URL llamada. Como mencionamos anteriormente, con una solicitud GET el usuario verá los datos en su barra de URL, pero con una solicitud POST no lo harán. Esto puede ser muy importante por dos razones:
1. Si necesita enviar una contraseña (o cualquier otro dato sensible), nunca use el método GET o corre el riesgo de mostrarlo en la barra de URL, lo que sería muy inseguro.
2. Si necesita enviar una gran cantidad de datos, se prefiere el método POST porque algunos navegadores limitan el tamaño de las URL. Además, muchos servidores limitan la longitud de las URL que aceptan.
En el lado del servidor: recuperar los datos
Sea cual sea el método HTTP que elija, el servidor recibe una cadena que se analizará para obtener los datos como una lista de pares clave / valor. La forma de acceder a esta lista depende de la plataforma de desarrollo que utilice y de los marcos específicos que pueda usar con ella. La tecnología que utiliza también determina cómo se manejan las claves duplicadas; a menudo, el valor recibido más recientemente para una clave dada tiene prioridad.
Ejemplo: Raw PHP
PHP ofrece algunos objetos globales para acceder a los datos. Suponiendo que haya utilizado el método POST, el siguiente ejemplo simplemente toma los datos y los muestra al usuario. Por supuesto, lo que hagas con los datos depende de ti. Puede mostrarlo, almacenarlo en una base de datos, enviarlo por correo electrónico o procesarlo de alguna otra manera.
<?php
// The global $_POST variable allows you to access the data sent with the
// POST method by name
// To access the data sent with the GET method, you can use $_GET
$say = htmlspecialchars($_POST['say']);
$to = htmlspecialchars($_POST['to']);
echo $say, ' ', $to;
?>
Este ejemplo muestra una página con los datos que enviamos. Puede ver esto en acción en nuestro ejemplo de archivo
php-example.html, que contiene el mismo formulario de ejemplo que vimos anteriormente, con un méthod POST y una action de
php-example.php en nuestro ejemplo anterior. Cuando se envía, envía los datos del formulario a php-example.php, que contiene el código PHP que se ve en el bloque anterior. Cuando se ejecuta este código, la salida en el navegador es Hi Mom.
Nota: Este ejemplo no funcionará cuando lo cargue localmente en un navegador: los navegadores no pueden interpretar el código PHP, de modo que cuando se envíe el formulario, el navegador solo ofrecerá descargar el archivo PHP por usted. Para que funcione, necesita ejecutar el ejemplo a través de un servidor PHP de algún tipo. Buenas opciones para las pruebas locales de PHP son MAMP (Mac y Windows) y AMPPS (Mac, Windows, Linux).
Ejemplo: Python
Este ejemplo muestra cómo usaría Python para hacer lo mismo: mostrar los datos enviados en una página web. Utiliza el
Flask framework para representar las plantillas, gestionar el envío de datos de formulario, etc. (ver
python-example.py).
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def form():
return render_template('form.html')
@app.route('/hello', methods=['GET', 'POST'])
def hello():
return render_template('greeting.html', say=request.form['say'],
to=request.form['to'])
if __name__ == "__main__":
app.run()
Las dos plantillas a las que se hace referencia en el código anterior son las siguientes:
form.html: la misma forma que vimos anteriormente en la sección del método POST, pero con la acción establecida en {{url_for ('hello')}}. (Esta es una plantilla
Jinja2, que es básicamente HTML pero puede contener llamadas al código Python que ejecuta el servidor web contenido entre llaves) url_for ('hello') básicamente dice "redirigir a / hello cuando se envía el formulario" .)
greeting.html: esta plantilla solo contiene una línea que representa los dos bits de datos que se le pasan cuando se procesa. Esto se realiza a través de la función hello () que se muestra arriba, que se ejecuta cuando se navega a / hello URL.
Nota: De nuevo, este código no funcionará si solo intenta cargarlo en un navegador directamente. Python funciona de manera diferente a PHP: para ejecutar este código localmente, necesitarás
instalar Python / PIP, luego instalar pip3 install Flask. En este punto, debería poder ejecutar el ejemplo usando python3 python-example.py, luego navegando a localhost: 5000 en su navegador.
Otros lenguajes y frameworks
Hay muchas otras tecnologías del lado del servidor que puede usar para el manejo de formularios, como
Perl,
Java,
.Net,
Ruby, etc. Simplemente elija la que más le guste. Dicho esto, vale la pena señalar que es muy poco común usar estas tecnologías directamente porque esto puede ser complicado. Es más común usar uno de los muchos frameworks que facilitan el manejo de formularios, como:
Symfony para
PHP
Django para
Python (un poco más pesado que
Flask, pero con más herramientas y opciones).
Express para
Node.js
Ruby On Rails para
Ruby
Grails para
Java
etc.
Vale la pena señalar que incluso utilizando estos frameworks, trabajar con formularios no es necesariamente fácil. Pero es mucho más fácil que tratar de escribir todas las funciones desde cero y le ahorrará mucho tiempo.
Nota: está más allá del alcance de este artículo enseñarle cualquier lenguajes o frameworks del lado del servidor. Los enlaces de arriba le brindarán ayuda, en caso de que desee aprenderlos.
Un caso especial: envío de archivos
El envío de archivos con formularios HTML es un caso especial. Los archivos son datos binarios, o considerados como tales, mientras que todos los demás datos son datos de texto. Debido a que HTTP es un protocolo de texto, existen requisitos especiales para manejar datos binarios.
El atributo enctype
Este atributo le permite especificar el valor del encabezado HTTP Content-Type incluido en la solicitud generada cuando se envía el formulario. Este encabezado es muy importante porque le dice al servidor qué tipo de datos se envían. Por defecto, su valor es
application/x-www-form-url-encoded. En términos humanos, esto significa: "Esto es información de formulario codificada en parámetros de URL".
Si desea enviar archivos, debe realizar tres pasos adicionales:
- Establezca el atributo
method en POST porque el contenido del archivo no puede colocarse dentro de los parámetros de URL.
- Establezca el valor de
enctype en
multipart/form-data porque los datos se dividirán en varias partes, una para cada archivo más una para los datos de texto incluidos en el cuerpo del formulario (si el texto también se ingresa en el formulario).
- Incluya uno o más widgets de
file-picker para permitir que los usuarios seleccionen los archivos que se cargarán.
Por ejemplo:
<form method="post" enctype="multipart/form-data">
<div>
<label for="file">Choose a file</label>
<input type="file" id="file" name="myFile">
</div>
<div>
<button>Send the file</button>
</div>
</form>
Nota: Algunos navegadores admiten el atributo multiple en el elemento <input>, que permite elegir más de un archivo para cargar con solo un elemento <input>. Cómo maneja el servidor esos archivos realmente depende de la tecnología utilizada en el servidor. Como se mencionó anteriormente, usar un framework hará su vida mucho más fácil.
Advertencia: Muchos servidores están configurados con un límite de tamaño para archivos y solicitudes HTTP para evitar abusos. Es importante verificar este límite con el administrador del servidor antes de enviar un archivo.
Problemas comunes de seguridad
Cada vez que envía datos a un servidor, debe considerar la seguridad. Los formularios HTML son, con diferencia, los vectores de ataque más comunes (lugares donde pueden ocurrir ataques) contra servidores. Los problemas nunca provienen de los propios formularios HTML; provienen de cómo el servidor maneja los datos.
Dependiendo de lo que esté haciendo, hay algunos problemas de seguridad muy conocidos con los que se enfrentará:
XSS y CSRF
Cross-Site Scripting (XSS) y
Cross-Site Request Forgery (CSRF) son tipos comunes de ataques que ocurren cuando muestra datos enviados por un usuario al usuario o a otro usuario.
XSS permite a los atacantes inyectar el script del lado del cliente en páginas web vistas por otros usuarios. Los atacantes pueden usar una vulnerabilidad de secuencias de comandos entre sitios para eludir los controles de acceso, como la
misma política de origen. El efecto de estos ataques puede variar desde una molestia menor a un riesgo de seguridad significativo.
Los ataques
CSRF son similares a los ataques
XSS ya que comienzan de la misma manera, al inyectar secuencias de comandos del lado del cliente en las páginas web, pero su objetivo es diferente. Los atacantes de
CSRF intentan escalar los privilegios a los de un usuario de mayor privilegio (como un administrador de sitio) para realizar una acción que no deberían poder realizar (por ejemplo, enviar datos a un usuario que no es de confianza).
Los ataques
XSS explotan la confianza que un usuario tiene en un sitio web, mientras que los ataques
CSRF explotan la confianza que un sitio web tiene para sus usuarios.
Para evitar estos ataques, siempre debe verificar los datos que un usuario envía a su servidor y (si necesita mostrarlos) intente no mostrar el contenido HTML tal como lo proporciona el usuario. En su lugar, debe procesar los datos proporcionados por el usuario para que no los muestre al pie de la letra. Casi todos los frameworks en el mercado actual implementan un filtro mínimo que elimina los elementos HTML
<script>,
<iframe> y
<object> de los datos enviados por cualquier usuario. Esto ayuda a mitigar el riesgo, pero no necesariamente lo erradica.
Inyección SQL
La inyección
SQL es un tipo de ataque que intenta realizar acciones en una base de datos utilizada por el sitio web objetivo. Esto generalmente implica el envío de una solicitud
SQL con la esperanza de que el servidor la ejecute (generalmente cuando el servidor de aplicaciones intenta almacenar datos enviados por un usuario). Este es en realidad uno de los
principales vectores de ataque contra sitios web.
Las consecuencias pueden ser terribles, desde la pérdida de datos hasta ataques que toman el control de la infraestructura de un sitio web completo mediante el uso de escalada de privilegios. Esta es una amenaza muy seria y nunca debe almacenar datos enviados por un usuario sin realizar una desinfección (por ejemplo, al usar
mysql_real_escape_string () en una infraestructura
PHP/MySQL).
Inyección de encabezado HTTP e inyección de correo electrónico
Este tipo de ataques pueden ocurrir cuando su aplicación genera encabezados HTTP o correos electrónicos basados en los datos ingresados por un usuario en un formulario. Esto no dañará directamente su servidor ni afectará a sus usuarios, pero son una puerta abierta a problemas más profundos, como el secuestro de sesiones o los ataques de phishing.
Estos ataques son en su mayoría silenciosos, y pueden convertir tu servidor en un
zombie.
Sé paranoico: nunca confíes en tus usuarios
Entonces, ¿cómo luchas contra estas amenazas? Este es un tema mucho más allá de esta guía, pero hay algunas reglas para tener en cuenta. La regla más importante es:
nunca confíes en tus usuarios, incluyéndote a ti; incluso un usuario de confianza podría haber sido secuestrado.
Todos los datos que llegan a su servidor deben ser revisados y desinfectados. Siempre. Sin excepción.
1. Escapa de personajes potencialmente peligrosos. Los caracteres específicos con los que debe tener precaución varían según el contexto en el que se usan los datos y la plataforma del servidor que emplea, pero todos los idiomas del lado del servidor tienen funciones para esto.
2. Limite la cantidad de datos entrantes para permitir solo lo que sea necesario.
3. Archivos cargados Sandbox (almacénelos en un servidor diferente y permita el acceso al archivo solo a través de un subdominio diferente o incluso mejor a través de un nombre de dominio completamente diferente).
Debería evitar muchos/la mayoría de los problemas si sigue estas tres reglas, pero siempre es una buena idea obtener una revisión de seguridad realizada por un tercero competente. No suponga que ha visto todos los posibles problemas.
Nota: El artículo de seguridad del sitio web de nuestro tema de aprendizaje del lado del servidor analiza las amenazas anteriores y las posibles soluciones con más detalle.
Conclusión
Como puede ver, enviar datos de formulario es fácil, pero asegurar una aplicación puede ser complicado. Solo recuerde que un desarrollador front-end no es quien debe definir el modelo de seguridad de los datos. Sí, como veremos, es posible realizar la
validación de los datos del lado del cliente, pero el servidor no puede confiar en esta validación porque no tiene forma de saber realmente qué sucede realmente en el lado del cliente.
fuente: https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data