ASPNL logo (1 kb)
zaterdag 17 mei 2008




Microsoft MVP

.NET Codewise Community
<< vorige | overzicht | volgende >>

ASP.NET Applicaties Beveiligen met Forms Beveiliging

Door Michiel van Otegem
29 juni 2006

De beveiliging die een operating systeem biedt is voor een webapplicatie vaak te ingewikkeld, onhandig, en overbodig. In de meeste gevallen is een simpele beveiliging op basis van een database, XML- of ander bestand met gebruikersgegevens wel genoeg. ASP.NET biedt voor dit soort applicaties een standaardmechanisme dat gebruik maakt van HTML-formulieren en cookies.

Hoewel dit artikel ASP.NET 1.x betreft, ligt hetzelfde mechanisme ten grondslag aan het Membership mechanisme van ASP.NET 2.0, waardoor dit artikel ook inzicht biedt in hoe het Membership mechanisme werkt wanneer gebruik gemaakt wordt van een database voor het opslaan van logingegevens.

In het vorige artikel in deze serie Applicaties beveiligen met Windows beveiliging (Windows & .NET Juni 2002) heb ik de beveiliging die Windows en Internet Information Server (IIS) bieden voor webapplicaties uitvoerig besproken. Die vorm van beveiliging is veruit het beste als het gaat om de veiligheid. Applicaties die waterdicht afgesloten moeten worden omdat ze bedrijfskritieke gegevens bevatten, zoals bijvoorbeeld een intranet, zijn derhalve aangewezen op deze vorm van beveiliging. Voor applicaties met minder strenge veiligheidseisen is deze vorm van beveiliging echter onhandig. Neem bijvoorbeeld een dating-applicatie. Hierin moet je gebruikers van elkaar onderscheiden en in principe moet de ene gebruiker geen toegang krijgen tot de gegevens van een andere. Er is echter geen sprake van bedrijfskritieke gegevens. Het is dus niet nodig om delen van de applicatie af te schermen voor een gedeelte van de gebruikers. Daar komt bij dat de dating-applicatie zeer waarschijnlijk veel meer gebruikers heeft dan een intranet. Om voor al die gebruikers een Windows gebruikersaccount aan te maken is onwenselijk. Dit is lastig te beheren en bovendien moet je zeker weten dat alle onderdelen van de server waartoe de gebruikers geen toegang mogen hebben goed afgeschermd zijn voor alle gebruikers. Dat is een stuk gemakkelijker als alle gebruikers via hetzelfde Windows gebruikersaccount de webapplicatie gebruiken. Om dat te kunnen bewerkstelligen, moet er een alternatieve manier zijn om gebruikers te kunnen identificeren. In veel gevallen is dit een database of een tekst (XML) bestand met gebruikersgegevens. Een dergelijke aanpak is veel makkelijker te beheren, omdat gebruikers programmatisch toegevoegd, gewijzigd en verwijderd kunnen worden. Met Windows gebruikersaccounts is dat lastiger, omdat voor dergelijke opdrachten administratierechten nodig zijn, en die wil je nu juist niet verlenen aan een webapplicatie vanwege het hoge risico op misbruik. Krijgt iemand toegang tot gebruikersgegevens die opgeslagen zijn in de database, dan is dit natuurlijk vervelend, maar de kraker heeft daarmee nog geen toegang tot de rest van het systeem. Omdat beveiliging die niet gebruik maakt van Windows/IIS geen onderdeel was van ASP en andere technologieën, zijn hiervoor allerlei verschillende oplossingen bedacht. ASP.NET biedt echter een gestructureerde standaardoplossing die makkelijk te gebruiken is: Forms Beveiliging.

Inloggen bij Forms beveiliging gaat via een HTML-formulier (vandaar de naam). Hiermee log je in op een gebruikersaccount dat vastgelegd staat in web.config, het configuratiebestand van ASP.NET. Omdat er geen Windows gebruikersaccount gebruikt wordt, gaat de beveiliging van afzonderlijke mappen op basis van de URL. Dit mechanisme heb ik in mijn vorige artikel reeds besproken, dus wordt hier geen aandacht meer aan besteed. Forms beveiliging zorgt ervoor dat als de gebruiker voor het eerst een beveiligde pagina oproept de gebruiker een loginpagina te zien krijgt. Via deze pagina kan de gebruiker inloggen, waarna de gebruiker teruggestuurd wordt naar de pagina die hij/zij oorspronkelijk heeft opgevraagd. Heeft de ingelogde gebruiker niet voldoende rechten, dan krijgt de gebruiker een pagina te zien die dit vermeld. Dit proces is weergegeven in figuur 1.


Figuur 1, Schematische weergave Forms beveiliging

Het eerste dat je moet doen om Forms beveiliging te gebruiken is web.config aanmaken of aanpassen. In het eerste geval kun je de code uit figuur 2 gebruiken.

<configuration>
 <system.web>
  <authentication mode="Forms">
   <forms name=".ASPXLOGIN"
          loginUrl="login.aspx"
          path="/"
          protection="All"
          timeout="60" />
  </authentication>
 </system.web>
</configuration>
Figuur 2, web.config voor Forms beveiliging

Bestaat web.config al in de applicatie, dan moet je op zoek naar het authentication element en het vervangen door de waarde van het authentication element zoals weergegeven in figuur 2. Als het element niet bestaat, kun je het direct onder system.web plaatsen zoals weergegeven in figuur 2. Het mode attribuut van het authentication element geeft aan dat de applicatie Forms beveiliging dient te gebruiken. Voor Windows beveiliging was de waarde van dit attribuut "Windows". Het forms element bevat vervolgens de instellingen die de Forms beveiliging moet gebruiken. Het name attribuut bevat de naam van de cookie die op de browser geplaatst moet worden om aan te geven dat de gebruiker is ingelogd. Deze cookie wordt gecontroleerd bij elke pagina die opgevraagd wordt. Is de cookie niet aanwezig of heeft deze niet de juiste waarde, dan wordt de gebruiker verwezen naar de login pagina. Dit is de pagina die aangegeven wordt in het loginUrl attribuut. Dit is een virtueel pad naar de login pagina, dus als deze pagina via de browser opgevraagd wordt met http://www.voorbeeld.nl/aspnet/beveiliging/login.aspx, dan moet de waarde van dit attribuut /aspnet/beveiliging/login.aspx zijn. Het path attribuut heeft hier, in tegenstelling tot wat je zou denken, niets mee te maken. Het pad dat je daarin opgeeft bepaalt in welke submap van de applicatie de cookie geldig is. In 99 van de 100 gevallen moet dit gewoon de hoofdmap zijn, zoals in figuur 2. Het protection attribuut bepaalt hoe de gegevens in de cookie beschermd worden tegen misbruik. De standaard waarde is All, waarbij de gegevens zowel versleuteld worden als gecontroleerd op de server. Andere mogelijke waardes voor het protection attribuut zijn None (geen versleuteling, geen controle), Encryption (alleen versleuteling, geen controle), en Validation (alleen controle, geen versleuteling). Tenzij de server zeer zwaar belast wordt is het niet verstandig een andere instelling te gebruiken dan All. De laatste instelling, timeout bepaalt na hoeveel tijd de cookie verloopt. Wacht de gebruiker langer dan het daar opgegeven aantal minuten met het opvragen van een nieuwe pagina, dan moet de gebruiker opnieuw inloggen. Iedere keer dat de gebruiker een nieuwe pagina opvraagt, wordt deze cookie bijgewerkt, zodat de tijd opnieuw gaat lopen.
Figuur 2 zorgt er alleen voor dat de applicatie Forms beveiliging kan gebruiken. Naast die instelling heb je nog een aantal dingen nodig, zoals een bron met gebruikers en wachtwoorden, en een pagina die het inlogproces afhandelt. Verder moet je natuurlijk aangeven voor welke mappen de beveiliging moet gelden, en welke gebruikers wel/geen toegang hebben tot die mappen. In z'n simpelste vorm kun je de gebruikers en wachtwoorden opslaan in web.config. Omdat web.config beveiligd wordt door ASP.NET is deze niet te downloaden, dus is dit minder onveilig dan je zou denken. Bovendien heb je de keuze om wachtwoorden versleuteld met SHA1 of MD5 encryptie op te slaan in web.config. In het onwaarschijnlijke geval dat iemand dan alsnog toegang krijgt tot web.config, zijn de wachtwoorden dusdanig versleuteld dat ze van weinig nut zijn. Als je de gebruikersnamen en wachtwoorden opslaat in web.config, dan ziet het forms element uit figuur 2 eruit als in weergegeven in figuur 3.

<forms name=".ASPXLOGIN"
       loginUrl="login.aspx"
       path="/"
       protection="All"
       timeout="60">
 <credentials passwordFormat="SHA1">
   <user name="michiel"
         password="2EBED033C1EF2CB59723B8AC1CF4FF2846751ECA" />
   <user name="peter"
         password="C4A042B60DC04B84572B00E96EB716C90DE8FE13" />
 </credentials>
</forms>
Figuur 3, web.config met gebruikersnamen en wachtwoorden

In figuur 3 zijn de wachtwoorden versleuteld met SHA1 encryptie. Je kunt ook passwordFormat="Clear" gebruiken en de wachtwoorden in web.config zetten zonder dat ze versleuteld zijn. Dit is echetr niet aan te raden. Om web.config te gebruiken met SHA1 (of MD5) encryptie heb je wel een methode nodig om wachtwoorden te versleutelen. Figuur 4 laat de broncode van een pagina zien waarmee je een met SHA1 of MD5 versleutelde versie van een wachtwoord op kunt vragen. Deze en alle andere voorbeeld code is te downloaden van http://www.aspnl.com/aspnl/nl/artikelen/formssecurity.aspx.

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Web.Security" %>
<script runat="server">
Sub Bereken_Click(src As Object, e As EventArgs)
 Hash.Text = FormsAuthentication.HashPasswordForStoringInConfigFile(Password.Text, _
               Algorithm.SelectedItem.Text)
End Sub
</script>
<html>
<body>
  <form runat="server">
    Password:
    <asp:textbox id="Password" runat="server"/>
    <br>
    <asp:radiobuttonlist id="Algorithm"
                         runat="server"
                         RepeatDirection="Horizontal">
    <asp:listitem text="SHA1" Selected="True"/>
    <asp:listitem text="MD5"/>
    </asp:radiobuttonlist>
    <br>
    <asp:button id="Bereken"
             runat="server"
                text="Bereken"
                onclick="Bereken_Click"/>
    <hr>
    Resultaat:
    <asp:label id="Hash" runat="server"/>
  </form>
</body>
</html>
Figuur 4, Versleutelen van wachtwoorden

Figuur 4 maakt gebruik van de System.Web.Security namespace. Hierin zit alle functionaliteit die te maken heeft met het beveiligen van een webapplicatie. Onderdeel van die namespace is het FormsAuthentication object. De HashPasswordForStoringInConfigFile methode van dit object kun je gebruiken om een wachtwoord te versleutelen, zoals in figuur 4. Om het versleutelde wachtwoord te gebruiken moet je dit in web.config zetten. Dat is over het algemeen nog een handmatige taak, aangezien het onwenselijk is om web.config zeer regelmatig te moeten aanpassen. Het versleutelde wachtwoord wordt in de pagina van figuur 4 weergegeven. Het spreekt daarom voor zich dat de pagina in figuur 4 alleen toegankelijk dient te zijn voor de beheerder(s) van de webapplicatie. In de te downloaden voorbeeldapplicatie staat deze in de admin map, die gebruik maakt van de web.config in figuur 5.

<configuration>
  <system.web>
    <authorization>
      <allow users="michiel" /> 
      <deny users="*" />
    </authorization>
  </system.web>
</configuration>
Figuur 5, web.config voor beheermap

web.config in figuur 5 zorgt er voor dat de map waarin dit staat alleen toegankelijk is voor de gebruiker michiel. Alle andere gebruikers krijgen een bericht te zien dat ze niet voldoende rechten hebben om pagina's in de betreffende map (en submappen daarvan) te bekijken.
Met alle instellingen en de mogelijkheid om gebruikers toe te voegen, rest er nog één ding: het loginscherm. Doordat we hier gebruik maken van een standaard mechanisme, is ook dit betrekkelijk simpel, zoals je kunt zien in figuur 6.

<%@ Page Language="VB"%>
<%@Import Namespace="System.Web.Security"%>
<script runat="server">
Sub DoLogin(src As Object, e As EventArgs)
  If FormsAuthentication.Authenticate(txtLogin.Text, txtPassword.Text) Then
    FormsAuthentication.RedirectFromLoginPage(txtLogin.Text, False)
  Else
    txtMsg.Text = "Login onjuist"
  End If
End Sub
</script>
<html>
<body>
<form runat="server">
  Loginnaam:
  <asp:TextBox id="txtLogin" runat="server" />
  <br>
  Wachtwoord:
  <asp:TextBox id="txtPassword" runat="server"
               TextMode="Password" />
  <br>
  <asp:Button id="btnLogin" runat="server"
              Text="Login" OnClick="DoLogin" />
  <p>
  <asp:Label id="txtMsg" runat="server"
             ForeColor="Red"
             EnableViewState="False" />
</form>
</body>
</html>
Figuur 6, Loginpagina

Ook de loginpagina maakt gebruik van het FormsAuthetication object van de System.Web.Security namespace. De Authenticate methode vergelijkt de gegeven gebruikersnaam en wachtwoord met die zijn opgeslagen in web.config. Zijn de gebruikersnaam en het wachtwoord correct, dan wordt met de RedirectFromLoginPage methode de gebruiker doorverwezen naar de pagina die hij/zij oorspronkelijk heeft opgevraagd. Hierbij wordt de gebruikersnaam meegegeven om te zorgen dat de gebruiker voorlopig niet meer hoeft in te loggen. De tweede parameter van deze methode geeft aan of er gebruik gemaakt kan worden van een zogenaamde Persistent Cookie, een cookie die actief blijft, ook als de gebruiker de browser sluit. In dat geval kan iemand later terug komen zonder opnieuw te moeten inloggen. In dit geval is de meegegeven waarde False, dus wordt een dergelijke cookie niet gebruikt. Wil je dit wel, dan moet de waarde True worden. Een andere oplossing is om de gebruiker de keuze te geven middels een checkbox.

Het standaardmechanisme dat ik hier besproken heb, is aan te passen naar eigen wens. In een applicatie voor veel gebruikers is het bijvoorbeeld onhandig om gebruikers in web.config op te slaan, en kun je beter een XML bestand of een database gebruiken. Je kunt hiervoor de structuur zoals die nu is hetzelfde laten. De gebruikers moeten echter in de database opgeslagen worden en je moet een eigen functie schrijven ter vervanging van Authenticate in figuur 6. De code hiervoor is onderdeel van de eerder genoemde download, maar ik ga er hier niet verder op in. De implementatie van database gestuurde beveiliging in de download maakt het ook mogelijk om rollen te definiëren, vergelijkbaar met Windows gebruikersgroepen. Wanneer dat geïmplementeerd is (wat helaas niet mogelijk is als de gebruikers worden opgeslagen in web.config), kun je web.config uit figuur 5 ook zo aanpassen dat alleen toegang wordt verleend op basis van de groep Beheerders, zoals weergegeven in figuur 7.

<configuration>
  <system.web>
    <authorization>
      <allow roles="Beheerders" /> 
      <deny users="*" />
    </authorization>
  </system.web>
</configuration>
Figuur 7, web.config voor beheermap op basis van rollen

Forms beveiliging is makkelijk en snel toe te passen. Je hoeft je niet te verdiepen in de complexiteit van Windows beveiliging, omdat deze volkomen omzeild wordt. De gebruiker waaronder de ASP.NET pagina's worden uitgevoerd is daarom ook altijd dezelfde: de ASPNET gebruiker. Als je Forms beveiliging eenmaal ingesteld hebt in web.config, kun je verschillende submappen makkelijk anders beveiligen door een web.config bestand in de betreffende map te plaatsen waarin andere gebruikers toegang wordt verleend. Dit is veel makkelijker en handiger dan werken op basis van Windows gebruikersaccounts. Forms beveiliging zal daarom in veel gevallen de voorkeur hebben boven Windows beveiliging.

Dit artikel is eerder verschenen in Windows & .NET Magazine Benelux, september 2002 (huidige naam: NetOpus)

<< vorige | ^ naar boven | overzicht | volgende >>
copyright 2000-2007 ASPNL