old_passwords in MySQL e interazione con il PHP

old_passwords

Nel dicembre 2003 MySQL ha modificato il sistema con cui vengono cifrate le password. Fino alla versione 4.0 veniva usato un hash a 16 caratteri, mentre da 4.1 in poi è stato introdotto un hash più complesso, a 41 caratteri (in realtà sono 40, con un asterisco iniziale).

Per garantire la compatibilità con i vecchi client (cioè quelli più vecchi del 2003), MySQL ha introdotto l’opzione di configurazione old_passwords, che se posta a  1 continua a codificare le password con i vecchi hash a 16 caratteri.

Il vecchio sistema, naturalmente, è meno sicuro e fortemente scoraggiato.

No one should be using these anymore. This variable makes the password hashing algorithm compatible with that of MySQL 4.0. I’m pretty sure 4.0 was released 9 years ago. I don’t know of anyone still using it (or 4.0 client libraries).

http://planet.mysql.com/entry/?id=27450 (del 2011)

L’unico motivo per utilizzare  old_passwords=1 è se si ritiene che ci siano in giro client precedenti al 2003.

I dettagli del sistema di gestione delle password sono raccontati a http://dev.mysql.com/doc/refman/5.0/en/password-hashing.html

I nuovi client MySQL sono comunque compatibili con il vecchio sistema. I nuovi client, in altre parole, inviano entrambi gli hash e possono connettersi anche al vecchio MySQL < 4.1.0 e al nuovo MySQL > 4.1.0 con old_passwords=1. (Il caso MySQL 4.1.0 è particolare e transitorio).

In altre parole, il tentativo di login con il client MySQL funziona in ogni caso e sembra che non ci siano problemi. A meno che…

Gli hash a 16 caratteri sono considerati così vecchi e poco sicuri che esiste un’altra opzione di configurazione, secure_auth, che serve ad impedire il login con vecchie password. A partire da MySQL 5.6.5 (marzo 2012secure_auth è attivata per default.

Le conseguenze sul PHP

Se le password vengono generate mentre old_passwords=1, le conseguenze sul PHP sono abbastanza dolorose e producono effetti a catena. Riguardano la qualità dei programmi, le performance, la compatibilità con gli aggiornamenti futuri e la sicurezza. E dipendono dalla versione.

A partire dalla versione 5.3.0 (giugno 2009), il PHP può connettersi al MySQL in due modi. O utilizzando le librerie fornite da MySQL (libmysqlclient) oppure con un client interamente riscritto in casa Zend (mysqlnd) per adattarsi alle particolarità delle applicazioni web.

L’uso delle mysqlnd è altamente raccomandato:

using the built-in mysqlnd library is highly recommended

http://www.php.net/manual/en/mysqlinfo.library.choosing.php

Un’applicazione web, infatti, esegue molto spesso query ripetute. Il client mysqlnd, perciò, possiede caratteristiche ulteriori come il caching delle query nel client e le lazy connections, eseguite solo quando le query hanno veramente bisogno di essere lanciate e non al momento indicato dal programmatore. Un gran vantaggio di performance, soprattutto in siti web con un numero medio/alto di visite.

Ma quando le mysqlnd sono state introdotte erano passati più di 5 anni da quando in casa MySQL hanno inventato il novo sistema di hash. Un tempo enorme per la velocità con cui si evolvono i software; e in casa PHP non hanno garantito così tanta compatibilità all’indietro: le mysqlnd NON sono compatibili con i vecchi hash a 16 caratteri.

La conseguenza, come si diceva, è diversa a seconda della versione del PHP.

Fino al PHP 5.5.0 escluso, le diverse librerie erano associate alle API disponibili. Le uniche API capaci di autenticarsi con gli hash a 16 caratteri erano le mysql_*, che sono procedurali, impongono tecniche di programmazione obsolete e sono ormai deprecate (http://www.php.net/manual/en/function.mysql-connect.php). Le  mysql_*, infatti, non hanno protezioni contro l’SQL injection, e quindi la sicurezza è affidata soltanto all’esperienza e alla concentrazione del programmatore, cioè è a rischio di errore umano.

Con versioni del PHP precedenti alla 5.5.0, insomma, si è costretti irrimediabilmente a scrivere programmi di cattiva qualità, molto meno sicuri, meno performanti e che impediranno gli aggiornamenti futuri del PHP.

A partire da PHP 5.5.0 (giugno 2013) la situazione è migliorata perché le librerie che fanno da client MySQL sono state sganciate dalle API. In altre parole, i programmi vengono scritti indipendentemente da come è stato compilato il PHP. La scelta, perciò, è tutta in fase di installazione.
Se in una rete anche un solo database MySQL ha le password codificate con gli hash a 16 caratteri ( old_passwords=1 ), il PHP degli host che dovranno accedere a quel database – fosse anche occasionalmente e per applicazioni minori – dovrà essere compilato con le libmysqlclient, degradando le performance di tutti i siti ospitati.

Con il PHP 5.5.0, insomma, si possono scrivere programmi migliori e più sicuri. Ma a causa delle vecchie password codificate in hash a 16 caratteri bisogna accettare un degrado delle prestazioni.

Lavorare nel web allo stato del 2003 fa piuttosto effetto. Nel 2003:

  • L’ADSL era nato da poco
  • Non esisteva Gmail
  • Non esisteva Google Maps
  • Non esisteva Facebook
  • Non esisteva Twitter
  • Non esisteva WordPress
  • C’era il PHP 4 e non prevedeva la programmazione a oggetti
  • C’erano Windows XP e Explorer 5.5
  • Mozilla Firefox non era ancora nato, c’era Netscape Navigator
  • AJAX era appena nato
  • Si parlava ancora di pagine web e non di applicazioni

Le tecnologie, il fenomeno sociale e le esigenze degli utenti, insomma, erano l’ombra di quelli attuali.

La soluzione

Non è sicuro che ci sia una soluzione.

Per saperlo, bisogna valutare il tipo di dato della colonna  Password della tabella degli utenti, mysql.user.

La verifica può essere fatta eseguendo, come amministratore:

 

Se la colonna  Password della tabella  mysql.user è CHAR(16), le nuove password NON possono essere utilizzate. Questo potrebbe verificarsi se la tabella degli utenti è stata importata da un vecchio database senza gli adeguati accorgimenti.

Se invece la colonna  Password è  CHAR(41) si può passare alle nuove password senza preoccupazioni.

Nella documentazione si legge infatti:

4.1 and later clients can authenticate using accounts that have short or long hashes

http://dev.mysql.com/doc/refman/5.0/en/password-hashing.html#idm47969038334240

(In realtà anche il caso sfavorevole dovrebbe essere riconvertibile a quello favorevole attraverso lo strumento amministrativo mysql_upgrade. Ma in ambienti di produzione non è una manovra consigliabile.)

Ma veniamo alla soluzione.

Se la colonna Password della tabella  mysql.user è CHAR(41) , la prima operazione da compiere è rimuovere l’opzione old_passwords.
È importante ricordare che  old_passwords non ha effetti sul sistema di autenticazione, ma solo su come vengono codificate le password al momento della creazione o della modifica. Quindi bisogna ancora procedere al rinnovo delle password esistenti, per renderle adeguate alle mysqlnd del PHP.

A questo scopo, senza urgenza, ogni utente (e solo l’utente può farlo, perché bisogna manipolare la password) deve semplicemente reimpostare la password:

 

MySQL, a questo punto, conserva il nuovo hash a 41 caratteri.

L’amministratore del database, quindi, può convocare i propri utenti uno ad uno – rispettandone i tempi di reazione – e richiedere che venga eseguita la manovra (e magari attivare infine secure_auth).

Per conoscere quali utenti abbiano ancora la vecchia codifica è sufficiente guardare quali hash hanno 16 caratteri.

 

Qualora ci siano ancora dei vecchissimi client che hanno bisogno di password codificate con hash a 16 caratteri, gli utilizzatori di quei client dovranno semplicemente evitare la manovra.

Se dovesse essere necessario intervenire su quelle vecchie codifiche, infine, si può ancora modificare una password mantenendo l’hash a 16 caratteri:

 

Ma chi è che usa ancora client del 2002?

 

2 Comments

 Add your comment
  1. Un azienda di cui siamo entrati in possesso della gestione del loro software dopo il fallimento della suddetta.

    Ha i database di tutti progetti con password di tipo 0.

    Purtroppo non posso toccare il database or richiedere agli utenti di reiserire le password, c’è un modo da codice che mi permette di codificare la password appena ricevuta nel modo corretto ? come un funzione decode per i josn ?

  2. @Giuseppe, esistono due modi per recuperare la password di root dei database MySQL. Li trovi descritti in rete e il manuale ufficiale ne parla a http://dev.mysql.com/doc/refman/5.0/en/resetting-permissions.html
    Dovrebbero funzionare indipendentemente da com’erano le vecchie password.

Leave a Comment

Your email address will not be published.

Analisi degli accessi a www.istat.it
×
', 'auto'); ga('require', 'displayfeatures'); ga('set', 'forceSSL', true); ga('send', 'pageview');