Authentifier un visiteur gnump3d avec LAMP

Bonjour,

J’utilise un serveur gnump3d pour le streaming mp3, je vous renvoie d’ailleurs à une présentation succinte du logiciel qui, comme son nom l’indique, est open-source. :stuck_out_tongue:

Comment authentifier la connexion à gnump3d par login/password grâce à LAMP ?
et plus particulièrement ici apache-ssl, puisque c’est le serveur apache que j’utilise.


NB : Je pars du principe que vous avez :

  • les logiciels suivants fonctionnels :
  • gnump3d
  • apache-ssl ( ou apache avec mod-ssl, mais alors vous devrez modifier vous-même en fonction de votre configuration)
  • php (5 ?), mysql (5 ?), bref, le LAMP, configuré et en état de marche.
  • les connaissances suffisantes dans le maniement de LAMP, de mysql, du php.

Les thèmes possibles pour gnump3d sont dans /usr/share/gnump3d/
Le thème par défaut est Tabular, créé par l’auteur de gnump3d, c’est celui ci que j’ai choisi d’utiliser.
Le fichier de configuration de serveur est /etc/gnump3d/gnump3d.conf
Le fichier que l’on va devoir modifer en particulier est l’exécutable, dans lequel le serveur boucle en attente de tentative de connexion, soit :
/usr/bin/gnump3d.

Il faut savoir qu’à chaque tentative de connexion, le serveur lit son fichier de conf, ou se rappelle ce qu’il a lu en démarrant ( à voir ), à la recherche de la directive : allowed_clients = 192.168.1.100 et denied_clients = .
On laisse donc ce mode d’authentification par défaut, au lieu d’opter dans ce fichier pour la reconnaissance par password, et on va s’occuper plus tard de modifier le script perl.
Attention : Faîtes une sauvegarde de /usr/bin/gnump3d avant tout bidouillage de ce fichier … c’est lui le pivot central.
Remarque : Ici, à priori, je n’autorise que mon poste, en local, à acceder au serveur par le port 8888, que j’ai laissé par défaut (gnump3d.conf).

/usr/bin/gnump3d :
Quand gnump3d reçoit la requête d’un navigateur, il fait un test sur l’adresse IP du visiteur [quote]#
# Make sure the user is actually allowed to talk to us
# this works by comparing the client address to those addresses
# given in ‘allowed_clients’, and ‘denied_clients’.
#
if ( &bannedAddress( $connected_address ) )
{ … }[/quote]
en appelant une fonction sub bannedAddress ( $ ) qui prend en paramètre l’ip du client, et qui la compare aux adresses autorisées et bannies de gnump3d.conf. Cette fonction renvoie donc vrai ou faux, vrai pour bannie. C’est ce bloc de code qui est à modifier légèrement, ainsi que la fonction.

Il se produit que si l’adresse est bannie, le serveur, au lieu d’ouvrir la page d’index.html du thème (Tabular), va ouvrir une page d’erreur :
“vous n’êtes pas autorisé … etc …” par appel de ceci :

my $header = &getHTTPHeader( 200, "text/html" ); &sendData( $data, $header ); my $text = &getErrorPage( $ARGUMENTS{'theme'}, $literals->get( "ACCESS_DENIED" ) ); &sendData( $data, $text );
On peut donc :

  • créer une nouvelle variable que j’appelle $loginpath
  • la placer en tête du fichier script (plutot avec les autre variable my $var) déclarées en début de fichier.
  • lui affecter une valeur qui sera, pour faire simple :
    ""
    NB: le fichier html est à la racine de DocumentRoot, mais on aurait pu le placer dans un repertoire caché de celui-ci, ce qui soulève toutefois un léger probleme, le visiteur connecté à la page de login pourrait remonter, en faisant un saut en arrière dans la barre du navigateur, dans l’arborescence d’apache, ce qui n’est pas l’idéal … c’est pourquoi je n’entre pas dans ces détails.
    On peut donc modifier le test ci-dessus en remplacant la variable $text par $loginpath. Ce qui va, à l’ouverture de la page d’erreur théorique, déclencher l’exécution du script javascript et une redirection du visiteur vers le serveur apache et la page de login dédiée.

Voici le contenu du fichier login.html que j’ai utilisé :

[code]

$META gnump3d :: Accueil - Login [/code] [color=darkblue][b]Explications [/b]:[/color] On demande à php de lire un fichier de même niveau (./mes_fonctions.php) contenant entre autre une fonction de connexion à la base de données des utilisateurs autorisées, et une fonction de requête. Je vous invite à utiliser comme moi celui fourni par un bon tutoriel de développez.com : [url=http://pbnaigeon.developpez.com/tutoriel/PHP/conception-site-dynamique/]Exemple de conception d'un site dynamique[/url]. NB : - $user sera le nom de l'utilisateur root ou admin que vous avez désigné comme administrateur de mysql. - $pass ne doit pas rester vide, mettez y le password en clair (oui ennuyeux ...). - l'énoncé de la requête sql est à adapter en fonction des noms du champ et de la base de données chez vous biensur. - les instructions exit; en cas d'erreur d'authentification entrainent la fin d'interprétation du fichier, et donc permettent d'ignorer la dernière instruction javascript que j'y place ... - cette ultime intruction n'est lue que si l'utilisateur est authentifié, elle a pour effet de rediriger l'utilisateur vers gnump3d, en page d'accueil, ce qui va être l'occasion pour le serveur de faire un nouveau test afin de savoir si cet utilisateur (son ip) est autorisé par gnump3d à visiter le site.

On va faire en sorte qu’il le soit, maintenant. C’est plutot simple, plus haut, on a demander à php d’ajouter l’ip du visiteur dans un fichier situé par exemple dans l’arborescence de gnump3d :

$ip = $_SERVER["REMOTE_ADDR"]; exec("echo $ip >> /var/music/logins");
Il faut veiller à ce que php aie les droits suffisants pour écrire dans ce fichier.
Il reste donc à modifier la fonction sub bannedAddress( $ ) dans /usr/bin/gnump3d pour lui demander de rajouter les addresses contenues dans logins à la collection ou tableau d’addresses qu’il va lire pour authentification de l’ip client… Comme ceci, en deux temps :
1/ Lecture du fichier, enregistrement des lignes dans un tableau @lignesopen(TEXT, "</var/music/logins") || die "Erreur survenue: $!"; # Lit le fichier d'authentification. my @lignes = <TEXT>; # recueille les lignes=IP dans un tableau close(TEXT);
2/ Ajout de @lignes au tableau @good (liste des ip allowed) @good = ( @good , @lignes );ceci venant juste aprés que gnump3d aie traité comme il se doit son fichier de conf, soit aprés l’instruction :

my @good = split( /;/, $allow ); my @bad = split( /;/, $deny );

Ainsi, l’ip client tout à l’heure refusée va être maintenant autorisée, et gnump3d ouvre la page d’index.html du thème, laissant accès à la lecture des répertoire de /var/music, pour le plaisir, normalement, du visiteur… :stuck_out_tongue:

Parmis les nombreuses modifications et améliorations qui pourraient être apportées à cette façon de faire, je vois entre autre :

  • l’écriture du mot de pass admin de mysql en clair dans un fichier, qui me chagrine …
  • les défauts de la feuille css de login.html que j’utilise, et qui, bien que trés inspirée de l’originale de Steve Kemp, en font par les modifications apportées, une feuille de piètre conception… je vous demande de m’en excuser, c’était juste pour l’exemple …
  • login.php, plutôt que de se contenter de simples exit, il vaudrait mieux rediriger l’user vers cette page à nouveau vierge, du moins avec un reset des champs à blanc.
  • l’absence de processus d’éffacement du fichier /var/music/logins, si on en voit l’utilité, passé un certain délai.
  • Et quelques autres peut-être, relatifs à la sécurité, mais qui restent à tester, je vous fais confiance pour le dire si c’est le cas, moi je n’en ai pas vraiment conscience …

Voilà … j’espère n’avoir rien oublié … et zou :stuck_out_tongue:

Je ne m’y connais pas trop en php mais je trouve cette ligne pas très rassurante :

En general c’est bon de verifier les user-input et de decoreller avec la requete sql.
Dans mes pages, je fais des verifications à la mano mais il y a des mecanismes automatiques pour faire ca en php.

Et pour le mot de passe stocké dans un fichier, si tu as mis les bons droits dessus, ca me choque pas. Il faut bien qu’il soit stocké quelquepart.

Il y a effectivement peut être moyen de mettre dans le login un truc genre :

' <une fin de clause sql qui fait que la requète rend forcément ce que je vais mettre comme mot de passe>(notes bien le ’ usinagaz).
Les bons sqlistes pourraient confirmer et imaginer une injection pour l’exemple , pour usinagaz ?

ah !? :smiley: un M… en mode furtif :smiley:
Pour ce bout de code , il n’est pas de moi, je n’ai pas les connaissances en plus pour le commenter (developpez.com - tutoriel php). Merci pour les réactions en tout cas. :wink:

Je ne suis pas non plus expert en sql mais c’est vrai que c’est loin d’etre rassurant ce genre de requete.

Je préfèrerais quelques chose dans ce genre la

Le ORDER BY ici ne sert à rien au niveau de la requête en elle même il empeche juste de rajouter du code à la suite lors d’une injection. Et encore, je ne pense pas que ce soit vraiment optimal comme protection mais c’est déjà mieux que la requête précédente.

securityfocus.com/infocus/1864/2

C’est bien a cause du OR 1=1 à la fin de la requete que ca pose problème alors qu’en rajoutant un ORDER BY tu ne peux rien mettre derriere ce qui protege dans un sens.

je vois … mais je saisis pas trés bien; dans l’exemple de Boris (lien), le nom de l’input ne devrait-il pas être ‘username’ et non ‘user’ ?
D’autrepart, dans la requête mise en cause dans “mon” exemple, en quoi est-ce pertinent ? je veux dire que la requête va renvoyer un couple login/passwd, ou échouer non ?
Alors, si 1=1, quel couple login/passwd pourrait bien renvoyer la requête, puis comparer au couple fourni par la méthode post ?
Auncun à mon avis (le login ‘vrai’ ou ‘’ n’existant pas dans la table interrogée) … m’égares-je ? :confused:

Je n’ai pas lu le contexte complet de la requete mais en regle générale lors d’une telle requete c’est suite a un formulaire pour acceder a des données dites “sensibles” et qui donc nécessite un mot de passe et un login. Le fait de rajouter OR 1=1 à la requete permet de bypasser cette sécurité ou suivant le contexte de trouver un mot de passe correspondant à un login. D’une manière ou d’une autre c’est pas bon.

[quote=“usinagaz”]je vois … mais je saisis pas trés bien; dans l’exemple de Boris (lien), le
nom de l’input ne devrait-il pas être ‘username’ et non ‘user’ ?
D’autrepart, dans la requête mise en cause dans “mon” exemple,
en quoi est-ce pertinent ?
je veux dire que la requête va renvoyer un couple login/passwd,
ou échouer non ?
Alors, si 1=1, quel couple login/passwd pourrait
bien renvoyer la requête, puis comparer au couple fourni par la méthode post ?
Auncun à mon avis (le login ‘vrai’ ou ‘’ n’existant pas dans la table interrogée) … m’égares-je ? :confused:[/quote]

$sql = "select pwd from private_members where login='".$_POST['login']."'";
$req = requete_SQL($sql); //or die('Erreur SQL !<br>'.$sql.'<br>'.mysql_error());
$data = mysql_fetch_assoc($req);

if($data['pwd'] != $pass) {
  echo '<p>Mauvais login / password. Merci de recommencer</p>';
 exit;
} 

A y re-reflechir, dans ton cas, je ne pense pas que ce soit exploitable pour dumper tous les pass car si login = “tuc ’ or 1=1” (ou un truc comme ca, il y a des gens qui connaissent mieux que moi les injections, te fais pas de soucis ) alors la requete sql risque de renvoyer tous les mot de passes de ta base. T’es d’accord? select pwd from members where login=‘usine’ or 1=1 renverra toute la base ( 1=1 est tjrs valide!).
Mais ensuite tu verifie en comparant séparémment le pass donc c’est bon; mais j’en suis loin d’etre sûr et je ne laisserai pas une variable pass se remplir potentiellement de tous les mots de passe de la base.
Donc pour l’authentification, je vois pas de moyen de la passer.
Par contre, on peut tres bien mettre
where login=‘usine’ ; delete private_members ;
Et là ben… j’ai peur que t’ai pu de base.
phpbuilder.com/columns/ProPH … part2.php3
phpbuilder.com/columns/ProPH … part3.php3

En gros, il faut plus verifier les entrées utilisateurs, en ne laissant que les caractères autorisés.
Tu fais un filtre pour ne laisser que a->z, A->Z, 0->9 et tant pis pour O’Connor, l’avait qu’à s’appeler comme tout le monde :laughing:

:smiley: okay merci, je comprend mieux maintenant … :bulb: