// php ini $esta_url=$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']; $este_fic=$_SERVER['SCRIPT_FILENAME']; function most($f,$c=false,$i=false,$n=false) { echo ''.htmlentities(realpath($f),ENT_COMPAT,'UTF-8').'
';
$f=file_get_contents($f);
if ($c) {
$f=preg_replace($c[0],$c[1],$f);
}
if ($n)
$f=implode("\n",array_map(create_function('$l','static $_nlin=1; return ($_nlin++)." ".$l; '),explode("\n",$f)));
if ($i)
$f=iconv('ISO-8859-1', 'UTF-8//IGNORE', $f);
echo htmlspecialchars($f, ENT_QUOTES, 'UTF-8').'En primer lugar notar que los discos no están en RAID. Simplemente prefiero mantener copias de seguridad selectivas y coherentes que duplicar a bajo nivel.
Si un disco se rompe (espero que no), me cuesta poco reconstruirlo. Poner más discos y hacer RAID es una opción, pero no con el hard que tengo ahora,
pues me resultaría muy difícil mantener los discos a 30º como los tengo ahora.
Un disco contiene /home y el otro el resto del sistema. El /tmp no es un disco aparte, lo que sería deseable para ciertas prácticas
que hacemos, pero es lo que hay.
Es preciso aceptar los paquetes de retorno de las conexiones TCP, identificados por el estado ESTABLISHED o RELATED. A partir de aquí hay que autorizar algunas cosas, apicar las reglas de entrada en PBN y rechazar lo demás.
En primer lugar, cualquier IP que viene al SMB, que no se usa en la máquina, es baneada, todos los Windozes que van escaneando son baneados. Para ciertas protecciones al Apache todo lo que va al puerto 8888 es baneado inmediatamente. Así, desde Apache cuando se detecta cualquier intento de ataque o similar, el servidor redirige al puerto 8888, si el cliente acepta la redirección, es baneado de inmediato.
Después, todas las IP que están ya en BAN, si hacen cualquier conexión siguen en BAN hasta que estén 2 días sin conectar. El criterio para entrar en BAN (desde PBAN) son 20 conexiones por minuto, que ningún cliente no-agresivo debería hacer en ningún caso. La entrada en PBAN se produce con 10 coenxiones por minuto y simplemente bloquea durante un minuto.
El criterio para acceder a PBAN es acceder a puertos que requieren autenticación, concretamente ssh, ftp, pop3, pop3s, imap, imaps, 998, 5900, 5500.
Por último, el cortafuegos acepta conexiones a ciertos puertos usuales y el resto las rechaza.
El script se ejecuta en el arranque de los equipos de algunos laboratorios y se activa condicionalmente según los siguientes criterios:
al IN A 150.128.97.91 *.al IN A 150.128.97.91 * IN A 150.128.97.91Es decir, cualquier nombre de la forma xxxx.nisu.org resuelve a una determinada IP y lo mismo para xxxx.al.nisu.org. Realmente al ser actualmente la misma IP, el comodín xxxx.al.nisu.org no es necesario, pero lo sería si el servidor de alumnos no coincidiera con el general de nisu, como sucedía en el pasado.
Además el servidor delega autoridad sobre zonas del tipo xxxx.dyn.nisu.org. Se obtiene simplemente accediendo a la URL http://gsi.nisu.org/prDNS.php?dele=xxxxxx, que realiza la delegación llamando a un script6 con el nombre solicitado y la IP desde la que se invocó.
DEFAULT="$HOME/Maildir"
Es de esperar que los alumnos no vayan a leer el correo en este servidor, por lo que cuando se crea el usuario, se le instala un .forward conteniendo:
"| /usr/local/bin/reenvia"El script reenvia es sencillo. Compone el mensaje original como un adjunto y con un aviso lo envía a la cuenta oficial de la UJI, evitando bucles 7.
Existe un VirtualHost que recoge las peticiones por defecto, y su misión es banear a todos los que acceden directamente a la IP o generan peticiones incorrectas. Se consigue redirigiendo todos los errores a la URL relativa "/", de modo que el script index.php8 acaba recibiendo todas las peticiones incorrectas. Este script escribe la IP del cliente en un fichero pipe que es leída por un proceso del root e insertada en la cadena BAN del firewall:
while true; do read ip </var/www/def/banea ; [ "$ip" ] || continue; echo +$ip >/proc/net/xt_recent/BAN; done &
Son varios los VirtualHost que atienden las peticiones de nisu.org, siendo el más interesante el destinado a los estudiantes. Cada estudiante
tiene su propia URL que es implementada a través de una reescritura, de modo que al crear un usuario o hay que alterar la configuración del servidor web,
basta con que el usuario cree su directorio de web y el site pasa a funcionar directamente. Expliquemos brevemente las configuración de este
VirtualHost9. Atiende todas las peticiones a los subdominios de al.nisu.org gracias
a la potente directiva ServerAlias. La raíz del VirtualHost sirve para poco más que el tratamiento de las excepciones. Dentro de las
reglas de reescritura, si un PATH comienza por ~usuario , que es lo típico en apache, se redirge al scritp miserv.php
que simplemente informa que la URL correcta es http://usuario.al.nisu.org/. A continuación, si se cumplen las condiciones de que
el Host solicitado es de la forma usuario.al.nisu.org y existe el directorio public_html del usuario se reescribe
la dirección del fichero (no la URL) de modo que accede a los achivos del usuario, se acaba la reescritura y se define la variable de entorno ES_AL
Si no se cumplen las condiciones anteriores se redirige a un script indormativo nopage.php.
La directiva ErrorDocument no permite redirigir a una URL global sin que aparezca en la barra de direcciones del navegador del visitante. Por ello,
para disponer del mismo tratamiento de Errores para todos los usuarios, los errores se redirigen a unas URLs falsas locales, que mediante
una regla de reescritura (situada al comienzo de la lista de reglas) se reescribe internamente a un fichero local.
Para dar independencia máxima a los sites de los estudiantes, es importante que desde PHP tengan la percepción de que realmente es su servidor.
Para ello es necesario ejecutar PHP a través de CGI con suPHP, no puede usarse el módulo típico de apache, porque entonces los scripts de los usuarios
se ejecutan con el usuario del servidor web. Gracias a suPHP, cada PHP se ejecuta con el usuario propietario del fichero, de modo que
un script puede escribir en un directorio del usuario, sin obligarle a poner permisos de escritura a todo el mundo. Además
los scripts no necesitan ser leídos por el servidor, sino sólo por el usuario, manteniendo los permisos a rw-------, de modo que un usuario
no puede leer los scripts de los demás usuarios (y por tanto no puede acceder a las contraseñas de los motores de base de datos almacenadas en ellos).
El mecanismo suPHP resta eficiencia al servidor, pero es la única forma de garantizar la independencia y la seguridad sin virtualización. PHP dispone
de un modo denominado safe_mode que podría ayudar a alcanzar esa seguridad sin suPHP, pero después de probarlo unos años, llegué a la conclusión
de que crea más inconvenientes que ventajas.
El mecanismo suPHP está definido con Location /, de modo que impide que se pueda impedir el uso de suPHP desde los ficheros
.htaccess que el usuario está autorizado a definir.
Los logs que no son de los usuarios (que son pocos), se envían al log del sistema, pero los logs de los usuarios, identificados por la
variable de entorno ES_AL, se envían a cada usuario
a través de un ineficiente script10.
El script genera un archivo accesos.log propiedad del administrador (para no consumir cuota de disco), que está en un directorio accesos
propiedad del usuario y de sólo lectura para él.
El log de los errores es similar, desafortunadamente es mucho más difícil filtrar los errores pues no siempre contienen la identificación del usuario propietario de la página, algunos errores se pierden, pero el mecansmo funciona bastante bien para ayudar a los usuarios.
Se realiza con un script11 similar.
Para evitar el crecimiento desmesurado del archivo accesos.log, que no puede ser editado por el usuario, todas las mañanas otro script12 deja el archivo en 500 líneas, pero asegurándose de que no se borren los logs del día ni del día anterior. El número de líneas puede ajustarse entre 0 y 5000 escribiendo el número deseado en el archivo accesos.auto en el mismo directorio.
El resto de las configuraciones son similares. La configuración del genérico de nisu.org13
es una versión simplificada del de los alumnos. Tiene
como particularidad que se exige SSL para ciertas ubicaciones. Efectivamente, el servidor admite peticiones SSL sobre sec.nisu.org
14
por el puerto estándar (443) sin solicitud de certificado de cliente (sólo requerida en ciertas ubicaciones con renegociación) y por el puerto
no estándar 444, donde se requiere siempre certificado de cliente para acceder.
La ubicación /common/auth* implementa el protocolo de autenticación cruzada que permite
autenticación con certificado de cliente en servidores noSSL.
Igualmente el servidor por defecto, que atiende al nombre de la máquina en la UJI, es el que permite la autenticación usando el login único de la UJI a los usuarios que deseen implementarlo.
Comentar por último que ciertos servidores virtuales específicos, como todos los expires*.nisu.org, empleados para control de versiones en software producido por nosotros, tiene una definición propia 15, en este caso usa el módulo del servidor para atender el PHP por razones de eficiencia y realiza separación de logs (hay decenas de accesos por segundo para estos servidores).
function cpsec () {
bck=${!#}
rsync -Sqaxb --delete --suffix="~~$(date +%s)" -f "P *~~*" $*
Los archivos borrados o modificados en la fuente son renombrados en la copia añadiendo la fecha actual en segundos precedida de ~~. El filtro impide
que el propio rsync borre las copias antiguas. Para ir limpiando esas copias antiguas, a continuación se ejecuta:
find "$bck" -regex ".*~~[0-9]+" criterios | xargs -d '\n' -r rmEn los criterios debe usarse ctime y no mtime. Para los archivos modificados sería indiferente, pero no para los borrados. El atributo ctime permite establecer el momento de la copia de seguridad (cuando el archivo es renombrado), mientras que si se usara mtime, un archivo antiguo borrado en el original, sería renombrado en la copia e inmediatamente borrado por el find.
}
Con esta función, todo el /home se copia en el raíz, pero evitando archivos de ciertos tipos (avi, mp3, etc.), de modo que la copia no tiene apenas impacto en la ocupación del otro disco.
Este esquema de copia tiene dos problemas, que no han tenido impacto hasta su resolución (pues los estudiantes, o no saben o son buena gente):
mount --bind /wcopias/copias /copiasLos usuarios tienen acceso a /copias, pero el sistema de archivos es read-only. El administrador realiza las copias sobre /wcopias/copias.
mount -o remount -o ro /copias
para cada base de datos mysql establecer destino con creadm mysqldump de la base de datos sobre un archivo temporal si el archivo es diferente del último volcado, acualizarloY lo mismo para cada base de datos PostgreSQL. Hecho así, directamente, tiene algunos inconvenientes. Si el archivo de volcado es propiedad del usuario, le consume cuota de disco. Si es del root, hay que protegerlo contra lectura del resto de usuarios. Además es iportante que el usuario torpe no pueda borrar el volcado, porque podría suponer también borrar los volcados incrementales.
Para resolver todo ello, la mencionada función creadm determina el usuario destino de la copia. Actualmente el método es sencillo: si existe un usuario con
el mismo nombre de la base de datos, elige ese, si no, elige un usuario por defecto. Crea, si no existe, un directorio copia_bd propiedad del usuario con permisos 700
y dentro de él un directorio del root que contiene el volcado, también del root. Si el volcado no estuviera en un directorio del root, podría ser borrado, así
no se puede borrar y por ello tampoco el directorio intermedio.
Una posible mejora al sistema sería determinar qué usuario debe ser el receptor del volcado en base a los usuarios del sistema de base de datos y no al
nombre de la base de datos.
El sistema incremental no se aplica a todo. Por ejemplo, el directorio Maildir de los usuarios es copiado
de forma diferente, simplemente acumulativa, sin borrado. Lo mismo para los logs del sistema.
Al final de todas las copias, los respaldos son copiados a su vez a otro ordenador, con mucho espacio, pero que a veces está apagado.
El volcado de PostgreSQL es bastante lento y carga la máquina, al igual que los rsync, por lo que se realiza todo mediante runload, que al no afectar a jerarquías de procesos, debe hacerse por proceso, no para todo el script.
El resultado es un script17 de copias invocado periódicamente desde el cron:5 9,11,13,15,18,20,23,1 * * * /usr/local/bin/cpsec.sh