CORS - Cross-Origin Resource Sharing - Lenguaje en C

¿Qué son los CORS y para qué sirven?

CORS (Cross-Origin Resource Sharing) es un mecanismo de seguridad utilizado en aplicaciones web para controlar cómo se permite que un navegador acceda a recursos en un servidor que tiene un dominio diferente (origen) al del sitio web que realiza la solicitud.

  • Origen cruzado: Cuando una página web de un dominio intenta acceder a un recurso (API, archivo, etc.) ubicado en otro dominio.
  • Finalidad de CORS:
    • Proteger contra ataques de tipo CSRF (Cross-Site Request Forgery).
    • Permitir el intercambio de recursos específicos entre diferentes dominios de forma segura.
    • Definir reglas de acceso mediante encabezados HTTP para que el servidor indique qué solicitudes de origen cruzado son permitidas.

Por ejemplo:

  • El navegador de http://example.com quiere acceder a datos desde http://api.example2.com.
  • Sin CORS, los navegadores bloquearán estas solicitudes por políticas de seguridad.

Encabezados clave en CORS:

  1. Access-Control-Allow-Origin:
    • Especifica qué dominios tienen permiso para acceder al recurso.
    • Ejemplo: Access-Control-Allow-Origin: * (permite acceso desde todos los dominios).
  2. Access-Control-Allow-Methods:
    • Lista de métodos HTTP permitidos para la solicitud (ej., GET, POST).
  3. Access-Control-Allow-Headers:
    • Define los encabezados HTTP permitidos por el servidor.
  4. Access-Control-Max-Age:
    • Especifica cuánto tiempo un cliente puede usar una respuesta en caché antes de realizar una nueva solicitud.

Código en lenguaje C para implementar soporte básico de CORS

A continuación, se presenta el código fuente avanzado de un servidor HTTP en C con soporte para CORS. Este servidor incluye encabezados CORS según estándares de seguridad y telecomunicaciones.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

void handle_request(int client_socket);
void send_response(int client_socket, const char *status, const char *content_type, const char *body, const char *cors_origin);

int main() {
    int server_fd, client_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    // Crear socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("Socket failed");
        exit(EXIT_FAILURE);
    }

    // Configurar dirección
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // Asociar socket
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }

    // Escuchar conexiones
    if (listen(server_fd, 3) < 0) {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }

    printf("Servidor HTTP con soporte CORS ejecutándose en el puerto %d\n", PORT);

    // Manejar clientes
    while (1) {
        if ((client_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) {
            perror("Error al aceptar conexión");
            continue;
        }

        handle_request(client_socket);
        close(client_socket);
    }

    return 0;
}

void handle_request(int client_socket) {
    char buffer[BUFFER_SIZE] = {0};
    read(client_socket, buffer, BUFFER_SIZE);

    // Imprimir solicitud recibida (opcional para depuración)
    printf("Solicitud recibida:\n%s\n", buffer);

    // Verificar si es una solicitud OPTIONS (verificación previa de CORS)
    if (strncmp(buffer, "OPTIONS", 7) == 0) {
        // Enviar respuesta para solicitudes preflight (verificación previa)
        send_response(client_socket, "204 No Content", NULL, NULL, "*");
    } else {
        // Enviar respuesta estándar con encabezados CORS
        const char *body = "<html><body><h1>Bienvenido al servidor CORS</h1></body></html>";
        send_response(client_socket, "200 OK", "text/html", body, "*");
    }
}

void send_response(int client_socket, const char *status, const char *content_type, const char *body, const char *cors_origin) {
    char response[BUFFER_SIZE] = {0};

    // Encabezados HTTP básicos
    snprintf(response, sizeof(response),
        "HTTP/1.1 %s\r\n"
        "Access-Control-Allow-Origin: %s\r\n"  // Permitir acceso desde cualquier origen
        "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
        "Access-Control-Allow-Headers: Content-Type\r\n"
        "Access-Control-Max-Age: 86400\r\n",  // Mantener respuestas preflight en caché por 1 día
        status, cors_origin);

    if (content_type && body) {
        // Agregar encabezados de contenido
        strncat(response, "Content-Type: ", sizeof(response) - strlen(response) - 1);
        strncat(response, content_type, sizeof(response) - strlen(response) - 1);
        strncat(response, "\r\n\r\n", sizeof(response) - strlen(response) - 1);
        strncat(response, body, sizeof(response) - strlen(response) - 1);
    } else {
        // Finalizar para respuesta preflight
        strncat(response, "\r\n", sizeof(response) - strlen(response) - 1);
    }

    // Enviar respuesta al cliente
    write(client_socket, response, strlen(response));
}

 

Características y estándares implementados:

  1. Cumple con estándares internacionales:
    • El soporte para CORS utiliza los encabezados HTTP definidos por la IETF (RFC 7231 y RFC 6454) para intercambio de recursos entre dominios. 
    • Maneja solicitudes preflight (método OPTIONS) y proporciona un caché para respuestas en hasta 24 horas (Access-Control-Max-Age).
  2. Características avanzadas:
    • Permite el acceso desde cualquier origen (Access-Control-Allow-Origin: *). 
    • Soporta métodos estándar como GET, POST y OPTIONS. 
    • Manejo básico de encabezados personalizados.
  3. Seguridad:
    • Aunque permite el acceso desde cualquier origen, puedes restringirlo a dominios específicos cambiando * por el dominio permitido (por ejemplo, Access-Control-Allow-Origin: https://example.com).

 

¿Cómo usarlo?

  1. Compilar el servidor: Guarda el código en un archivo llamado cors_server.c y compílalo con:
  2. gcc -o cors_server cors_server.c 
  3.  Ejecutar el servidor:
  4. ./cors_server 
  5. Hacer una solicitud desde la terminal:
    • Solicitudes OPTIONS para simulación de preflight:
    curl -X OPTIONS http://localhost:8080 -i 
    • Solicitudes normales GET o POST: 
    curl -X GET http://localhost:8080 -i 

 

¿Es viable en proyectos reales?

  • , este código cumple con los estándares básicos de telecomunicaciones, informática y seguridad para implementar CORS.
  • Para uso en proyectos reales, debes:
    • Implementar HTTPS (por ejemplo, con OpenSSL) para asegurar la transferencia de datos.
    • Agregar autenticación y control de acceso más refinado si los recursos son sensibles.
    • Extender el soporte para métodos HTTP adicionales, encabezados personalizados o reglas específicas para orígenes.

Este servidor puede integrarse en sistemas de backend modernos o incluso en aplicaciones embebidas para garantizar compatibilidad con aplicaciones web que requieren acceso entre dominios.

 

Interpretación del resultado

Servidor HTTP con soporte CORS ejecutándose en el puerto 8080
Solicitud recibida: GET / HTTP/1.1 
Host: localhost:8080 
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3 
Accept-Encoding: gzip, deflate, br, zstd 
Connection: keep-alive 
Upgrade-Insecure-Requests: 1 
Sec-Fetch-Dest: document 
Sec-Fetch-Mode: navigate 
Sec-Fetch-Site: none 
Sec-Fetch-User: ?1 
Priority: u=0, i
Solicitud recibida: GET /favicon.ico HTTP/1.1 
Host: localhost:8080 
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0 
Accept: image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5 
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3 
Accept-Encoding: gzip, deflate, br, zstd 
Connection: keep-alive 
Referer: http://localhost:8080/ 
Sec-Fetch-Dest: image 
Sec-Fetch-Mode: no-cors 
Sec-Fetch-Site: 
same-origin Priority: u=6 

General análisis del resultado:

El servidor HTTP con soporte CORS está ejecutándose correctamente en el puerto 8080 y recibió dos solicitudes GET:

  1. Solicitud para el recurso / (página principal del servidor).
  2. Solicitud para /favicon.ico (ícono del sitio web).

Cada solicitud incluye encabezados HTTP que describen información adicional sobre lo que el cliente (navegador Firefox) está solicitando. Estos encabezados son típicos y contienen metadatos sobre la solicitud, como el tipo de contenido, la codificación aceptada, el idioma, y la conexión.

 

Por qué dice Sec-Fetch-Mode: no-cors en la segunda solicitud

Concepto de Sec-Fetch-Mode:

El encabezado Sec-Fetch-Mode es una característica de seguridad moderna introducida en navegadores como Firefox y Chrome. Este encabezado describe cómo el navegador está solicitando el recurso:

  1. navigate:
    • Modo que indica una solicitud para navegar directamente al documento principal (como en la primera solicitud al recurso /).
  2. no-cors:
    • Modo utilizado para recursos secundarios, donde el navegador no aplica los métodos CORS (por ejemplo, en solicitudes que no necesitan autorización o encabezados personalizados).
    • Este modo es utilizado principalmente para recursos simples (como imágenes, íconos o scripts) que el navegador puede cargar automáticamente sin interactuar con las reglas de origen cruzado (CORS).

Contexto de la solicitud para /favicon.ico:

  • Por qué no-cors:
    • El navegador solicita el archivo favicon.ico como un recurso pasivo que no requiere autorización o interacción directa con el servidor (ningún encabezado CORS es evaluado porque es un recurso estático).
    • Estos tipos de solicitudes están diseñados para ser lo más eficientes posible y permiten al navegador descargar el recurso sin verificar reglas de origen cruzado.

 

Secuencia de las solicitudes:

  1. Primera solicitud (GET / HTTP/1.1):
    • La solicitud se realizó con el propósito de navegar al recurso principal del servidor (página de inicio).
    • El navegador utiliza Sec-Fetch-Mode: navigate porque el recurso solicitado es un documento que el navegador necesita renderizar como parte de la navegación.
  2. Segunda solicitud (GET /favicon.ico HTTP/1.1):
    • Esta es una solicitud automática realizada por el navegador para cargar el ícono del sitio web (favicon.ico).
    • Debido a que es un recurso secundario y pasivo, se utiliza el modo no-cors.

 

Conclusión

  • Primera solicitud: Modo navigate porque el navegador está solicitando un documento interactivo.
  • Segunda solicitud: Modo no-cors porque el navegador está solicitando un recurso pasivo (favicon) que no requiere interacción con las reglas de CORS.

 

 

 

 

 

Destacado

Bootloader Avanzado en Ensamblador

Bootloader Avanzado en Ensamblador Características del Bootloader Se carga en la dirección 0x7C00 (BIOS). ...