CGI in Perl

Da Hacknowledge.

Perl dispone di numerosi moduli che gli permettono di interagire con i servizi offerti normalmente dai server, ad esempio: SMTP, POP3, FTP, HTTP. È tuttavia possibile effettuare anche una programmazione a lato server, in particolare attraverso le CGI (Common Gateway Interface). Complesse applicazioni sono state sviluppate in CGI e sono disponibili in siti che giornalmente visitiamo, alcuni esempi sono: Amazon e Yahoo.

NOTA: Per avere un idea sui siti che utilizzano cgi, si cerchi in Google:
      "inurl:cgi", "inurl:cgi-bin", "inurl:pl"


Indice

[modifica] CGI (Common Gateway Interface)

Quando si parla di CGI, si intende un protocollo standard con il quale è possibile interfacciare applicazioni ad un webserver. Con altre parole, si può affermare che attraverso le CGI, il webserver identifica l'eseguibile (o script) richiesto dal client e gli fornisce gli argomenti passati dal browser, una volta eseguito il programma, l'output generato viene rispedito al client. Lo schema seguente mostra il modello di interazione tra client e server.

Immagine:Cgi.gif

Vediamo il funzionamento classico delle CGI, in dettaglio.

  1. L'utente effettua una richiesta di una pagina dove andrà ad inserire il suo input attraverso un programma client (es. Firefox, Internet Explorer, Opera,...).
  2. Il webserver elabora la richiesta ed invia al client la pagina richiesta.
  3. A questo punto l'utente completa il form e fa submit inviandolo nuovamente al server.
  4. Il server HTTP riceve la richiesta inviata dal client con i dati e a seconda del sistema crea un nuovo processo o thread che esegue la CGI, ovvero il programma (o script).
  5. Il risultato dell'esecuzione di questa CGI deve dare luogo ad una pagina HTML che il programma (o script) ha inviato sul suo standard output.
  6. Questo output viene intercettato dal webserver che provvede a inviarlo al client.


[modifica] Esempio Login Form

Nella sezione precedente abbiamo avuto una breve infarinatura sul funzionamento teorico, vediamo ora, attraverso un esempio, come funzionano le CGI in pratica. Supponiamo di essere un webmaster che vuole proteggere il proprio pannello di controllo con un login. Il primo passo consiste nel creare un form da cui l'utente possa inserire i propri dati ed autenticarsi.

<html>
<head>
	<title>Login</title>
</head>
<body>
	<h1>Login!</h1>
	<form action="/cgi-bin/login.pl" method="GET">
		Username: <br><input type="text" name="user"><br>
		Password: <br><input type="password" name="pass"><br>
		<input type="submit" value="Login">
	</form>
</body>
</html>

Questa pagina contiene il minimo indispensabile per autenticarsi con username e password.

NOTA: Il method è GET esclusivamente perchè più facile da comprendere. Normalmente i 
      dati sensibili vengono inviati attraverso POST per evitare che rimangano nei 
      log del webserver.

Alla pressione del bottone "Login", sara inviata un HTTP Request, dal vostro browser, identificato dalla seguente URL:

http://www.gnixserver.net/cgi-bin/login.pl?user=gnix&pass=segreta

A questo punto, il server gnixserver.net, lancerà un nuovo processo o thread che esegua lo script login.pl, e passerà a costui, i parametri che ha trovato nell'URL:

user=gnix&pass=segreta

Bisogna precisare che esistono due modi per passare i parametri dal server HTTP alla CGI: o attraverso lo Standard Input della CGI (se la request del client è avvenuta con modalità POST), o memorizzando la stringa dei parametri nella variabile d'ambiente REQUEST_METHOD (se la request è avvenuta con modalità GET). Vediamo ora il contenuto di un possibile login.pl:

#!/usr/bin/perl -w
 
use CGI;
 
# Crea un oggetto CGI
$q = CGI::new();
 
# Legge i parametri (attenzione che non sono filtrati da XSS o Injection vari)
$user = $q->param('user');
$pass = $q->param('pass');
 
# Stampa l'header della pagina HTML
print $q->header();
 
# Stampa il l'head e il title 'Login'
print $q->start_html('Login');
 
# Effettua un semplice confronto e stampa un output
if(($user eq "gnix") && ($pass eq "segreta")) {
  print "<p>Login corretto!</p>";
}
else {
  print "<p>Login errato!</p>";
}
 
# Stampa la fine del body e dell'html
print $q->end_html();

Questo semplice script mi permette di leggere i parametri passati e di confrontarli con due valori scalari per decidere cosa visualizzare su STDOUT. Attraverso l'oggetto CGI a cui si fa riferimento con $q, è possibile accedere ad un vasto repertorio di funzioni che permettono di lavorare in maniera molto semplice con parametri passati, form, richieste e altro ancora (vedi http://cpan.uwinnipeg.ca/dist/CGI.pm).


[modifica] Uno sguardo al modulo CGI

[modifica] Escaping

La libreria CGI di Perl mette anche a disposizione funzioni per l'escaping di stringhe nel caso in cui contengano caratteri speciali. È possibile ad esempio convertire una stringa in formato URL (ad esempio quelle contenenti i cookie o le query string di form GET o POST, ovvero stringhe contenenti solo caratteri alfanumerici e che ad ogni altro tipo di carattere sostituiscono % seguito dal codice ASCII corrispondente) o da formato URL ad ASCII normale rispettivamente con le funzioni escape() e unescape(). Esempio:

use CGI qw/escape unescape/;
 
$str=escape('Qu€sta $stringa contiene caratteri ASCII ~speciali~');
print "$str\n";
 
$str=unescape($str);
print "$str\n";

Allo stesso modo si possono usare escapeHTML() e unescapeHTML() per parsare i tag HTML ed evitare quindi XSS.


[modifica] Variabili di sessione HTTP

Le CGI Perl mettono anche a disposizione funzioni per la gestione delle variabili di sessione HTTP, quelle usate all'interno degli header. È quindi possibile gestire direttamente da qui la query string nel caso di richieste GET, gestire remote addr, remote host, user agent ecc. e anche gestire arbitrariamente gli header HTTP attraverso la funzione http(). Queste cose potrebbero essere fatte in modo abbastanza semplice gestendo per bene le variabili d'ambiente. In ogni caso Perl mette anche a disposizione delle funzioni per farlo senza problemi. Date un'occhiata qui per maggiori informazioni e per l'elenco completo delle funzioni a riguardo messe a disposizione dall'interprete Perl.


[modifica] Cookie

Abbiamo anche una funzione per la gestione di cookie, gestiti dalla funzione CGI::cookie, usata sia per settarli sia per leggerli. Per settare un cookie faremo nel seguente modo:

#!/usr/bin/perl
 
use CGI;
 
$query = new CGI;
$cookie = $query->cookie(-name=>'sessionID',
        		     -value=>'xyzzy',
			     -expires=>'+1h',
			     -path=>'/cgi-bin/database',
			     -domain=>'.capricorn.org',
			     -secure=>1);
print $query->header(-cookie=>$cookie);

e il gioco è fatto. I parametri della funzione sono

  • -name (obbligatorio) - Nome del cookie
  • -value (obbligatorio) - Valore contenuto nel cookie
  • -expires (facoltativo) - Tempo di validità del cookie (se non specificato, il cookie è valido solo per la sessione corrente)
  • -path (facoltativo) - PATH del cookie
  • -domain (facoltativo) - Dominio di validità del cookie
  • -secure (facoltativo) - Se settato a 1, il cookie verrà usato solo in sessioni SSL

Per leggere invece un cookie,

$uid = $query->cookie('UID');
Strumenti personali