Mostrando entradas con la etiqueta apache. Mostrar todas las entradas
Mostrando entradas con la etiqueta apache. Mostrar todas las entradas
Reverse Proxy con Apache en 4 pasos
Los reverse proxy son muy útiles para poder proteger nuestros servers, ya que podemos colocar el server que realiza el procesamiento en la red interna y publicar todo a través del proxy, el cual puede filtrar y actuar de application firewall, balancear carga, etc. La idea del post no es explicar qué es ni qué ventajas tiene un Reverse Proxy, sino cómo crear uno usando apache. Para entender qué son, pueden arrancar por la wiki.
Existen módulos para Apache que nos permiten convertirlo en un Reverse Proxy, denominados mod_proxy_*. Los que interesan para esta explicación son mod_proxy y mod_proxy_http.

Supongamos que tenemos la siguiente configuración:

Internet ----> | www.dvpem.org / proxy.dvpem.org |<---> | background-man1.dvpem.org |

Donde www.dvpem.org tiene IP pública accesible desde Internet y es atendida por el server proxy.dvpem.org, y background-man1.dvpem.org tiene una IP privada. El web server background-man1 es el encargado de procesar todos los pedidos, pero no queremos exponerlo, por lo que levantamos un Reverse Proxy (proxy.dvpem.org), que es quien atiende los request a la página www.dvpem.org y los reenvía a background-man1 para su procesamiento. Una vez que background-man1 termina, retorna los resultados a proxy.dvpem.org que es quien responde finalmente al cliente.

Para lograr esto, sólo necesitamos realizar los siguientes 4 pasos:

1. Instalar apache.
2. Habilitar mod_proxy y mod_proxy_http:
    a2enmod proxy proxy_http
3. Crear un Virtual Host que atienda los pedidos www.dvpem.org y los reenvíe a background-man1:
    <VirtualHost *:80>
        ServerName   www.dvpem.org:80
        ServerAlias  www.dvpem.org
       
        Alias /about.html /var/www/about.html   #about.html lo procesa el proxy
        ProxyPassMatch ^/about.html !           #Indicamos que no proxee los requests del file about.html
       
        ProxyPass / http://background-man1.dvpem.org/           #Mapeamos los request www.dvpem.org para que vayan a background-man1
        ProxyPassReverse / http://background-man1.dvpem.org/    #Reescribe los headers retornados por background-man1 (ej: Location, Content-Location, URI) para que hagan referencia a www.dvpem.org
    </VirtualHost>
En la configuración agregué una yapa, y es que los request de about.html sean retornados por el mismo proxy, utilizando el file que está en su filesystem local. Esto es, no irá a background-man1, sino que lo retornará de un file en el mismo server. Esto puede ser muy útil si queremos que además de proxy sirva algunas cosas.
4. Reloadear la configuración de apache:
    service apache2 reload
   
El módulo es muchísimo más polenta que esto, expliqué un uso muy básico. Algo interesante es que podríamos resolver diferentes paths a diferentes servers, como por ejemplo usando:
    ProxyPass /main http://background-man1.dvpem.org/      
    ProxyPassReverse /main http://background-man1.dvpem.org/
   
    ProxyPass /images http://images.dvpem.org/
    ProxyPassReverse /images http://images.dvpem.org/
   
Pueden leer más sobre mod_proxy en su página oficial.
Apache kerberizado - Single Sign On (AD y MIT Kerberos)

Una funcionalidad que se está utilizando mucho en las empresas es el Single Sign On (SSO), esto es, permitir que los usuarios se logueen una vez y accedan a todos los sistemas que necesiten, sin tener que ingresar nuevamente sus credenciales. Más allá de las graves implicaciones de seguridad que esto acarrea, es algo que se está utilizando mucho y que los administradores deben conocer.
El SSO no es otra cosa que kerberizar servicios, es decir, autenticar el usuario, obtener un ticket, y luego solicitar servicios con el ticket de sessión. En el caso de los servicios Web, MS integra fácilmente IIS con la autenticación de Active Directory. Apache, por su parte, también brinda esta posibilidad.
En este artículo mostraré los pasos necesarios para kerberizar Apache, es decir, permitir que un usuario acceda a un sitio web sólo si antes se autentica utilizando kerberos. La configuración mostrada es sobre un servidor GNU/Linux, y describe los pasos para kerberizar Apache tanto en una red con AD, como en una de MIT Keberos.
Se asume que el lector tiene ciertos conocimientos básicos de kerberos. Sino pueden leer los artículos que escribí anteriormente sobre el tema:
- Instalación de MIT Kerberos
- Configurar PAM para utilizar kerberos
- Autenticar con kerberos y almacenar información de usuarios con LDAP en GNU/Linux
- OpenLDAP kerberizado

Yendo al grano, los pasos de configuración son los siguientes:

1. Crear un usuario en el dominio que servirá como principal para el servicio HTTP (solicitud de tickets de servicio). El uso es como el de una cuenta de máquina.
  En AD:
    - Abrir Active Directory Users and Computers (ADUC)
    - Ir al dominio donde se creará el usuario.
    - Click derecho en Users
    - Elegir New -> User
    - Completar los datos y finalizar.

  En MIT Kerberos:
      # kadmin.local
      Authenticating as principal root/admin@DVPEM.ORG with password.
      kadmin.local: addprinc -randkey HTTP/apache.dvpem.org@DVPEM.ORG
      WARNING: no policy specified for HTTP/apache.dvpem.org@DVPEM.ORG; defaulting to no policy
      Principal "HTTP/apache.dvpem.org@DVPEM.ORG" created.
      donde -randkey permite generar un password random.

2. Mapear el servicio HTTP con el usuario recién creado y exportar el keytab para ser utilizado en el servidor:
    En AD:
      ktpass -princ HTTP/apache.dvpem.org@DVPEM.ORG -mapuser DVPEM\pruebaapache -ptype KRB5_NT_PRINCIPAL -pass prueba -out C:\apache.keytab
    donde:
      -princ indica el nombre que tendrá el principal (servicio HTTP)
      -mapuser indica el usuario con el que se mapea el servicio
      -ptype especifica el tipo del principal
      -pass asigna un password para el principal. Si utilizan un asterisco (*) el sistema pregunta el password.
      -out especifica el nombre del archivo keytab a generar
    Dependiendo del tipo de encripción soportado por el servidor y el cliente, puede ser necesario especificar el uso de encripción débil. Esto se realiza con:
      -mapop set +desonly
      -crypto all o bien -crypto DES-CBC-MD5

    En MIT Kerberos:
      kadmin.local: ktadd -k /root/apache.keytab HTTP/apache.dvpem.org
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type AES-256 CTS mode with 96-bit SHA-1 HMAC added to keytab WRFILE:/root/apache.keytab.
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/root/apache.keytab.
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/root/apache.keytab.
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/root/apache.keytab.

3. Copiar el keytab al servidor donde se encuentra Apache instalado. Cambiar el dueño del archivo y restringir los permisos. Si por ejemplo se copia el archivo a /etc/apache2/apache.keytab, ejecutar lo siguiente:
    chown www-data:www-data /etc/apache2/apache.keytab
    cmod 400 /etc/apache2/apache.keytab

4. Instalar en el servidor web las utilidades de kerberos y el módulo de Apache, y habilitar el módulo:
    # apt-get install krb5-{config,user} libapache2-mod-auth-kerb
    # a2enmod mod_auth_kerb

5. Configurar los valores de realm, KDCs, y dominios para kerberos. Esto es, editar las siguientes líneas del archivo /etc/krb5.conf
  - En la sección libdefaults setear el nombre del realm:
      default_realm = DVPEM.ORG
  - En la sección realms, indicar cuáles son los servidores KDC para nuestro realm:
      DVPEM.ORG = {
 kdc = kdc01.dvpem.org:88
 admin_server = kdc01.dvpem.org
 }
  - En la sección domain_realm, agregar los mapeos de dominio con realms:
      .dvpem.org = DVPEM.ORG
      dvpem.org = DVPEM.ORG

6. Testear si kerberos funciona correctamente. Para ello, solicitar un ticket de usuario, para un usuario válido del dominio:
    $ kinit demasiadovivo@DVPEM.ORG
    $ klist

7. Agregar la siguiente configuración a apache para el directorio que se desea autenticar con kerberos. En este ejemplo, la intención es autenticar el directorio /var/www/mipagina
    <Directory /var/www/mipagina>
      AuthType Kerberos
      AuthName "Kerberos Login"
      KrbMethodK5Passwd Off
      KrbMethodNegotiate On
      KrbAuthRealms DVPEM.ORG
      KrbServiceName HTTP
      Krb5KeyTab /etc/apache2/apache.keytab
      require valid-user
    </Directory>
donde:
  AuthType Kerberos: especifica el tipo de autenticación
  KrbMethodNegotiate On: habilita el uso de SPNEGO (GSSAPI-SASL)
  KrbMethodK5Passwd Off: deshabilita el uso de password para la autenticación. Esto puede causar problemas con browsers que no soportan SPNEGO, o máquinas que no se encuentran unidas al dominio. En estos casos puede setearse este valor en On, pero esto permite el uso de autenticación BASIC (muy insegura).
  KrbAuthRealms DVPEM.ORG: especifica el realm (o dominio)
  KrbServiceName HTTP: nombre del servicio
  Krb5KeyTab /etc/apache2/apache.keytab: donde se encuentra el keytab
  require valid-user: fuerza a que el usuario sea validado antes de acceder.

8. Chequear que el ticket provisto por el servidor contiene un tipo de encripción que es consistente con los valores configurado en el keytab:
  Obtener un ticket de servicio y listar los tipos de encripción:
    kvno HTTP/apache.dvpem.org@DVPEM.ORG
    klist -e
  Mostrar los tipos de encripción configurados en el keytab:
    klist -e -k -t /etc/apache2/apache.keytab
Si los valores no coinciden, el servicio no podrá ser utilizado.
NOTA: Hay que tener en cuenta que Windows 7 y 2008 dejaron de aceptar por defecto la encripción con DES, algo que puede causar errores en la autenticación.

9. Reiniciar Apache y probar la configuración accediendo a la página Web protegida con Kerberos.
Algo muy importante es que debe utilizarse el nombre DNS especificado en el keytab como nombre del servicio, dado que si se utiliza la IP o un alias, la autenticación no funcionará.

10. Errores, posibles causas y soluciones. A continuación se listan los errores con los que me topé al configurar el servicio y una explicación sobre cómo lo solucioné. Además incluí soluciones alternativas.
  krb5_get_init_creds_password() failed: Cannot resolve network address for KDC in requested realm
    - Verificar que tanto el registro A como el registro PTR del servidor se encuentren registrados. Si por ejemplo el nombre del servidor apache es apache.dvpem.org, debe ingresarse el registro PTR correspondiende a la IP de dicho servidor.
    - El parámetro KrbAuthRealms de Apache debe estar seteado correctamente. Recordar que en este parámetro se especifica el realm (dominio) en mayúsculas:
KrbAuthRealms DVPEM.ORG
    - Los kdc del dominio se encuentran seteados correctamente en el archivo /etc/krb5.conf. Un ejemplo de esta configuración es:
DVPEM.ORG = {
 kdc = kdc01.dvpem.org:88
 admin_server = kdc01.dvpem.org
 }

  failed to verify krb5 credentials: Server not found in Kerberos database
    - El principal utilizado esta mal configurado en el keytab creado o en el atributo KrbServiceName de la configuración de Apache.
    - Al acceder a la página debe utilizarse el nombre del servidor registrado en el keytab. Es decir, si el principal está designado para apache.dvpem.org, en el navegador debe utilziarse la dirección apache.dvpem.org.
   
  failed to verify krb5 credentials: KDC has no support for encryption type
    - El tipo de encripción aceptada por el servidor no es compatible con la encripción aceptada por el cliente, o bien los tipos de encripción configurados en el keytab no son compatibles con el servidor. Verificar obteniendo un ticket de servicio y la encripción soportada en el keytab:
      kvno HTTP/apache.dvpem.org@DVPEM.ORG
      klist -e
      klist -e -k -t /etc/apache2/apache.keytab
      Hay que tener en cuenta que Windows 7 y 2008 dejaron de aceptar por defecto la encripción con DES, algo que puede causar el error mencionado si se utilizan estos sistemas.
   
  gss_acquire_cred() failed: Unspecified GSS failure.  Minor code may provide more information (, )
    - Revisar si no se encuentra seteado el valor "Use Kerberos DES encryption for this account" en la cuenta del usuario utilizada para el pricipal.

 
Referencias

- Kerberos Module for Apache - Configuration
- Configure Apache to use Kerberos authentication
- Kerberos authentication with Apache in a multi-domain Active Directory
- Single Sign On with Kerberos using Debian and Windows Server 2008 R2
- Kerberos-Based SSO with Apache
- Using mod_auth_kerb and Windows 2000/2003/2008R2 as KDC
- Apache on Linux and Single-Sign-On with Active Directory
- Active Directory and Apache Kerberos authentication
- JBoss Doc - Chapter 5. Configuring Microsoft Active Directory
- Ktpass
Instalación y configuración básica de ModSecurity
Desde hace tiempo tengo ganas de instalar un Web Application Firewall (WAF) y siempre tuve ModSecurity en la mira. Hoy con un poco de tiempo, decidí darle una chance y jugar un rato.
ModSecurity es un módulo para Apache que permite analizar los pedidos en distintas fases del protocolo HTTP. De esta forma, es posible procesar los pedidos antes de ser entregados a la aplicación subyacente (por ejemplo, escrita en PHP), o luego de que se completó la ejecución. Con este sistema es posible prevenir ataques de SQL Injection, XSS, LDAP Injection, File Injection, Session Fixation, etc.
Como es un módulo para Apache, es muy fácil de instalar, aunque requiere algunos pasos para su configuración. En este artículo explicaré cómo instalar, configurar y poner en funcionamiento ModSecurity. La explicación culmina con una configuración básica de ModSecurity trabajando en modo monitoreo, es decir, sólo loggea los eventos, no actúa de forma activa. Por supuesto que la verdadera utilidad de un WAF es la prevención de los ataques, pero para evitar falsos positivos que afecten la funcionalidad de los sites que se encuentren activos, es preferible comenzar en un modo pasivo e ir habilitando reglas a medida que se va conociendo el tráfico.

Instalar ModSecurity en debian, una vez que ya está instalado Apache, es tan simple como ejecutar:
  apt-get install libapache2-modsecurity modsecurity-crs

El paquete modsecurity-crs contiene el conjunto de reglas core creado por OWASP. ModSecurity es simplemente el motor del firewall y todo firewall necesita reglas para funcionar. Las reglas creadas por OWASP abarcan todos los ataques más comunes de la web y por supuesto que son gratuitas de utilizar.

Una vez instalado el módulo, debe activarse ejecutando:
  a2enmod mod-security

En el paquete de debian encontré un error al intentar cargar el módulo, dado que las librerías estaban mal referenciadas en el archivo .load. Para arreglar el problema, debe modificarse la línea Load del archivo /etc/apache2/mods-enabled/modsecurity.load para que quede
  LoadFile /usr/lib/libxml2.so.2
en lugar de "LoadFile libxml2.so.2".

Para probar que el módulo está instalado correctamente, renombrar el archivo de configuración default:
  mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
reiniciar Apache:
  /etc/init.d/apache2 restart
y ejecutar nikto:
  nikto -host http://localhost
Puede utilizarse cualquier otra herramienta que genere tráfico malicioso, nikto es solamente un ejemplo.

Con esto ya debería existir el archivo de auditoría /var/log/apache2/modsec_audit.log, donde deberían estar las entradas generadas por nikto.

Como explicaba al principio, por si solo ModSecurity no hace nada, necesita ser alimentado con reglas, para ello el paquete modsecurity-crs. Si ya está instalado, las reglas se encontrarán en /usr/share/modsecurity-crs/. Este directorio está dividido en 5 subdirectorios:
  activated_rules
  base_rules
  experimental_rules
  optional_rules
  slr_rules
Los nombres explican por si mismos el contenido. La idea es colocar en activated_rules links simbólicos a las reglas que deseemos activar, como por ejemplo "/usr/share/modsecurity-crs/base_rules/modsecurity_crs_41_sql_injection_attacks.conf". Todo dependerá de qué deseen hacer, es una cuestión organizativa.
Para una configuración básica, simplemente incluiremos todo el directorio base_rules, en lugar de incluir activated_rules y agregar de a una las reglas. También debe incluirse el archivo de configuración modsecurity_crs_10_config.conf, que cuenta con seteos básicos. Esto se realiza editando el archivo "/etc/apache2/mods-enabled/mod-security.conf" y agregando las siguientes líneas:
  Include "/usr/share/modsecurity-crs/modsecurity_crs_10_config.conf"
  Include "/usr/share/modsecurity-crs/base_rules/*.conf"
es decir, el archivo debería quedar como a continuación:
<ifmodule security2_module="">
        SecDataDir /var/cache/modsecurity
        Include "/etc/modsecurity/*.conf"
        Include "/usr/share/modsecurity-crs/modsecurity_crs_10_config.conf"
        Include "/usr/share/modsecurity-crs/base_rules/*.conf"
</ifmodule>

Cada vez que realicen un cambio en la configuración deberán cargar nuevamente Apache. Claro que no es necesario reiniciarlo, también es posible hacer un reload más sutil y no matar las conexiones existentes:
  /etc/init.d/apache2 graceful

Un error bastante común al ejecutar las reglas de OWASP es el exceso en el límite de la librería PCRE que viene por defecto en el archivo modsecurity.conf. El error contiene el siguiente mensaje:
  Execution error - PCRE limits exceeded
Estos límites se configuran mediante las directivas SecPcreMatchLimit y SecPcreMatchLimitRecursion (modsecurity - Configuration Directives) y previenen que expresiones regulares mal formadas se salgan de control. Aumenten con cuidado este valor, tratando de que las reglas se ejecuten, pero sin asignar un número exorbitante. Por ejemplo, un valor que a mi me funcionó bien es 5000:
  SecPcreMatchLimit 5000
  SecPcreMatchLimitRecursion 5000

Con esto ya cuentan con ModSecurity habilitado y funcionando en modo "sniffer", dado que sólo revisa el contenido y loggea los ataques. A partir de aquí deberán analizarse dichos logs y decidir qué tipo de prevención aplicar. Hay que tener cuidado con los falsos positivos, dado que pueden influir en el correcto funcionamiento de los sites que intentamos proteger.

Una idea interesante es utilizar ModSecurity en conjunto con el módulo mod_proxy, es decir, utilizar Apache como un reverse Proxy y proteger con una sola instancia de ModSecurity varios web servers que se encuentren detrás.


Referencias

- ModSecurity Reference Manual
- Category: OWASP ModSecurity Core Rule Set Project
- mod_security on Apache
Hardening PHP
PHP es el lenguaje más popular para la creación de Webs, y por lo tanto muy conocido, y a la vez atacado.
Si bien es trabajo del programador (y el mayor responsable de) tomar los recaudos necesarios para que sus aplicaciones no sean vulnerables, un administrador de sistemas puede utilizar varias opciones para que el servidor sea lo más resistente posible. PHP ofrece varias opciones que aumentan la seguridad significativamente, si se encuentran bien configuradas.

La siguiente es una lista de directivas que se pueden configurar en el archivo de configuración de php (/etc/php.ini, o /etc/php5/apache2/php.ini, dependiendo la distribución) para mejorar la seguridad del servidor:
  • Restringir el acceso al sistema de archivos. Dado que los sites se alojarán en /var/www, salvo casos excepcionales, los scripts PHP no necesitan acceso al resto del sistema de archivos, a excepción del directorio /tmp que es donde se alojan los archivos cuando el usuario hace un upload. Por ello, es posible restringir los directorios a los que se puede acceder, mediante la opción:
    open_basedir = /var/www:/tmp
    Esta configuración se puede cambiar por site en el correspondiente Virtual Host, utilizando la directiva:
    php_admin_value open_basedir /var/www/[nombre site]/
  • Deshabilitar funciones riesgosas. Hay funciones que deben ser permitidas sólo en casos particulares, debido a que se usan raramente y representan un gran riesgo. Esta configuración se realiza con la directiva disable_functions:
    disable_functions = show_source, system, shell_exec, passthru, exec, phpinfo, popen, proc_open
  • No revelar información de PHP en los headers. Esto le permitiría a un atacante saber que el servidor posee PHP, además de la versión instalada, y así poder realizar un ataque más específico:
    expose_php = Off
  • No exponer errores de scripts al cliente. Los errores de programación no deben quedar expuestos a los clientes, sino que deben loggearse en archivos para que el programador los pueda depurar:
    display_errors = Off
    display_startup_errors = Off
  • Loggear errores permiten detectar cuál fue la falla que causó que el programa no funcione o lo haga de forma imprevisible:
    log_errors = On
  • No utilizar register_globals. Esta funcionalidad se considera extremadamente peligrosa y por default viene desactivada en toda configuración actual, pero por las dudas se debe checkear que el valor sea el siguiente:
    register_globals = 0
  • No utilizar magic_quotes. PHP provee, hasta la versión 5, de una utilidad para escapar caracteres peligrosos (', “, \, NULL), antes de ser utilizados por los scripts del servidor. Esto permite evitar algunos ataques de SQL Injection, pero tiene complicaciones con las distintas codificaciones de caracteres y además puede introducir problemas en la programación. Este tipo de controles deben estar implementados en la aplicación y no en el servidor, por lo cual a partir de PHP 5.3 se considera deprecated y en la versión 6 ya no existe.
    magic_quotes_gpc = Off
    magic_quotes_runtime = Off
    magic_quotes_sybase = Off
  • Para realizar upload de archivos desde el cliente, utilizar el directorio tmp correspondiente al site, es decir /var/www/[nombre site]/tmp. Esta configuración se realiza en el virtual host con la sentencia:
    php_admin_value upload_tmp_dir /var/www/[nombre site]/tmp
  • No tratar las URLs (como http:// o ftp://) como archivos. En caso de encontrar un error en la programación, un atacante podría realizar remote file inclusion si esto se encuentra activado.
    allow_url_fopen = Off
    allow_url_include = Off
  • Cambiar el nombre de la variable de sesión. Por defecto esta variable se llama PHPSESSID y demuestra que el servidor ejecuta PHP, y que la página actual está escrita en PHP. Si bien esto agrega poca seguridad, agrega una traba más al atacante.
    session.name = SESSION_ID
Como dije, estas opciones ayudan a la seguridad, pero no evitan, por ejemplo, que un programa vulnerable a SQLi permita a un atacante romper la base de datos.
Espero que les sean de utilidad!


Referencias

- Description of core php.ini directives
- Securing PHP: Step-by-Step
Activar HTTPS en Apache + Forzar SSL
Una tarea que repito una y otra vez al instalar un servidor Apache, es la configuración para activar HTTPS. Los pasos son bastante simples, pero es necesario algún que otro truco. Por ello, me pareció interesante describir el procedimiento.
Además les comentaré cómo forzar al servidor a que siempre utilice HTTPS, y que no envíe nada a través de HTTP.
La configuración que describiré a continuación está pensada para una distribución debian o basada en ésta, aunque los pasos no deberían cambiar mucho en otras distros.

Para configurar HTTPS, primero deben crear un certificado SSL. Hace poco más de un año escribí una guía completa, describiendo los certificados y cómo crear uno utilizando openssl. La pueden acceder aquí.

Una vez que tenemos el certificado, debemos actualizar apache para que escuche en el puerto 443 y decirle donde están los certificados. Las distros basadas en debian suelen traer el archivo /etc/apache2/sites-available/default-ssl, en el cual se encuentra una configuración default del VirtualHost necesario para utilizar HTTPS. Podemos utilizar este archivo como base para nuestra configuración. Simplemente deben copiar el archivo de sites-available a sites-enabled:
cp /etc/apache2/sites-available/default-ssl /etc/apache2/sites-enabled/
o bien, utilizar el comando a2ensite, que se encarga de habilitar Virtual Hosts definidos en sites-available:
a2ensite default-ssl
El siguiente paso me costó un par de horas de trabajo. El paso en sí es muy simple, pero encontrar el error me llevó bastante tiempo.
Luego de configurar el servidor para que funcione con ssl (incluyendo los pasos que describo luego), me encontré con que apache arrojaba el error "ssl_error_rx_record_too_long". Me costó un buen tiempo descubrir el problema, aunque la solución la tuve desde el principio en la página stackoverflow.
El error se debe a que en la configuración del VirtualHost default (/etc/apache2/sites-enabled/000-default) se especifica que apache debe utilizar esa configuración para todas las direcciones DNS y para todos los ports. Por ello, cuando accedemos a través de HTTPS (port 443), apache se encuentra con una configuración que no presenta SSL, y envía una respuesta HTTP común, cuando en realidad el browser del cliente está esperando una conexión SSL.
En fin, el error se soluciona cambiando la línea:
<VirtualHost *>
por
<VirtualHost *:80>
en el archivo /etc/apache2/sites-enabled/000-default. Ahora apache sabe que esta configuración es sólo para el port 80.

Una vez realizado el paso anterior, debemos modificar algunas líneas en el archivo sites-enabled/default-ssl para que funcione SSL. Por un lado necesitamos cambiar los paths al certificado y la clave del certificado. Dirijanse a la parte del archivo que empieza con "SSL Engine Switch" y asegúrense de que la línea "SSLEngine on" se encuentre descomentada. Luego modifiquen las líneas:
SSLCertificateKeyFile /path/clave.key
SSLCertificateFile /path/certificad.crt
y coloquen el path correspondiente. La primera especifica la ubicación de la clave, y la segunda la ubicación del certificado.


Configurado SSL correctamente, forzaremos al cliente a utilizar HTTPS en lugar de HTTP. Es decir, si el usuario olvida poner https en la dirección, forzaremos a que el server igualmente utilice https a través de una redirección.
Para forzar la redirección, agregaremos algunas líneas al archivo /etc/apache2/sites-enabled/000-default. Vayan a la parte donde se configura el directorio base, y dejenlo de la siguiente forma:
<Directory /var/www/>
...
...
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</Directory>
Las líneas que agregamos realizan un if. Si no se está utilizando HTTPS (RewriteCond %{HTTPS} off), entonces redirigir a la misma dirección pero utilizando HTTPS (RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}). Estas reglas las obtuve de Apache: Redirect http to https Apache secure connection – force HTTPS Connections.

Eso es todo, ya tenemos habilitado SSL en Apache, y establecimos que siempre se utilice HTTPS =)
Apache web server sobre IPv6
Para esta entrega decidí traerles un muy buen artículo realizado por Emiliano Marini, el cual, por suerte, me dio permiso para publicarlo en el blog. Emiliano es bastante fanático del IPv6 y espera que en algún futuro no muy lejano se comience a utilizar masivamente, así que dedica algunas de sus horas libres a investigar cómo funcionan ciertas cosas con este protocolo.
En este caso armó un artículo sobre cómo utilizar Apache sobre IPv6 luego de pelearse un rato haciendo pruebas. Realmente es muy interesante.

Emiliano es Ingeniero en Sistemas, además trabaja como administrador de seguridad y al igual que yo promueve el uso de herramientas libres.

Este es el primer artículo que publico que no fue realizado por mi, y espero poder traerles más en el futuro, dado que tengo varios amigos haciendo trabajos muy interesantes y que me gustaría poder compartir acá.

Sin más introducción, los dejo con el artículo.


Prólogo

Esta es la primer entrega (espero que sea la primera de muchas) de una serie de artículos de investigación sobre IPv6. Actualmente, IPv6 es el tema que me resulta más interesante para investigar, siempre con la ayuda de VirtualBox. Para el final de Redes y Teleprocesamiento investigué (junto con Sebastián Silva) los protocolos de bajo nivel: configuración estática de direcciones IPv6; Neighbor Discovery; Autoconfiguración de direcciones IPv6 de ámbito global tanto en routers (i.e. PC's funcionando como routers, se instala el demonio radvd) como en clientes (trivial); RIPng con zebra; y DNS utilizando bind9.
Por lo tanto ahora voy a investigar los protocolos de alto nivel, empezando por lo básico: HTTP sobre IPv6 y cómo levantar un servidor web Apache que funcione sobre IPv6 ("quiere dejar de decir IPv6" diría Marge Simpson).
Debido a que las tecnologías libres incentivan y motivan la investigación y el desarrollo, voy a trabajar con sistemas operativos y software libre, por lo tanto dejando de lado los productos del amigo "Puertas".


Introducción

Para los experimentos cuento con un servidor Apache 2.0 ejecutándose en un host Ubuntu 8.04 con kernel 2.6.28. Este artículo va dirigido a un público avanzado, por lo tanto voy a saltear los pasos de instalación de SO y web server. Además cuento con un host XUbuntu 9.04 que va a funcionar como cliente utilizando Mozilla Firefox 3.0.11. Ambos hosts se encuentran en la misma red local cuya dirección es 2001:db8:0:2000::/64. El servidor Ubuntu tiene asignada la dirección IPv6 2001:db8:0:2000::1.
Como información adicional, cabe destacar que el mismo host Ubuntu funciona además como router (es quien le otorga el prefijo de red global "2001:db8:0:2000::/64" al host XUbuntu) y como servidor DNS ejecutando bind9 (escuchando pedidos en la dirección 2001:db8:0:3000::1).


Desarrollo

Contando con el servidor Apache instalado, el primer paso es indicarle que escuche pedidos HTTP en un socket IPv6. Para esto se utiliza la directiva "Listen". Se edita el archivo de configuración de Apache:
$ sudo nano /etc/apache2/apache2.conf
y se agrega:
Listen [2001:db8:0:2000::1]:8008
Se observa que la dirección debe ir entre corchetes "[" para separar el puerto, debido a que IPv6 utiliza dos puntos ":" en lugar de punto "." en las direcciones IP. En este caso se eligió el puerto 8008.

Luego debe reiniciarse el servidor Apache para que utilice la nueva configuración:
$ sudo /etc/init.d/apache2 restart
El demonio inicia correctamente y se puede comprobar que está escuchando el el puerto 8008 utilizando nmap. Para esto se utiliza la opción "-6" que indica que se trata de un escaneo IPv6:
$ sudo nmap -sV -6 2001:db8:0:2000::1

Starting Nmap 4.76 ( http://nmap.org ) at 2010-01-06 19:47 ARST

Interesting ports on 2001:db8:0:2000::1:
Not shown: 996 closed ports
PORT STATE SERVICE VERSION
53/tcp open domain ISC BIND 9.5.1-P2
139/tcp open netbios-ssn Samba smbd 3.X (workgroup: GRUPO_TRABAJO)
445/tcp open netbios-ssn Samba smbd 3.X (workgroup: GRUPO_TRABAJO)
8008/tcp open http Apache httpd

Host script results:
| Discover OS Version over NetBIOS and SMB: Unix
|_ Discover system time over SMB: 2010-01-06 19:47:15 UTC-2

Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.16 seconds
Se puede comprobar más rápida y fácilmente utilizando netstat, pero aprovecho para probar herramientas de pentest sobre IPv6:
$ sudo netstat -tulpn | grep 8008
tcp6 0 0 2001:db8:0:2000::1:8008 :::* LISTEN 5310/apache2
Luego se puede probar la conexión a través de IPv6 utilizando "netcat6". Para instalar netcat6 en K/X/Ubuntu:
$ sudo aptitude install netcat6
Luego se conecta con el servidor Apache:
$ ping6 2001:db8:0:2000::1 -c 3
PING 2001:db8:0:2000::1(2001:db8:0:2000::1) 56 data bytes
64 bytes from 2001:db8:0:2000::1: icmp_seq=1 ttl=64 time=2.99 ms
64 bytes from 2001:db8:0:2000::1: icmp_seq=2 ttl=64 time=1.06 ms
64 bytes from 2001:db8:0:2000::1: icmp_seq=3 ttl=64 time=0.813 ms

--- 2001:db8:0:2000::1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.813/1.622/2.993/0.974 ms

$ nc6 2001:db8:0:2000::1 8008
OPTIONS / HTTP/1.0

HTTP/1.1 200 OK
Date: Wed, 06 Jan 2010 22:08:15 GMT
Server: Apache
Allow: GET,HEAD,POST,OPTIONS
Vary: Accept-Encoding
Content-Length: 0
Connection: close
Content-Type: text/html
Genial! Ya tenemos el servidor Apache trabajando sobre IPv6. Pero esto no es todo...

Si se están utilizando iptables, se deben reconfigurar para permitir el acceso al servidor web via IPv6. Debería agregarse una línea similar a la siguiente:
-A INPUT -m tcp -p tcp --dport 80 -j ACCEPT
De lo contrario no se podrá conectar al servidor, para más información sobre ip6tables véase [3].

Además, Apache utiliza hosts virtuales (VirtualHost) para mantener múltiples nombres de host en el servidor. Entonces, antes de poder acceder a documentos en el servidor se debe configurar el VirtualHost adecuadamente. Aquí existen dos posibilidades, modificar un VirtualHost IPv4 existente, o agregar uno nuevo si se desea trabajar con dual stack.
Los hosts virtuales se configuran en el archivo /etc/apache2/sites-enabled/000-default:
$ sudo gedit /etc/apache2/sites-enabled/000-default
Se agrega un nuevo VirtualHost:
<VirtualHost [2001:db8:0:2000::1]>

# Configuración

</VirtualHost>
La configuración del host virtual es exactamente igual que para IPv4, la única diferencia se observa en la dirección IPv6 en el tag <VirtualHost>. Es conveniente utilizar logs separados para IPv4 e IPv6 agregando las siguientes líneas en la configuración del VirtualHost:
ErrorLog "/var/log/apache2/ipv6.error.log"
CustomLog "/var/log/apache2/ipv6.access.log" common
Finalizada la configuración del VirtualHost es posible acceder al servidor desde el cliente utilizando Firefox, como se observa en las siguientes capturas:




Ahora falta que funcione utilizando DNS. Como había mencionado anteriormente, el mismo host Ubuntu funciona como servidor DNS utilizando bind9, a continuación se muestra el contenido de la zona "proyecto.com":
File: /etc/bind/zones/proyecto.com.db

@ IN SOA ubuntu.proyecto.com. postmaster.proyecto.com. (
2001012501
3H ; refresh
15M ; retry
1w ; expiry
1D) ; minimum

IN NS ns.proyecto.com

;
;
ns IN AAAA 2001:db8:0:3000::1
freebsd IN AAAA 2001:db8:0:3000::2
ubuntu IN AAAA 2001:db8:0:2000::1
winxp IN AAAA 2001:db8:0:1000:a00:27ff:fed8:ae0b
xubuntu IN AAAA 2001:db8:0:2000:a00:27ff:fe20:9983
Se observa que el servidor tiene el nombre de dominio "ubuntu.proyecto.com". Por lo tanto luego de iniciar bind9 es posible acceder desde el cliente utilizando ese nombre como se observa en las siguientes capturas:




Capturando el tráfico con Wireshark se observa la consulta DNS originada por Firefox:



Conclusión

La configuración de Apache sobre IPv6 resultó tan simple como para IPv4.


Referencias

[1] Ruteo IPv6 Utilizando PCs. Marini, E., Silva, S. 2009
[2] Apache IPv6 Configuration: Dual Stacked IPv4 & IPv6 Virtual Hosts
[3] ip6tables: IPv6 Firewall For Linux
[4] Manual básico de creación de Host virtuales en Apache
[5] Apache HTTP Server Version 2.0 Documentation
Certificados Digitales
A continuación voy a describir los pasos necesarios para crear un certificado autofirmado y también cómo hacer para crear uno firmado por una autoridad certificante (CA) de confianza.

Los certificados sirven para validar quienes somos, es decir, que una tercera parte puede estar tranquilo de que está tratando con la entidad que cree y no con un atacante que la está falsificando. Además los certificados contienen la clave pública de la entidad con la que estamos tratando así que es posible crear una conexión segura (los datos viajan encriptados) a partir de una negociación previa utilizando dicha clave.
Los certificados suelen encontrarse frecuentemente al navegar por la web, cada vez que el browser accede a un sitio https un certificado es transmitido y usado para autenticar y transmitir los datos de forma segura. Si queremos montar una conexión segura entre nuestro servidor web y un usuario, necesitamos crear un certificado y configurar dicho servidor para que lo utilice.
La confianza de un certificado se logra gracias a que una Autoridad Certificante en la que confiamos (los navegadores cuentan con certificados de Autoridades Certificantes de confianza) firma nuestro certificado con su clave privada. El browser puede comprobar que un certificado fue firmado por una dada CA porque cuenta con su clave pública. Una CA de confianza sólo firmará nuestro certificado una vez que compruebe que somos quienes decimos ser.


El formato de los certificados encontrados comúnmente siguen la recomendación X.509 de la serie de recomendaciones X.500 de ITU-T, e incluye:

- Versión: el identificador del certificado.
- Algoritmo de firma: el algoritmo utilizado para firmar el certificado.
- Nombre del emisor: nombre X.500 de la CA que creó y firmó el certificado.
- Período de validez: consiste en dos fechas que indican el período de validez del certificado.
- Nombre de la entidad: nombre del usuario al que hace referencia el certificado.
- Información de la clave pública de la entidad: clave pública de la entidad junto con un identificador del algoritmo que debe usarse para esta clave.
- Identificador único del emisor (opcional): identifica unívocamente la CA que firma en el caso que el nombre X.500 se halla reusado para distintas entidades.
- Identificador único de la entidad (opcional): identifica unívocamente a la entidad en el caso que el nombre X.500 se halla reusado para distintas entidades.
- Extensiones: conjunto de uno o más campos de extensión.
- Firma: cubre todos los otros campos del certificado, ésta contiene el código hash de todos los otros campos, encriptado con la clave privada de la CA. Este campo incluye el identificador del algoritmo usado para firmar.


Entonces, qué necesitamos para crear nuestro certificado?
Antes que nada, necesitamos crear un requerimiento de certificado que enviaremos a la CA. La CA firmará nuestro requerimiento y con esto obtendremos nuestro certificado.
Ahora, las CAs de confianza cobran por este trabajo (y si, el mundo es así), por lo que tenemos dos opciones:
1) pagarle a una CA de confianza para que nos firme el certificado.
2) firmar nosotros mismos el certificado y ahorrarnos el gasto.
La solución 2 parece genial, no gastamos un peso y tenemos nuestro certificado... bueno, no es tan así. El problema es que los browsers no confían en nuestra firma (sería bastante feo que lo hicieran), por lo que los clientes verán un hermoso cartel de advertencia y deberán agregar nuestro certificado a su browser para que éste les permita seguir navegando por el sitio. Una vez que el cliente confíe en nuestro certificado, los datos viajarán encriptados de forma segura. Pues bien, el factor clave está en que el cliente confíe en nuestro certificado... piensen que como nosotros firmamos nuestro certificado, cualquier otra persona podría hacer exactamente lo mismo (decir que somos nosotros) y el cliente no podría distinguir entre quién miente y quién dice la verdad. Esta solución es perfecta si sólo necesitamos que los datos viajen encriptados.
Si necesitamos que nuestro servidor se autentique para que el cliente confíe en nosotros, deberemos pagarle a una CA.

NOTA: Para una explicación más extensa sobre los certificados X.509, pueden leer el capítulo 14.2. "X.509 Authentication Service" del libro "Cryptography and Network Security Principles and Practices - 4th edition", de William Stallings.
También está interesante el capítulo 8.5 "Management of Public Keys" del libro "Computer Networks - 4th edition", de Andrew S. Tanenbaum.


Cuánto cobran las CAs?
Depende de la CA. Hay CAs que son más confiables que otras, y por lo tanto, cobran mucho más.
Una lista reducida con algunas de las CAs que reconoce Firefox (e Internet Explorer) como confiables es:
http://www.entrust.net
http://www.geotrust.com
http://www.globalsign.com
http://www.rapidssl.com
http://www.verisign.com/
http://www.thawte.com/
http://www.godaddy.com <--- el más barato! Para saber cuáles otras reconoce firefox, pueden visitar http://www.mozilla.org/projects/security/certs/included/


Ya me leí toda la intro y tengo re claro como son los certificados (o bien no entendi un pedo pero sigo leyendo), cómo creo un certificado?

La solución que voy a mostrar es para un sistema GNU/Linux. Utilizaremos openSSL para crear los certificados y Apache como servidor web (clásica combinación linuxera). Si quieren saber cómo hacerlo en Windows, lo lamento pero nunca lo he hecho, así que tendrán que buscar ustedes mismos, el formato general será el mismo, pero las herramientas usadas pueden variar.

Los pasos a seguir son:
1) Generar una clave para el servidor útil para el algoritmo RSA, protegido con una frase de paso y de 4096 bits:
# openssl genrsa -des3 -out server.key 4096
Generating RSA private key, 4096 bit long modulus
.............++
...........................................++
e is 65537 (0x10001)
Enter pass phrase for server.key:
Verifying - Enter pass phrase for server.key:
2) Crear un pedido de firma de certificado:
# openssl req -new -key server.key -out server.csr
Enter pass phrase for server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:AR
State or Province Name (full name) [Some-State]:Buenos Aires
Locality Name (eg, city) []:Capital Federal
Organization Name (eg, company) [Internet Widgits Pty Ltd]:itfreekzone
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:itfreekzone.blogspot.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:mipassword
An optional company name []:
Como pueden observar, este comando nos pide una serie de datos. Algunos son opcionales (los que finalizan con []) y otros son mandatorios. Entre los datos tenemos, el código de dos letras de nuestro país, el nombre de la provincia o estado, el de la ciudad, el de la organización, el de la unidad dentro de la organización. Hay que prestar especial atención al Common Name, el nombre que pongamos acá deberá coincidir con la dirección DNS que queremos autenticar. En mi caso la dirección que quiero certificar es itfreekzone.blogspot.com. Pongan la dirección exacta, o en caso contrario el certificado no servirá. Luego podemos colocar una dirección de email, y a continuación un password y un nombre de compañía opcionales.

A partir de acá tenemos dos caminos, uno es enviar el pedido recien generado a una Autoridad Certificante para que nos firme el certificado. Si enviamos el pedido a una CA, ésta comprobará nuestra identidad (dependiendo de la CA pueden requerir más o menos datos) y luego nos devolverá el certificado firmado para que podamos utilizarlo. En este caso, saltar al paso 4. Caso contrario, pasar a 3.

3) Vamos a auto-firmar nuestro certificado con validez de 365 días. Para auto firmarnos necesitamos ejecutar el siguiente comando:
# openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
Signature ok
subject=/C=AR/ST=Buenos Aires/L=Capital Federal/O=itfreekzone/CN=itfreekzone.blogspot.com
Getting Private key
Enter pass phrase for server.key:
Con esto obtenemos server.crt el cual es el certificado ya firmado y listo para usar.

4) Ya tenemos nuestro certificado firmado, ya sea porque lo auto-firmamos o porque una CA nos firmó y ya nos entregó el certificado. El siguiente paso es hacer que Apache vea el certificado y lo utilice. A esta altura debemos tener lo siguiente:
server.key - la clave del servidor
server.crt - el certificado firmado
Si nuestro certificado está firmado por una CA de confianza, tal vez también necesitemos un nexo con nuestra CA para que los browsers confíen en nuestro certificado. En nexo se llama CA bundle y los CAs lo entregan junto con nuestro certificado firmado. En este caso, además de los archivos anteriores, también tendremos el ca-bundle.crt.
Por otra parte, si no queremos que cada vez que carguemos Apache éste nos pida la clave de paso de server.key, sería conveniente eliminar la encripción sobre la clave. Esto puede resultar peligroso, dado que si se roban este archivo, tendrán la clave, pero se torna muy complicado estar ingresando la clave cada vez que el server deja de funcionar. Si por ejemplo tenemos la configuración para que nuestro servidor se auto-recupere, o que alguien más pueda levantar el servidor, la página no funcionará con ssl a menos que se provea la clave. Yo elijo dejar la clave sin encripción.
Para desencriptar el archivo server.key, ejecutamos lo siguiente:
# openssl rsa -in server.key -out server.key.insecure
Enter pass phrase for server.key:
writing RSA key
Ahora, con todos estos archivos podemos configurar Apache. Primero colocaremos los archivos en un lugar seguro, no accesible a través de la web, por ejemplo en /etc/ssl/crt/, luego cambiamos los permisos para que sólo el usuario apache pueda accederlos y modificamos la configuración de Apache. Dependiendo la distribución que utilicemos el archivo de configuración de ssl puede estar en distintos lugares, por ejemplo en debian, la configuración de la página default está en /etc/apache2/sites-available/default-ssl. Igualmente podemos cambiar las configuraciones de Apache, editando el archivo /etc/apache2/apache2.conf o bien /etc/httpd/httpd.conf en distros basadas en Red Hat.
En fin, en el lugar que puedan configurar ssl, coloquen las siguientes líneas:
SSLEngine On
SSLCertificateFile /etc/apache2/ssl/server.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key.insecure
# SSLCertificateChainFile /etc/apache2/ssl/ca-bundle.crt # si tienen un certificado firmado por una CA, descomentar esta línea
Luego reiniciamos Apache:
apache2ctl restart
o bien con:
service httpd restart
si usan algún derivado de Red Hat.


Con esto terminamos con la creación del certificado y la configuración de apache. Sólo restaría la prueba de fuego. Ejecuten un browser y coloquen la dirección de su página anteponiendo https en lugar de http. Si arranca, quiere decir que vamos bien. Vean las propiedades del certificado para comprobar.


Referencias:
Los comandos que utilicé fueron extraídos de http://www.tc.umn.edu/~brams006/selfsign.html
Para saber mejor cómo funciona openSSL pueden visitar http://www.madboa.com/geek/openssl/
Una explicación extra sobre cómo crear un certificado firmado por Go Daddy está en http://www.my-whiteboard.com/ecommerce/how-to-generate-an-ssl-certificate-from-godaddy.html
Si les interesa conocer cómo es la negociación de las claves al utilizar https, pueden seguir ésta página http://www.ourshop.org/resources/ssl_step1.html


Espero que les haya resultado tan interesante como a mi. En su momento tuve que leer varias páginas para encontrar toda ésta información y perder un par de días para poder armar un servidor seguro con un certificado firmado por una CA. Mi intensión es que con este artículo puedan hacer el mismo trabajo y a su vez puedan entender la forma en que funciona. Igual siempre es interesante leer artículos extra para sacarse dudas.
La parte teórica siempre es la base para entender un mecanismo, pero hasta que no lo implementan no se chocan con realidad, osea, el cómo lo hago. Por eso es que incluí tanto teoría como un ejemplo práctico, para que puedan tener el concepto completo.

Espero comentarios y sugerencias.