Messa in sicurezza di MySQL: step-by-step
by Valentino R.
Ultimo Aggiornamento 24 Settembre 2003


1. Introduzione

MySQL è una dei database più popolare su Internet ed è usato spesso insieme con PHP. Oltre ai relativi vantaggi come facilità di utilizzo ed il rendimento relativamente elevato, MySQL offre meccanismi di sicurezza semplici, ma molto efficaci. Sfortunatamente, l'installazione di default di MySQL, ed in particolar modo il fatto che la password dell'accout dell'amministratore sia vuota (black), e alcuni attacchi potenziali del tipo di buffer overflow, fanno diventare il proprio database server un facile bersaglio per chi ci vuole attaccare.

Questo articolo descrive i punti salienti che dovrebbero essere seguiti per assicurare MySQL contro gli attacchi locali e remoti.

1.1 Funzionalità

Premessa di questo articolo, è che sulla macchina siano correttamente installati il web server Apache con il modulo PHP, i quali dovranno essere installati in conformità con gli articoli precedenti ('Messa in sicurezza PHP: Step-by-Step e Messa in sicurezza di Apache: Step-by-Step), e precismente nella directory /produzione/httpd.

Inoltre, bisogna assumere quanto segue:

  • Il Database Server MySQL deve essere usato esclusivamente con le applicazioni sviluppate in PHP, installate su questo host;
  • I Tools di amministrazione predefiniti, come mysqladmin, mysql, mysqldump etc. verranno utilizzati per gestire i database;
  • Il Back-UP remoto dei dati sarà effettuato con l'utilizzo delle connessioni SSH.

1.2 Requisiti di Sicurezza

Per realizzare un livello elevato di sicurezza, l'installazione e la configurazione di MySQL dovrebbero essere effettuate in conformità con i seguenti requisiti di sicurezza:
  • Il database MySQL dovrà essere eseguito in una directory dedicata dentro la quale verranno letti e scritti tutti i dati - chrooting -. Nel nostro caso tutto si svilupperà all'interno della directory /produzione;
  • I processi di MySQL dovranno essere eseguiti sotto un unico UID/GID, il quale non dovrà essere usato da qualsiasi altro processo di sistema - un UID/GID dedicato -;
  • Saranno consentito solo gli accessi locali a MySQL;
  • L'accout di amministazione di MySQL (root) dovrà essere protetto con l'utilizzo di una password non indovinabile da chiunque;
  • L'account di amministrazione dovrà essere rinominato;
  • Gli accessi 'Anonimi' al database (usandio l'account nobody) dovranno essere disattivati;
  • tutti i databases di esempio dovranno essere rimossi (vedi test).

2. Installiamo MySQL

Prima di mettere in sicurezza MySQL, dobbiamo installare il software sul server. Come negli articoli precedenti, inizieremo l'installazione generando un gruppo e un user sul sistema operativo, che sarà dedicato al database di MySQL:


pw groupadd mysql
pw useradd mysql -c 'MySQL Server' -d /dev/null \
-g mysql -s /sbin/nologin

2.1 Compilazione di MySQL

Compileremo ed installeremo il software di MySQL nella dyrectory /usr/local/mysql:


./configure --prefix=/usr/local/mysql --with-mysqld-user=mysql
--with-unix-socket-path=/tmp/mysql.sock
make
su
make install
strip /usr/local/mysql/libexec/mysqld
./scripts/mysql_install_db
chown -R root /usr/local/mysql
chown -R mysql /usr/local/mysql/var
chgrp -R mysql /usr/local/mysql

In generale, il processo di installazione del database server è quasi identico a quello descritto nel manuale di MySQL. L'unico cambiamento è l'uso di alcuni parametri supplementari, specificati nella linea di comando ./configure. I parametri che sono stati passati durante la configurazione serviranno durante la fase di compilazione e di installazione. Con il parametro --prefix=/usr/local/mysql, si dichiara di voler installare il DB-Server nella directory specificata; --with-mysqld-user=mysql, imposta che il demone deve essere avviato con i privilegi dello user mysql; --with-unix-socket-path=/tmp/mysql.sock genera la socket mysql.sock nella directory /tmp, questa socket servirÓ per comunicare con le varie applicazioni (PHP, Perl, ecc..),.

2.2 Copia del file di configurazione

Dopo l'esecuzione dei summenzionati comandi, dobbiamo copiare il file di configurazione in conformità con la tipologia di dimensioni di databases previsti (piccolo, medio, grande, enorme). Per esempio:


cp support-files/my-medium.cnf /etc/my.cnf
chown root:sys /etc/my.cnf
chmod 644 /etc/my.cnf

2.3 Avvio del server

A questo punto MySQL è finalmente installato e pronto all'avvio. Possiamo avviare MySQL server eseguendo il seguente comando:


/usr/local/mysql/bin/mysqld_safe &

2.4 Prova di connessione

Prova a stabilire una connessione con il database server eseguire il comando riportato di seguito:


/usr/local/mysql/bin/mysql -u root mysql
...dopo il quale sarà visualizzato quanto segue:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2 to server version: 4.X.YY-Z
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> show databases;
+----------+
| Database |
+----------+
| mysql    |
| test     |
+----------+
2 rows in set (0.00 sec)

mysql> quit;

Una volta che il collegamento è stabilito con successo, possiamo arrestare il database server:


/usr/local/mysql/bin/mysqladmin -u root shutdown

...e ora si inizia a mettere in sicurezza il software. Altrimenti, nel caso qualcosa sia andato storto, possiamo analizzare le informazioni che sono memorizzate nel file di log /usr/local/mysql/var/`hostname`.err, e eliminare poi la causa del problema.

3. Chrooting del server

Il primo punto di messa in sicurezza di MySQL è di preparare l'ambiente di lavoro, in cui MySQL server funzionerà. La tecnica chrooting è stata descritta dettagliatamente nel primo articolo di questa serie ('Messa in sicurezza di Apache: Step-by-Step'), in modo tale che se non si ha una conoscenza di questa tecnica o del perchè chrooting è suggerito, puoi essere utile leggerlo.

3.1 Sistema Operativo

Il metodo presentato è possibile applicarlo nei più attuali sistemi operativi UNIX e UNIX-like. Nel nostro caso. il sistema nel quale si sta installando MySQL è il sistema operativo Linux, nella fattispecie la distribuzione Slackware.

3.2 Preparazione dell'ambiente produzione

Pre preparare l'ambienti di sviluppo, si dovrà generare la seguente struttura di directory:


mkdir -p /produzione/mysql
mkdir -p /produzione/mysql/dev
mkdir -p /produzione/mysql/etc
mkdir -p /produzione/mysql/tmp
mkdir -p /produzione/mysql/var/tmp
mkdir -p /produzione/mysql/usr/local/mysql/libexec
mkdir -p /produzione/mysql/usr/local/mysql/share/mysql/english

3.3 Setta i privilegi di accesso

I privilegi di accesso dovrebbero essere regolati come segue:


chown -R root:sys /produzione/mysql
chmod -R 755 /produzione/mysql
chmod 1777 /produzione/mysql/tmp

3.4 Generare la struttura della directory

Passo successivo, i seguenti file devono essere copiati nella nuova struttura della directory:


cp /usr/local/mysql/libexec/mysqld
/produzione/mysql/usr/local/mysql/libexec/
cp /usr/local/mysql/share/mysql/english/errmsg.sys
/produzione/mysql/usr/local/mysql/share/mysql/english/
cp /etc/hosts /produzione/mysql/etc/
cp /etc/host.conf /produzione/mysql/etc/
cp /etc/resolv.conf /produzione/mysql/etc/
cp /etc/group /produzione/mysql/etc/
cp /etc/master.passwd /produzione/mysql/etc/passwords
cp /etc/my.cnf /produzione/mysql/etc/

3.5 Rinforzare le password e i gruppi

Dai files: /produzione/mysql/etc/passwords e /produzione/mysql/etc/group dobbiamo rimuovere tutte le linee tranne l'user ed il gruppo di mysql. Dopo, dobbiamo creare il database di password come di seguito (questo si applica soltanto a FreeBSD):


cd /produzione/mysql/etc
pwd_mkdb -d /produzione/mysql/etc/passwords
rm -rf /produzione/mysql/etc/master.passwd

3.6 Particolari considerazioni

Nel caso del web server Apache, dobbiamo generare il file del dispositivo /dev/null, come di seguito:

ls -al /dev/null
 crw-rw-rw-  1 root  sys    2,   2 Jun 21 18:31 /dev/null
mknod /produzione/mysql/dev/null c 2 2
chown root:sys /produzione/mysql/dev/null
chmod 666 /produzione/mysql/dev/null

Dobbiamo anche copiare il database mysql, al cui interno sono contenute le tabelle con le autorizzazioni generate durante l'installazione:


cp -R /usr/local/mysql/var/ /produzione/mysql/usr/local/mysql/var
chown -R mysql:mysql /produzione/mysql/usr/local/mysql/var

3.7 Localizzazione

E' possibile personalizzare il proprio database server MySQL, configurandolo per l'utilizzo del file charset per la propria lingua, il quale si trovano nella directory /usr/local/mysql/share/mysql/charsets.

3.8 Test di configurazione

A questo punto MySQL è pronto per per iniziare a lavorare nell'ambiente di sviluppo. Possiamo provare il corretto funzionamento eseguendo il comando:


chrootuid /produzione/mysql mysql /usr/local/mysql/libexec/mysqld &

Se si verificano degli errori, sarà possibile utilizzare il comando truss oppure in alternativa, come anche ktrace/kdump, strace, etc. Questi tools potranno aiutarti a determinare la causa del problema.

AVVISO: Perchè è stato usato il programma chrootuid al posto di chroot, come nel caso di Apache o di PHP? La rispostaa è nella loro differenza di modificare i privilegi. In sostanza, chrootuid cambia il proprietario del processo di esecuzione. Nel nostro esempio, mysqld è in esecuzione in un ambiante dedicato, ma il proprietario del processo non è l'utente root ma l'utente mysql. Il chrootuid non è installato di default in molti sistemi operativi e può essere necessario installarlo manualmente. Il chrootuid può essere scaricato da qui.

4. Configurazione del server

Il prossimo passo è quello di configurare il database server in conformità ai nostri requisiti di sicurezza.

Nel caso di una installazione di default di MySQL, il file di configurazione è /etc/my.cnf. Nel nostro caso, tuttavia, a causa dell'esecuzione del database server in un ambiente di sviluppo, è possibile utilizzare due file: /produzione/mysql/etc/my.cnf e /etc/my.cnf. Il primo viene utilizzato dal database server, mentre il secondo dai tools di MySQL (e.s. mysqladmin, mysql, mysqldump etc.). In entrambi i casi, saranno necessari effettuare alcune modifiche ad entrambi i files.

4.1 Disattivare l'accesso remoto

La prima modifica si applica alla porta 3306/tcp, che è di default in ascolto per le connessioni da remoto. Ciò è uno dei presupposti iniziali, cioè che il database sarà usata soltanto dalle applicazioni localmente installate di PHP, possiamo quindi disattivare l'ascolto su quella porta. Ciò limiterà le possibilità di attacco da remoto del database server MySQL. La comunicazione locale sarà ancora possibile grazie alla socket mysql.sock. Per disattivare l'ascolto sulla porta 3306/tcp, bisogna effettuare un'aggiunta nella sezione [mysqld] del file /produzione/mysql/etc/my.cnf:


skip-networking

Se, per qualche motivo, l'accesso da remoto al database è necessario (e.s. per effettuare il salvataggio dei dati a distanza), può essere usato il protocollo SSH come segue:


backuphost$ ssh [mysqlserver] /usr/local/mysql/bin/mysqldump
-u [user] --password=[password] [noma_db] > backup.sql

In alcuni casi, Ŕ anche necessario poter effettuare l'importazione di dati nel nostro database, dati che sono contenuti all'internod di file, sotto forma di query sql:


backuphost$ ssh [mysqlserver] /usr/local/mysql/bin/mysql
-u [user] --password=[password] -D [noma_db] < restorefile.sql

4.2 Migliorie per la sicurezza locale

Il prossimo cambiamento è di disattivare l'uso del comando LOAD DATA LOCAL INFILE. Ciò farà si che si può evitare la lettura di file locali in modo non autorizzato. Ciò è importate per evitere l'ignezione di eventuali nuove vulnerabilità SQL tramite applicazioni PHP.

A tal proposito, il seguente parametro deve essere aggiunto nella sezione [mysqld] nel file /produzione/mysql/etc/my.cnf:


set-variable=local-infile=0

In più, per rendere pratico l'uso dei tools amministrativi del database, il seguente parametro che si trova nella sezione [client] del file /etc/my.cnf, dovrebbe essere cambiato come segue:


socket = /produzione/mysql/tmp/mysql.sock

Grazie a questa modifica, sarà possibile utilizzare i comandi mysql, mysqladmin, mysqldump etc. con il parametro --socket=/produzione/mysql/tmp/mysql.sock sempre impostato.

4.3 Cambiare la password di amministratore

Uno dei punti più importanti nel mettere in sicurezza MySQL sta nel cambiare la password dell'amministratore (root) del database, che è vuota per default. Per effettuare ciò, dovremmo fare avviare MySQL (se già è già stato avviato):


chrootuid /produzione/mysql mysql
/usr/local/mysql/libexec/mysqld &

e cambiare la password di amministratore come segue:


/usr/local/mysql/bin/mysql -u root
mysql> SET PASSWORD FOR root@localhost=PASSWORD('new_password');

è buona norma non cambiare le password dalla linea di comando, per esempio, usando 'mysqladmin password'. Ciò è particolarmente importante quando ci sono altri utenti che lavorano sul server, in quanto la parola d'accesso potrebbe essere rivelato facilmente, per esempio usando il comando 'ps -auxw' oppure rivisualizzando l'history files (~/.history, ~/.bash_history etc), quando i privilegi di accesso lo consentono.

4.4 Rimuovere gli utenti/db di default

Ora dobbiamo rimuovere il database di esempio (prova) e tutti gli utenti di default tranne il l'account locale di root:

 mysql> drop database test;
 mysql> use mysql;
 mysql> delete from db;
 mysql> delete from user where not \
 	(host='localhost' and user='root');
 mysql> flush privileges;

Ciò impedirà il collegamento ai database da connessioni anonime anche da remoto, anche se è impostato il parametro skip-networking all'interno del file /produzione/mysql/etc/my.cnf.

4.5 Cambiare il nome dell'utente amministratore

Sarebbe cosa giusta cambiare il nome della user di default dell'acocunt di amministratore (root), con un nome utente meno indicativo. Con questo cambiamento è possibile creare maggiori difficolta a chi vorrebbe effetturare un attacco del tipo brute-force e o a dizionario per recuperare la password. In questo caaso l'intruso oltre a dover tentare di riuscire a capire qual'è la password, deve innanzitutto capire qual'è l'account di amministratore.


mysql> update user set user='morpheus' where user='root';
mysql> flush privileges;

4.6 Rimuovere i file di log history

Infine, bisogna rimuovere il contenuto del file di history (~/.mysql_history) di MySQL, all'interno del quale sono conservati tutte le stringhe di comando impartite al database server (specialmente le passwords, che sono archiviate in chiaro):


cat /dev/null > ~/.mysql_history

5. Comunicare tra PHP e MySQL

Nell'articolo precedente ('Messa in sicurezza PHP: Step-by-Step'), è stato mensionato il problema di comuniczione che può esserci tra PHP e MySQL durante l'esecuzione di uno di questi programmi in un ambiente chroottato. Il perchè è spiegato dal fatto che PHP e MySQL comunicano usando la socket che si trova in /tmp/mysql.sock. La soluzione del problema sarebbe quello di creare un link fisico della socket nell'ambiente di sviluppo chroottato:


ln /produzione/mysql/tmp/mysql.sock /produzione/httpd/tmp/

Nota sulla socket /produzine/mysql/tmp/mysql.sock e sulla directory /produzione/httpd/tmp che dovranno resiedere all'interno dello stesso filesystem. Altrimenti i programmi non riuscirebbero a comunicare tra di loro - il link fisico non riesce a eseguirsi tra filesystem differenti -.

6. Passo finale

A questo punto potete creare tutti i database e gli account per ogni vostra applicazione scritta in PHP. E' fondamentale che ogni account possa accedere esclusivamente al proprieo databases usando la rispettiva applicazione sviluppata in PHP. Si raccomanda che nessun user deve aver accesso al database mysql, o a nessun privileggio di amministratore con la possibilità quindi di eseguire uno dei comandi SQL che sono prerogativa dell'admin (FILE, GRANT, ALTER, SHOW DATABASE, RELOAD, SHUTDOWN, PROCESS, SUPER etc.).

Come ultimo passo, ma non per questo meno importante, bisogna creare uno script schell che avvi il nostro database server MySQL all'avvio del sistema operativo L'esempio ch'è di seguito riportato, è possibile scaricarlo qui:

#!/bin/sh

CHROOT_MYSQL=/produzione/mysql
CHROOT_PHP=/produzione/httpd
SOCKET=/tmp/mysql.sock
MYSQLD=/usr/local/mysql/libexec/mysqld
PIDFILE=/usr/local/mysql/var/`hostname`.pid
CHROOTUID=/usr/local/sbin/chrootuid

echo -n "mysql"

case "$1" in
start)
        rm -rf ${CHROOT_PHP}/${SOCKET}
        nohup ${CHROOTUID} ${CHROOT_MYSQL} mysql \
        	${MYSQLD} >/dev/null 2>&1 &
        sleep 5 && ln ${CHROOT_MYSQL}/${SOCKET} \
        	${CHROOT_PHP}/${SOCKET}
        ;;
stop)
        kill `cat ${CHROOT_MYSQL}/${PIDFILE}`
        rm -rf ${CHROOT_MYSQL}/${SOCKET}
        ;;
*)
        echo ""
        echo "Sitassi: `basename $0` {start|stop}" >&2
        exit 64
        ;;
esac

exit 0

Nel nostro caso, che stiamo lavorando su un sistema Linux (Distribuzione Slackware), bisogna posizionare lo script nella directory /etc/rc.d, con il nome rc.mysql.

6.1 Sommario

Applicando gli accorgimenti descritti nel seguente articolo avremmo sicuramente incrementato la sicurezza del nostra database server MySQL. Avviando il database server in un ambiente chroottato, disabilitando la porta di connessione 3306/tcp e applicando delle password abbastanza complesse agli utenti, sarà possibile difendersi dai più comuni attacchi che vengono effettuati sulle installazioni di default di MySQL. Anche se nessun accorgimento ci darà una sicurezza al 100%, applicando questi accorgimenti è possibile limitare gli attacchi che un visitatore con intenzioni belligeranti può portare al nostro web-server durante la sua 'visita'.

mappa - disclaimer
Elav-Web le tue soluzioni contattaci
Soluzioni Informatiche Soluzioni Informatiche
Sviluppo software WebBased.
Elav-Web la tua soluzione I partner di Elav-Web news dal mondo IT

Tutorial


Sei il visitatore n° dal 22 settembre 2003.

Valid robots.txt Valid robots.txt Valid HTML 4.01 Transitional Valid CSS!