Configurar autenticación básica en los servidores web Nginx y Apache

Escrito por picodotdev el .
planeta-codigo web
Enlace permanente Comentarios

La autenticación básica o basic auth es un mecanismo de autenticación sencillo que permite proteger los recursos solicitados de un sitio o aplicación web. Es fácil de configurar en el servidor web y está implementado en los propios navegadores, otra ventaja es que se puede añadir a un sitio o aplicación web sin necesidad de realizar modificaciones en su código.

La autenticación básica por seguridad requiere utilizar en el servidor web el protocolo seguro HTTPS y obtener un certificado para el nombre del dominio del servidor web ya que el navegador cuando envía al servidor el usuario y contraseña no los protege de forma especial y utiliza el mecanismo de comunicación de la conexión, es usual también configurar un servidor web virtual para aplicar esta configuración únicamente al sitio web deseado. Con el protocolo HTTPS el usuario y contraseña se transmite cifrada por la propia conexión segura.

Cuando un servidor para el acceso a un recurso requiere autenticación básica el navegador muestra una ventana emergente en la que se solicita un usuario y contraseña.

Solicitud de credenciales por el navegador con autenticación básica

Configurar autenticación básica en el servidor web Nginx

La autenticación básica en Nginx se activan añadiendo dos directivas, auth_basic y auth_basic_user_file, en el archivo de configuración del sitio web y recurso a proteger. En este caso con la raíz del sitio web / cualquier ruta está protegida con autenticación básica.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
server {
    listen 80;
    server_name localhost;

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2 default_server;
    server_name localhost;

    ssl_certificate conf.d/localhost.crt;
    ssl_certificate_key conf.d/localhost.key;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;

        auth_basic "Restricted Area";
        auth_basic_user_file conf.d/.localhost.htpasswd;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}
nginx-default.conf

Utilizando Docker se puede crear un contenedor y probar la configuración. Al acceder a la dirección https://localhost el navegador mostrará el diálogo que solicita el usuario y contraseña.

1
2
3
4
5
6
7
#!/usr/bin/env bash
docker run --rm -p 80:80 -p 443:443 \
  -v `pwd`/nginx-default.conf:/etc/nginx/conf.d/default.conf:ro \
  -v `pwd`/localhost.crt:/etc/nginx/conf.d/localhost.crt:ro \
  -v `pwd`/localhost.key:/etc/nginx/conf.d/localhost.key:ro \
  -v `pwd`/.localhost.htpasswd:/etc/nginx/conf.d/.localhost.htpasswd:ro \
  nginx:alpine
docker-nginx.sh

Si los datos proporcionados no son correctos se devuelve el código de estado 401 que indica que el acceso no se ha autorizado y se requiere autorización. Si las credenciales son válidas se muestra el recurso solicitado.

Solicitud de credenciales y acceso al recurso solicitado

Configurar autenticación básica en el servidor web Apache

El comando de Docker para Apache es similar e incluye el archivo de configuración del servidor virtual con el recurso protegido, la clave privada y el certificado que proporcionan cifrado en las comunicaciones con el protocolo HTTPS.

1
2
3
4
5
6
7
8
#!/usr/bin/env bash
docker run --rm -p 80:80 -p 443:443 \
  -v `pwd`/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro \
  -v `pwd`/httpd-vhosts.conf:/usr/local/apache2/conf/extra/httpd-vhosts.conf:ro \
  -v `pwd`/localhost.crt:/usr/local/apache2/conf/extra/localhost.crt:ro \
  -v `pwd`/localhost.key:/usr/local/apache2/conf/extra/localhost.key:ro \
  -v `pwd`/.localhost.htpasswd:/usr/local/apache2/conf/extra/.localhost.htpasswd:ro \
  httpd:alpine
docker-apache.sh

En el caso del servidor web Apache las directivas necesarias a añadir en la configuración para activar la autenticación básica son: AuthType, AuthName, AuthUserFile y Require.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<VirtualHost *:80>
   ServerName localhost
   RewriteEngine On
   RewriteCond %{HTTPS} off
   RewriteRule (.*) https://%{SERVER_NAME}$1 [R,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName localhost
    DocumentRoot /usr/local/apache2/htdocs

    SSLEngine on
    SSLCertificateFile conf/extra/localhost.crt
    SSLCertificateKeyFile conf/extra/localhost.key
    Protocols h2 http/1.1

    <Location "/">
        AuthType Basic
        AuthName "Restricted Area"
        AuthUserFile "conf/extra/.localhost.htpasswd"
        Require valid-user
    </Location>
</VirtualHost>

httpd-vhosts.conf

Solicitud de credeciales y acceso al recurso solicitado

Cómo crear los archivos de credenciales htpasswd

La autenticación se realiza solicitando el navegador a petición del servidor un usuario y contraseña. En este caso el navegador presenta un diálogo al usuario que una vez introducidos realiza la petición de nuevo con las credenciales proporcionadas. El servidor para un recurso que requiere autenticación comprueba los datos de autenticación enviados y los valida con una pequeña base de datos en un archivo htpasswd que el administrador del servidor ha creado previamente con las credenciales de todos los usuarios.

Los archivos htpasswd que guardan las credenciales se crean con la utilidad de línea de comandos htpasswd. Tanto para añadir nuevos usuarios como para modificarlos y eliminarlos. Es posible guardar las contraseñas con diferentes algoritmos hash que transforman la contraseña en texto plano en un resultado equivalente con el cual no es posible conocer la contraseña original pero si validar que un dato proporcionado genera el mismo resultado con una función de una sola dirección. El algoritmo hash más seguro soportado es bcrypt que en el comando htpasswd se usa con la opción -B, los algoritmos MD5 y SHA con las capacidades de computación actuales se consideran inseguros.

1
2
3
4
5
6
7
8
# Crear un archivo de credenciales con un suaurio
htpasswd -c -b -B .localhost.htpasswd user password

# Añadir o modificar un usuario a un archivo de credenciales
htpasswd -b -B .localhost.htpasswd user password

# Eliminar una credencial
htpasswd -b -D .localhost.htpasswd user
htpasswd.sh

El resultado del archivo es una línea por credencial creada con el nombre del usuario y el hash de la contraseña.

1
user:$2y$05$bFhwns7nxUq.q2tmFf/Hp.ltqKKOEscuLuluis/72xGDXGI3FijmS
.localhost.htpasswd

Funcionamiento y cabecera de la autenticación básica

El formulario de autenticación solo se presenta una vez una vez introducidas unas credenciales correctas, dado que el protocolo HTTP es un protocolo sin estado el navegador en cada solicitud de cada página y recurso envía la cabecera Authorization que contiene el usuario y contraseña codificadas en base64. Esta cabecera y su valor aunque codificadas no tienen un mecanismo adicional de seguridad por eso es necesario utilizar el protocolo seguro HTTPS cuando se utiliza autenticación básica de modo que los datos incluidos en las cabeceras se transmitan cifrados.

Cabecera enviada en la petición con las credenciales de acceso al recurso

La codificación en base64 no añade seguridad, el valor de la cabecera con las credenciales decodificadas contiene el usuario y la contraseña separados por dos puntos.

1
2
3
4
5
6
7
# Decodificación de base64
$ echo "dXNlcjpwYXNzd29yZA==" | base64 --decode
user:password

# Codificación en base64
$ echo "user:password" | base64
dXNlcjpwYXNzd29yZAo=
base64.sh

Con la herramienta de linea de comandos curl que permite realizar peticiones HTTP también hay que enviar la cabecera de autenticación para obtener el recurso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ curl --insecure -H 'Authorization: Basic dXNlcjpwYXNzd29yZA==' 'https://localhost/'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
curl.sh

El servidor web indica al navegador que el recurso solicitado requiere autenticación básica devolviendo en la respuesta el código de estado 401 Unauthorized y la cabecera www-authenticate.

Esquema de peticiones, cabeceras y respuestas del protocolo de autenticación básica

Cuando no se envían credenciales o se envían unas incorrectas el navegador devuelve un código de estado 401.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
$ curl -v --insecure 'https://localhost/'
...
> GET / HTTP/2
> Host: localhost
> user-agent: curl/7.71.1
> accept: */*
> 
...
< HTTP/2 401 
< server: nginx/1.17.10
< date: Sun, 02 Aug 2020 10:38:14 GMT
< content-type: text/html
< content-length: 180
< www-authenticate: Basic realm="Restricted Area"
< 
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.17.10</center>
</body>
</html>
...

$ curl -v --insecure -H 'Authorization: Basic invalid' 'https://localhost/'
...
> GET / HTTP/2
> Host: localhost
> user-agent: curl/7.71.1
> accept: */*
> authorization: Basic invalid
> 
...
< HTTP/2 401 
< server: nginx/1.17.10
< date: Sun, 02 Aug 2020 10:37:03 GMT
< content-type: text/html
< content-length: 180
< www-authenticate: Basic realm="Restricted Area"
< 
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.17.10</center>
</body>
</html>
...
curl-authorization.sh

Alternativas a la autenticación básica

La ventaja de la autenticación básica es que es sencilla de implementar pero con algunos inconvenientes a tener en cuenta que son motivo de buscar alternativa más avanzadas aunque también mas complejas. Una desventaja es que los usuarios y contraseñas de las base de datos htpasswd son fijas, por seguridad las contraseñas se deberían rotar cada cierto tiempo para que usuarios que ya no deberían tener acceso tengan conocimiento de la contraseña válida actual, en una empresa es el caso de personas que ya no son empleados pero que si no se rotan las contraseñas seguirían teniendo acceso si no se implementan mecanismos de seguridad adicionales.

Otra desventaja de la autenticación básica es que los archivos htpasswd los crea el administrador de sistemas de modo que este tiene conocimiento de todas las contraseñas. Por esto la autenticación básica no es adecuada para realizar la autenticación en aplicaciones en las que los usuarios crean sus cuentas, las eliminan, tienen ellos mismos la posibilidad de cambian sus contraseñas y con la posibilidad de cerrar la sesión.

Estas desventajas hace de la autenticación básica no adecuada para algunos casos, dependiendo del caso las alternativas son implementar un formulario de autenticación, implementar OAuth en una aplicación web o utilizar autenticación mutua con certificados.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:
./docker-nginx.sh o ./docker-apache.sh

Comparte el artículo: