ESEMPIO 4 ASP - PROTEZIONE PAGINE WEB AVANZATA

Scenario:

Vogliamo pubblicare un'applicazione ASP che permetta la consultazione di un archivio di documenti riservati.
L'accesso è consentito solo alle persone  autorizzate (che chiameremo operatori) in possesso di un proprio identificativo utente (User-ID) e una propria password di accesso.
Ad ogni operatore viene assegnato un livello di accesso X, R o W. Ad ogni livello corrispondono diverse operazioni consentite, come sotto specificato:
X --> consente di visualizzare l'elenco dei documenti riservati.
R --> Oltre all'indice dei documenti riservati permette di visualizzare il contenuto dei singoli documenti protetti
W --> come R, con la possibilità di modificare il contenuto dei documenti riservati
 

Setup:

Prepariamo i files necessari e apportiamo le modifiche qui descritte:

1) Creiamo il file Accessi.mdb contenente la tabella TBL_UTENTI con i seguenti operatori

I seguenti comandi SQL consentono di creare la tabella TBL_UTENTI:

CREATE TABLE TBL_UTENTI
(
    UserID TEXT(10) CONSTRAINT IdOperatore PRIMARY KEY,
    Password TEXT(16) NOT NULL,
    Nominativo TEXT(16) NOT NULL,
    Livello TEXT(1) NOT NULL
);

INSERT INTO TBL_UTENTI VALUES ('admin', '1234', 'Amministratore', 'W');

INSERT INTO TBL_UTENTI VALUES ('guest', 'guest', 'Ospite', 'X');

INSERT INTO TBL_UTENTI VALUES ('sechim', 'corma', 'Sechi Marco', 'R');

2) Nel file global.asa, registrato nella  document root, inseriamo queste linee di codice:

<script LANGUAGE="VBScript" RUNAT="Server">
 Sub Session_OnStart
     Session("Nominativo") =""
     Session("Livello") = ""
 End Sub
 </script>

Le variabili di sessione appena definite contengono informazioni relative all'operatore che si è autenticato (loggato) nel sistema ed esattamente:
Session("Nominativo"): Il nominativo;

Session("Livello"): il livello di accesso  (X, R o W) associato a quell'operatore. Quando vale la stringa vuota ("") significa che nessun operatore si è autenticato in quella sessione;

2) Creiamo la pagina loginaccessodb.asp che consente all'utente di digitare l'identificativo e la password (operazione di login o autenticazione) e successivamente di visualizzare l'indice dei documenti riservati

LOGINACCESSODB.ASP

a video:

<HTML>
<BODY>
<%
' **********************************************************************
' FASE DI AUTENTICAZIONE E DETERMINAZIONE DEI DIRITTI

' **********************************************************************
if session("Livello")="" then
   user=request.form("USER")
   passwd=request.form("PWD")

   Set objConn = Server.CreateObject("ADODB.Connection")
   FileAccesso=
Server.mapPath ("accessi.mdb")
   objConn.Open("Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " & FileAccesso)

   CmdSQL="SELECT Livello, Nominativo from Tbl_Utenti "
   CmdSQL=CmdSQL+"WHERE UserID='"+user+"' AND Password='"+passwd+"'"
   set objRs = objConn.Execute(CmdSQL)
   if not ObjRS.eof then
      objRs.MoveFirst
      Session("Livello")=objRs("Livello")
      session("Nominativo")=objRs("Nominativo")
   else
      session("Nominativo")=""
      Session("Livello")=""
   end if
   objConn.Close
   Set objConn = Nothing
end if

' **********************************************************************
' VISUALIZZAZIONE IN BASE AI DIRITTI
' **********************************************************************
if session("Livello")<>"" then
%>
<H2>Indice documenti riservati su <%=request.ServerVariables("SERVER_NAME")%></H2>
<h3>User:
<%=session("Nominativo")%> - Livello:<%=session("Livello")%></h3>
<%
   if Session("Livello")="X" then
      response.write("Documento riservato 1<BR>")
      response.write("Documento riservato 2<BR>")
   elseif Session("Livello")="W" OR Session("Livello")="R" then
      response.write("<A HREF=riservata1.asp>Documento riservato 1</A><BR>")
      response.write("<A HREF=riservata2.asp>Documento riservato 2</A><BR>")
   end if
%>

...
<BR><BR><INPUT TYPE=BUTTON VALUE=Logout onclick="window.location='logout.asp'")
<%
else
%>

<FORM ACTION=loginaccessodb.asp METHOD=POST>
Utente:&nbsp;<INPUT TYPE=TEXT NAME=USER><BR>
Password:&nbsp;<INPUT TYPE=PASSWORD NAME=PWD><BR>
<INPUT TYPE=SUBMIT VALUE="Accedi">
</FORM>
<%
end if
%>

</BODY>
</HTML>



  Se session("Livello")="" viene visualizzato:

  Utente:
  Password:
 





  Se session("Livello")="W" viene visualizzato:

Indice documenti riservati su www.brescianet.com

 User: Amministratore - Livello:W

 Documento riservato 1
 Documento riservato 2
 ...

 



  Se session("Livello")="X" viene visualizzato:

Indice documenti riservati su www.brescianet.com

 User: Ospite - Livello:X

 Documento riservato 1
 Documento riservato 2
 ...

 

La prima parte dello script ASP controlla - quando la condizione Session("Livello")="" è vera (nessun utente loggato) - che lo User-ID e la password scritte nel form di autenticazione coincidano con quelle di uno degli operatori registrati in Tbl_utenti ed estrae eventualmente il livello di accesso associato. Il comando SQL registrato nella variabile CmdSQL

CmdSQL="SELECT Nominativo, Livello FROM TBL_UTENTI "
CmdSQL=CmdSQL+"WHERE UserID='" + User + "' AND Password='" + password + "'"

effettua tale ricerca. Quando la ricerca fallisce (quindi l'utente che si sta autenticando non ha diritti di accesso) le variabili di sessione vengono valorizzate con la stringa vuota ("").

Con la condizione Session("Livello")<>"" viene visualizzato l'indice dei documenti riservati, in caso contrario viene proposto il form di autenticazione. In base al livello di accesso l'indice dei documenti presenta i link ai documenti riservati (quando il livello è W o R) oppure no (livello uguale a X)

3) Creiamo ora la pagina logout.asp che consente di disconnettersi dall'applicazione ASP.

<HTML>
<BODY>
<%
   session("Nominativo")=""
   Session("Livello")=""
   response.redirect "loginAccessodb.asp"
%>

</BODY>
</HTML>

L'assegnare a Session("Livello")la stringa vuota ("") equivale a dire che nessun operatore risulta più connesso nella corrente sessione.

4) Inseriamo in ogni documento da proteggere questo segmento di codice ASP:

<HTML>
<BODY>
<%
   ' *****************************************************************
   ' Protezione contro accessi non autorizzati
   ' *****************************************************************
   if NOT (session("Livello")="R" or session("Livello")="W") then
      response.write "<H1>Accesso non autorizzato</H1>"
      response.end
   end if
%>

...

</BODY>
</HTML>

Le pagine riservate dovranno inoltre contenere il codice ASP necessario a gestire i livelli di accesso permettendo la modifica dei dati solo nel caso in cui il livello sia W. La generica pagina riservata1.asp potrebbe essere così implementata:

RISERVATA1.ASP A Video:

<HTML>
<BODY>
<%
if NOT (session("Livello")="R" or session("Livello")="W") then
   response.write "<H1>Accesso non autorizzato</H1>"
   response.end
end if
%>

<INPUT TYPE=BUTTON VALUE=Indice onclick="window.location='loginaccessodb.asp'")>
&nbsp;&nbsp;
<INPUT TYPE=BUTTON VALUE=Logout onclick="window.location='logout.asp'")><BR>
<H2>NOTE RISERVATE SULLO STUDENTE ROSSI MARIO</H2>
<%
if Session("Livello")="R" then
%>

   1) Studia troppo info<BR>
   2) Tralascia Mate<BR>
   3) In classe è uno studente modello<BR>
<%
elseif Session("Livello")="W" then
%>

   <FORM>
   1) <INPUT TYPE=TEXT VALUE="Studia troppo info" SIZE=40><BR>
   2) <INPUT TYPE=TEXT VALUE="Tralascia Mate" SIZE=40><BR>
   3) <INPUT TYPE=TEXT VALUE="In classe è uno studente modello" SIZE=40><BR>
   <INPUT TYPE=BUTTON VALUE=Registra onclick="alert('Salvataggio non operativo!')">
   &nbsp;&nbsp;
   <INPUT TYPE=Reset VALUE=Reset>&nbsp;&nbsp;</FORM>
<%
end if
%>

</BODY>
</HTML>


  Se session("Livello")="" viene visualizzato:

 Accesso non autorizzato


  Se session("Livello")="R" viene visualizzato:
   

 NOTE RISERVATE SULLO
 STUDENTE ROSSI MARIO

 1) Studia troppo info
 2) Tralascia Mate
 3) In classe è uno studente modello
 
  Se session("Livello")="W" viene visualizzato:

  

 NOTE RISERVATE SULLO
 STUDENTE ROSSI MARIO

 1)
 2)
 3)
   

Demo:

Clicca sul link qui a fianco per visualizzare la demo

Approfondimenti:

Per aumentare il livello di sicurezza è possibile aggiungere, in testa ad ogni singola pagina riservata, del codice ASP che registra nella tabella di access LOGACCESSI tutti gli accessi effettuati a quella pagina. In dettaglio registrerà:
a) la data/ora di accesso;
b) il livello di autorizzazione e il nominativo dell'operatore;
c) il browser utilizzato;
d) l'indirizzo IP del computer dell'operatore;
e) il nome della pagina consultata.

Creiamo quindi la tabella LOGACCESSI all'interno del file Accessi.mdb utilizzando questo comando SQL:

CREATE TABLE LOGACCESSI
(
   ID COUNTER CONSTRAINT Id PRIMARY KEY,
   IP TEXT(15) NOT NULL,
   DATAORAACCESSO DATETIME,
   Nominativo TEXT(16),
   Livello TEXT(1),
   Browser TEXT(150) NOT NULL,
   NomePagina TEXT(50) NOT NULL
)
La tabella creata dovrebbe avere una struttura di questo tipo:

Inseriamo in testa ad ogni pagina riservata queste righe di codice

<HTML>
<BODY>
<%
   ' *****************************************************************
   ' Registrazione accesso alla pagina riservata
   ' *****************************************************************
   IPClient=request.ServerVariables("REMOTE_ADDR")
   Browser=request.ServerVariables("HTTP_USER_AGENT")
   NomePagina=request.ServerVariables("SCRIPT_NAME")
   ' --------------------------------------------------------------
   ' Ribalto il mese con il giorno poichè SQL richiede
   ' le date in formato anglosassone
   ' --------------------------------------------------------------
   DataOraAccesso=FormatDateTime(now,0)
   DataOraAccesso=mid(DataOraAccesso,4,2) & "/" & Left(DataOraAccesso,2) & mid(DataOraAccesso,6)

   Set objConn = Server.CreateObject("ADODB.Connection")
   FileAccesso=Server.mapPath ("accessi.mdb")
   objConn.Open("Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " & FileAccesso)
   CmdSQL = "INSERT INTO LogAccessi (IP, Browser, DataOraAccesso, Nominativo, Livello, NomePagina) "
   CmdSQL = CmdSQL + "VALUES ('"+IPClient+"', '"+Browser+"', #" + DataOraAccesso+"#, "
   CmdSQL = CmdSQL + "'"+Session("Nominativo")+"', '" +Session("Livello")+"', '" +NomePagina+"')"
   objConn.Execute(CmdSQL)
   objConn.Close
   Set objConn = Nothing


  
' *****************************************************************
   ' Protezione contro accessi non autorizzati
   ' *****************************************************************
   if NOT (session("Livello")="R" or session("Livello")="W") then
      response.write "<H1>Accesso non autorizzato</H1>"
      response.end
   end if
%>

...

</BODY>
</HTML>

Nella variabile CmdSQL viene inserito un comando SQL di tipo INSERT INTO costruito dinamicamente sulla base dei parametri attuali della connessione.
Il comando SQL eseguito sarà simile al seguente

INSERT INTO LogAccessi
(IP, Browser, DataOraAccesso, Nominativo, Livello, NomePagina)
VALUES ('192.168.1.98',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1)',
#06/02/2006 14.21.01#, 'Sechi Marco', 'R', '/logindb/riservata1.asp')

Si osservi che è stata invertita la posizione del mese e del giorno poichè nei comandi SQL la data va scritta in forma anglosassone (mm/gg/aaaa).
Dal punto di vista operativo, nulla cambia per l'operatore.

E' possibile consultare il contenuto della tabella LogAccessi cliccando su questo link. Di seguito il codice ASP della pagina LogAccessi.asp che realizza tale report.

<HTML>
<BODY>
<STYLE TYPE=text/css>
DIV { font-family : "Courier New"; font-size : 10pt; width: 550px; COLOR: #6495ED; font-weight : bold;}
TH
{
    font-size : 10pt; COLOR: WHITE; background-color : Black; border-style: solid;
    border-width: 1; border-color : Black; border-collapse: collapse; font-family : Arial;
}
TD
{
    font-size : 10pt; border-style: solid; border-width: 1; border-color : Black;
    border-collapse: collapse; font-family : Arial;
}
TD.SMALL { font-size : 8pt;}
TD.CENTRO { text-align : center; font-weight : bold;}
TR.PARI { background-color : ButtonFace; }
</STYLE>
<%
   Set objConn = Server.CreateObject("ADODB.Connection")
   FileAccesso=Server.mapPath ("accessi.mdb")
   objConn.Open("Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " & FileAccesso)
   CmdSQL="SELECT TOP 20 * from LogAccessi ORDER BY DataOraAccesso DESC"
   set objRs = objConn.Execute(CmdSQL)
   if NOT objRS.eof then
      ' *******************************************************************************
      ' Elenco degli ultimi 20 accessi
      ' *******************************************************************************
      response.write "<H1>Ultimi 20 accessi:</H1>"
      response.write "<DIV>"+CmdSQL+"</DIV><BR>"
      response.write "<TABLE BORDER=0 CELLSPACING=0 CELLPADING=6 style='border-collapse: collapse'>"+vbcrlf
      response.write "<TR><TH>IP</TH><TH>Data/ora</TH><TH>Pagina</TH><TH>Nominativo</TH>"
  
   response.write "<TH>Liv.</TH><TH>Browser</TH></TR>"+vbcrlf
      objRs.MoveFirst
      Riga=1
      Do while NOT objRs.EOF
         if riga mod 2 = 0 then
            response.write"<TR CLASS=PARI>"+vbcrlf
         else
            response.write"<TR>"+vbcrlf
         end if
         response.write "<TD>" & objRs("IP") & "</TD>"
         response.write "<TD>" & FormatDateTime(objRs("DataOraAccesso"),0) & "</TD>"
         response.write "<TD>" & objRs("NomePagina") & "</TD>"
         response.write "<TD>" & objRs("Nominativo") & "&nbsp;</TD>"
         response.write "<TD CLASS=CENTRO>" & objRs("Livello") & "&nbsp;</TD>"
         response.write "<TD CLASS=SMALL>" & objRs("Browser") & "</TD><TR>"
         objRs.Movenext
         Riga=Riga+1
      Loop
      response.write"</TABLE><BR>"+vbcrlf

      ' *******************************************************************************
      ' Statistica per pagine
      ' *******************************************************************************
      CmdSQL="SELECT NomePagina, Count(*) AS Nr, Max(DATAORAACCESSO) AS UltimoAccesso, "
     
CmdSQL=CmdSQL+"Min(DATAORAACCESSO) AS PrimoAccesso FROM LOGACCESSI GROUP BY NomePagina"
      set objRs = objConn.Execute(CmdSQL)
      if NOT objRS.eof then
         response.write "<H1>Statistiche per pagina:</H1>"
         response.write("<DIV>"+CmdSQL+"</DIV><BR>")
         response.write "<TABLE BORDER=0 CELLSPACING=0 CELLPADING=6 style='border-collapse: collapse'>"+vbcrlf
         response.write "<TR><TH>Pagina</TH><TH>Nr. accessi</TH><TH>Primo accesso</TH>"
         response.write "<TH>Ultimo accesso</TH></TR>"+vbcrlf
         objRs.MoveFirst
         Do while NOT objRs.EOF
            response.write"<TR CLASS=DISPARI>"+vbcrlf
            response.write "<TD>" & objRs("NomePagina") & "</TD>"
            response.write "<TD CLASS=CENTRO>" & objRs("Nr") & "</TD>"
            response.write "<TD>" & FormatDateTime(objRs("UltimoAccesso"),0) & "</TD>"
            response.write "<TD>" & FormatDateTime(objRs("PrimoAccesso"),0) & "</TD></TR>"
            objRs.Movenext
         Loop
         response.write"</TABLE><BR>"+vbcrlf
      end if

      ' *******************************************************************************
      ' Statistica per user
      ' *******************************************************************************
      CmdSQL="SELECT iif(isnull(Nominativo) or Nominativo='','Non Autorizzati',Nominativo) AS NOMIN, "
      CmdSQL=CmdSQL+"Count(*) AS Nr, Max(DATAORAACCESSO) AS UltimoAccesso, "
     
CmdSQL=CmdSQL+"Min(DATAORAACCESSO) AS PrimoAccesso FROM LOGACCESSI GROUP BY "
      CmdSQL=CmdSQL+"iif(isnull(Nominativo)or Nominativo='','Non Autorizzati',Nominativo) "
      set objRs = objConn.Execute(CmdSQL)
      if NOT objRS.eof then
         response.write "<H1>Statistiche per Utente:</H1>"
         response.write("<DIV>"+CmdSQL+"</DIV><BR>")
         response.write "<TABLE BORDER=0 CELLSPACING=0 CELLPADING=6 style='border-collapse: collapse'>"+vbcrlf
         response.write "<TR><TH>Pagina</TH><TH>Nr. accessi</TH><TH>Primo accesso</TH>"
         response.write "<TH>Ultimo accesso</TH></TR>"+vbcrlf
         objRs.MoveFirst
         Do while NOT objRs.EOF
            response.write"<TR CLASS=DISPARI>"+vbcrlf
            response.write "<TD>" & objRs("Nomin") & "</TD>"
            response.write "<TD CLASS=CENTRO>" & objRs("Nr") & "</TD>"
            response.write "<TD>" & FormatDateTime(objRs("UltimoAccesso"),0) & "</TD>"
            response.write "<TD>" & FormatDateTime(objRs("PrimoAccesso"),0) & "</TD></TR>"
            objRs.Movenext
         Loop
         response.write"</TABLE><BR>"+vbcrlf
      end if

      ' *******************************************************************************
      ' Statistica incrociata pagina\user
      ' *******************************************************************************
      CmdSQL="TRANSFORM IIf(IsNull(Count(*)),0,Count(*)) AS NrAccessi "
      CmdSQL=CmdSQL+"SELECT LOGACCESSI.NomePagina FROM LOGACCESSI "
      CmdSQL=CmdSQL+"GROUP BY LOGACCESSI.NomePagina "
      CmdSQL=CmdSQL+"PIVOT IIf(IsNull([Nominativo]) Or [Nominativo]='','Non Autorizzati',[Nominativo]);"
     
set objRs = objConn.Execute(CmdSQL)
      if NOT objRS.eof then
         response.write "<H1>Statistiche incrociata Pagina\User:</H1>"
         response.write("<DIV>"+CmdSQL+"</DIV><BR>")
         response.write "<TABLE BORDER=0 CELLSPACING=0 CELLPADING=6 style='border-collapse: collapse'>"+vbcrlf
         response.write "<TR><TH>Pagina\User</TH>"+vbcrlf
         for i=1 to ObjRs.fields.count-1
            response.write("<TH>"+objRs(i).name+"</TH>")
         next
         response.write "</TR>"+vbcrlf
         Do while NOT objRs.EOF
            response.write"<TR CLASS=DISPARI>"+vbcrlf
            response.write "<TD>" & objRs("NomePagina") & "</TD>"
            for i=1 to ObjRs.fields.count-1
               response.write "<TD CLASS=CENTRO>" & objRs(i) & "</TD>"
            next
            response.write "</TR>"
            objRs.Movenext
         Loop
         response.write"</TABLE><BR>"+vbcrlf
      end if
   else
      response.write "<H1>Nessuno accesso alle pagine riservate risulta registrato!</H1>"
   end if

   objRs.Close
   Set objRs = Nothing
   objConn.Close
   Set objConn = Nothing
%>

</BODY>
</HTML>