Skip to the content.

Crear API para entregar datos

El objetivo del ejercicio descrito en esta página es ofrecer un servicio en php usando HTTPS, que esta disponible únicamente a usuarios que tengan un certificado de cliente autorizado. La identificación mútua TLS permite controlar el acceso a nuestra apliación usando certificados electrónicos.

Esta guía usa PHP y Nginx, es posible configurar identificación mútua TLS en Apache, JBossy IIS.

Crear servicio

El servicio de ejemplo utiliza un script PHP para regresar un objeto JSON con valores estaticos.

~# apt install php php-fpm

~#nano /var/www/html/index.php:

 <?php 
$json = new stdClass();
$json->nombre = "Pedro Paramo";
$json->nit = "012345012345";
$json->dui = "0987654321";
$data = json_encode($json); 
echo "\n".$data; 
?> 
 
~# php7.3 /var/www/html/index.php

{"nombre":"Pedro Paramo","nit":"012345012345","dui":"0987654321"} 

Autoridad Certificadora y Servicio Web

Para servir nuestra API vamos a crear un Host virtual en Nginx. El primer paso es crear los certificados que utilizaremos en el servicio https.

*Crear autoridad certificadora, certificado web y parámetros para HTTPS:

echo "####Autoridad Certificadora:'
openssl genrsa -out /etc/ssl/private/api-ac.key 4096;
openssl req -new -x509 -days 365 -key /etc/ssl/private/api-ac.key -out /etc/ssl/certs/api-ac.crt \
       -subj "/C=SV/O=Gobierno de El Salvador/O=Min xxx/OU=CERTIFICADO AUTOFRIMADO/CN=Autoridad certificadora";

echo "####Certificado de Servidor Web";
openssl genrsa -out /etc/ssl/private/servidor-web.key 2048;
openssl req -new -key /etc/ssl/private/servidor-web.key -out /etc/ssl/certs/server-web.csr \
        -subj "/C=SV/O=Gobierno de El Salvador/O=MIN xx/OU=CERTIFICADO AUTOFRIMADO/CN=Servidor HTTPS local";
        
openssl x509 -req -days 365 -in /etc/ssl/certs/server-web.csr -CA /etc/ssl/certs/api-ac.crt \
             -CAkey /etc/ssl/private/api-ac.key -set_serial 01 -out /etc/ssl/certs/server-web.crt;

~#openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048;

Configurar HTTPS en NGINX

Crear archivo de configuración de host virtual usando un puerto disponible (ej 9443):

##Host Virtual /etc/nginx/conf.d/ejemplo-xroad.conf
server {
        listen 9443 ssl;
        ssl_certificate /etc/ssl/certs/server-web.crt;
        ssl_certificate_key /etc/ssl/private/servidor-web.key;
        ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
        ssl_protocols TLSv1.2;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;
        ssl_prefer_server_ciphers on;

        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";

        ssl_session_cache    shared:SSL:10m;
        ssl_session_timeout  10m;
        keepalive_timeout    60;
        
        access_log /var/log/nginx/api_access.log;
        error_log /var/log/nginx/api_error.log;
        root /var/www/html;
        index index.php;

        # MTLS
        ssl_client_certificate /etc/ssl/certs/api-ac.crt;
        ssl_verify_client on;

        location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.3-fpm.sock;
        }
}

Al llamar la api sin un certificado autorizado, el servidor responderá con un error indicando que la llamada requiere una certificado autorizado:

~# curl -k https://localhost:9443/
<html>
<head><title>400 No required SSL certificate was sent</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>nginx</center>
</body>
</html>

Crear certificado de cliente autorizado

##Cliente Genera su llave Privada y una Solicitud de Certificado
openssl genrsa -out /etc/ssl/private/cliente.key 2048;
openssl req -new -key /etc/ssl/private/cliente.key -out /etc/ssl/certs/cliente.csr \
       -subj "/C=SV/O=Gobierno de El Salvador/O=MIN xx/OU=CERTIFICADO AUTOFRIMADO/CN=Cliente Autorizado";

##Autoridad usa/sella solicitud para generar certificado 
openssl x509 -req -days 365 -in /etc/ssl/certs/cliente.csr -CA /etc/ssl/certs/api-ac.crt 
             -CAkey /etc/ssl/private/api-ac.key -set_serial 01 -out /etc/ssl/certs/cliente.crt;

Cliente recibe certificado y lo usa para invocar la API:

~# curl -k -E /etc/ssl/certs/cliente.crt --key /etc/ssl/private/cliente.key https://localhost:9443/;