Security in ASP.NET


Security is vital to any type of distributed programming, and discussions of it are often highly charged with emotion. I will attempt to outline the problems that arise in this area and discuss how ASP.NET provides your Web application with prefabricated functionality that gives you the level of security you need without too much programming effort.

Security is vital to any distributed system.

The security requirements of a Web application are somewhat like those of a city hall. You have large numbers of people coming and going anonymously, accessing public areas such as the tourism office that dispenses maps. Because these areas aren’t sensitive, you don’t want to waste time and annoy users by subjecting them to strip searches, or else you won’t get many customers and the businesses that sponsor the map giveaways will be angry. But other areas of the same city hall, such as the floor containing the mayor’s office, are sensitive. You don’t want to allow anyone in who can’t prove their identity (authentication) and that they have business on the floor (authorization). And you might want to run them through a metal detector to make sure they can’t hurt anybody.

Different areas of an application require different levels of security.

Authentication

The first problem in security is authentication—Who are you, and how do I know you really are that person? Authenticating a user usually takes the form of examining some sort of credential presented by the user, sometimes agreed upon directly between the two parties, such as a PIN or password; sometimes issued by a third party that both trust, such as a driver’s license or passport. If the credentials are satisfactory to the server, the server knows who the user is and can use its internal logic to determine what actions she is allowed to perform. A user who is not authenticated is called an anonymous user. That doesn’t necessarily mean that she can’t have access to anything on the Web site. It means that she can have access only to the features that the designers have chosen to make available to anonymous users—perhaps checking an airline schedule but not redeeming a frequent flyer award.

Securely and definitively identifying a user is called authentication.

Authentication has historically been the most difficult problem in security design. Most application designers don’t want to deal with it because it’s so important but so difficult to get right. You need a full-time team of very smart geeks who do nothing but eat, drink, and sleep security because that’s what the bad guys have who are trying to crack your Web site and weasel free first-class upgrades (or worse). For example, you can’t just send a password over the network, even if it’s encrypted. If the network packet containing an encrypted password doesn’t somehow change unpredictably every time you submit it, a bad guy could record it and play it back. That’s how I broke into the foreign exchange system of a certain bank whose name you would recognize—fortunately with the bank’s permission—under a consulting contract to test their security. They were very proud of their password encryption algorithm, which I never even tried to crack, but it took me only 20 minutes with a packet sniffer to record a user ID/password packet and play it back to enter their server. Too bad I was charging them by the hour. Next time I’ll vacation for a billable week before declaring success. If you’d like more information about the design problems of writing secure applications, I recommend the book Writing Secure Code, Second Edition, by Michael Howard and David LeBlanc (Microsoft Press, 2003). I never even imagined half the ways to crack a system that these guys discuss.

An authentication system is difficult and expensive to build.

Because of the difficulty and importance of authentication, it’s one of the first features that gets built into a (hopefully) secure operating system. ASP.NET supports three different mechanisms for authentication (four if you count “none”). They are shown in Table 3-2.

Fortunately, several different types of authentication come built into ASP.NET

Table 3-2: ASP.NET authentication modes

Name

Description

None

No ASP.NET authentication services are used.

Windows

Standard Windows authentication is used from IIS.

Forms

ASP.NET requires all page request headers to contain a cookie issued by the server. Users attempting to access protected pages without a cookie are redirected to a login page that verifies credentials and issues a cookie.

Passport

Same idea as Forms, except that user ID info is held and cookies are issued by Microsoft’s external Passport authentication service.

You need to think carefully about exactly where in your Web site authentication should take place. As with a city hall, you need to balance security versus ease of use. For example, a financial Web site will require authentication before viewing accounts or moving money, but the site probably wants to make its marketing literature and fund prospectuses available to the anonymous public. It is important to design your site so that areas that require security have it, but you don’t want this security to hamper your unsecure operations. I have a hard time thinking of anything more detrimental to sales than making a user set up and use an authenticated account before allowing him to see a sales pitch, although some sites do just that.

You need to think carefully about which of your site’s resources require authentication for access and which don’t.

Note

Unlike DCOM, which used its own wire format to support packet privacy, none of the authentication schemes available to ASP.NET provide for encryption of the data transmitted from client to server. This problem doesn’t come from ASP.NET itself, but from the common Web transport protocol HTTP. If your Web site provides data that you don’t want on the front page of USA Today, you need to use the Secure Sockets Layer (SSL) transport or provide some other mechanism for encrypting. Typically, you will do this only for the most sensitive operations because it is slower than unsecure transports. For example, an airline Web site will probably use encrypted transport for the credit card purchase page but not for the flight search page.

Windows Authentication

ASP.NET supports what it calls Windows-based authentication, which basically means delegating the authentication process to IIS, the basic Web server infrastructure on which ASP.NET sits. IIS can be configured to pop up a dialog box on the user’s browser and accept a user ID and password. These credentials must match a Windows user account on the domain to which the IIS host belongs. Alternatively, if the client is running Microsoft Internet Explorer 4 or higher on a Windows system and not connecting through a proxy, IIS can be configured to use the NTLM or Kerberos authentication systems built into Windows to automatically negotiate a user ID and password based on the user’s current logged-in session.

Windows authentication works quite well for a Windows-only intranet over which you have full administrative control. For certain classes of installation—say, a large corporation—it’s fantastic. Just turn it on and go. But it’s much less useful on the wide-open Internet, where your server wants to be able to talk to any type of system, (say, a palmtop) using any type of access (say, not Internet Explorer), and where you don’t want to set up a Windows login account for every user.

Windows authentication works well on a Windows- only intranet.

Forms-Based, or Cookie, Authentication

Most designers of real-life Web applications will choose forms-based authentication, otherwise known as cookie authentication. The user initially sets up an account with a user ID and password. Some Web sites, such as most airline sites, allow you to do this over the Web through a page open to anonymous access. Other Web sites, such as most financial services companies, require a signed paper delivered via snail mail.

Forms-based authentication starts with a user ID and password.

When the user first requests a page from a secure Web site, he is directed to a form that asks for his ID and password. The Web server matches these against the values it has on file and allows access if they match. The server then provides the browser with a cookie that represents its successful login. Think of this cookie as the hand stamp you get at a bar when they check your ID and verify that you really are over 21 years old. It contains the user’s identification in an encrypted form. The browser will automatically send this cookie in the request header section of every subsequent page request so that the server knows which authenticated user it comes from. This relay keeps you from having to enter a user ID and password on every form submittal or page request. Figure 3-14 illustrates this process.

The server supplies the browser with a cookie, an admission ticket identifying the authenticated user.

click to expand
Figure 3-14: Forms-based authentication.

When it supplies the cookie, the server specifies whether the cookie is to be thrown away when the browser session ends or should be saved on the user’s hard disk so that he won’t have to log in next time. Financial Web sites often require the former in order to be ultraprotective against unauthorized use that could cost thousands of dollars. The latter, however, is obviously much more convenient for users. Most Web sites whose data isn’t very sensitive, on-line periodicals such as the Wall Street Journal for example, often provide the user with the capability to choose it. A sample persistent cookie is shown in Figure 3-15.

Cookies may be temporary or persistent.

click to expand
Figure 3-15: Persistent cookie created by sample application.

ASP.NET contains good support for forms-based authentication. A sample application is available on this book’s Web site and shown in Figure 3-16. You tell ASP.NET to use forms-based authentication by making an entry in the web.config file as shown in Listing 3-8. The authorization element tells ASP.NET to deny access to any unauthenticated users.

ASP.NET contains good prefabricated support for forms-based authentication.

click to expand
Figure 3-16: Sample application for forms-based authentication.

Listing 3-8: Web.config file for forms-based authentication.

start example
<authentication mode = "Forms" > <forms name="IntroducingMicrosft.NET" loginUrl="loginform.aspx"/> </authentication> <authorization> <deny users="?"/> </authorization> 
end example

This means that ASP.NET will require that any request for a page in that directory or its subdirectories must contain a cookie from the browser saying that you’ve authenticated the user and found him worthy. If the cookie is not present, as it won’t be prior to your first login, ASP.NET directs the user to the page you have specified in the loginUrl attribute. You use this page to provide controls for the user to enter his ID and password. The page’s handler contains whatever logic you need for checking that the user really is who he says he is. The sample code simply accepts a blank user password and rejects any that are nonblank. If the server accepts the incoming user, a simple function call (to System.Web.Security.FormsAuthentication.RedirectFromLoginPage) brings the user back to the page that he was trying to access when the authentication scheme shunted him to the login screen. If you’d like to send him somewhere else instead, you can use the function Response.Redirect. The code is shown in Listing 3-9.

Listing 3-9: Code for forms-based authentication form.

start example
Public Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) ’ Check for legal password (in this case, blank) If TextBox2.Text = "" Then System.Web.Security.FormsAuthentication.RedirectFromLoginPage( _ TextBox1.text, CheckBox1.Checked) ’ Reject a non-blank password. Don’t need to make any system calls, ’ just refrain from making the one that would grant access. Else Label5.Text = "Invalid Credentials: Please try again" End If End Sub
end example

You can also set up ASP.NET to automatically perform forms-based authentication using user IDs and passwords stored in XML configuration files. This approach would probably work well for a small installation. Unfortunately, a demonstration is beyond the scope of this book, at least in this edition.

start sidebar
Tips from the Trenches

Forms authentication is the approach my customers use the most, by far. They report that they often want to change the default behavior described here; for example, redirecting the user to a different form after successfully authenticating him. You’ll find methods for supporting these kinds of activities on the utility object System.Web.Security.FormsAuthentication.

end sidebar

Passport Authentication

The third authentication alternative is Passport-based authentication. The forms-based scheme described in the previous section sounds fine, and it’s a lot easier to write today than it used to be as the result of ASP.NET’s prefabricated support. But it suffers from the fatal problem of unchecked proliferation. Every Web site with anything the least bit sensitive needs some sort of login security. For example, I use five different airline Web sites for booking all the travel I have to do, and because they take credit cards, every one of them requires authentication. It is a colossal pain in the ass to keep track of all the user names and passwords I use on these different sites. On one of them my name is “dplatt”; on another one that ID was taken when I signed up so I’m “daveplatt”. I’ve tried using my e-mail address, which no one else ought to be using and which I can usually remember. This occasionally works, but many sites won’t accept the @ sign and others won’t accept a string that long. For passwords, some use 4-character PINs for identification, others use a password of at least six (or sometimes eight) characters, and one insists that the password contain both letters and numbers. Many sites consider their data to be so sensitive (my frequent flyer record? get a life) that they won’t allow a persistent cookie to remember my login credentials. The only way I can keep track of all my user names and passwords is to write them down and keep them near my computer, where any thief would look for them first. That’s one way Nobel physicist Richard Feynman broke into classified safes and left goofy notes for fun while working on the atomic bomb project at Los Alamos during World War II. (See his memoirs, Surely You’re Joking, Mr. Feynman, for the other two ways. I guess Los Alamos has had this problem for a while.) As a client told me a decade ago, the greatest threat to security isn’t the packet sniffer, it’s the Post-It note.

As Web sites proliferate, so do the user IDs and passwords that a user must remember. This is a growing menace to the security of all data.

Microsoft .NET Passport (http://www.passport.com) is an attempt to provide a universal one-step secure login procedure. It’s very much like the forms-based authentication mechanism described in the preceding section, except that Microsoft’s Passport Web servers handle the storing and verifying of user IDs and passwords. A user can go to the Passport Web site and create a passport, essentially a user ID and password stored on Microsoft’s central server farm. When the user requests a page from a site that uses Passport authentication, that site looks for a Passport cookie in the request. If it doesn’t find one, it redirects the request to Passport’s own site, where the user enters her ID and password and receives a Passport cookie. Subsequent browser requests to any Passport-compliant site will use that cookie until the user logs out. The process is illustrated in Figure 3-17. A user can thus use the same user ID and password pair at any participating site. This scheme could greatly simplify the proliferation problem and make many users’ lives easier, with a net gain in security.

Microsoft Passport is a one-step secure login service.

click to expand
Figure 3-17: Passport authentication.

You would think that such a useful idea would be wildly popular, but Passport hasn’t quite caught on yet outside of Microsoft. According to Passport’s own Web site, only 90 sites support Passport authentication at the time of this writing (February 1, 2003), of which 21 belong to Microsoft and 12 represent various flavors of eBay.

Passport has been slow to catch on outside of Microsoft.

Clearly, Passport hasn’t crossed over to the mainstream yet. Part of the problem might be the cost, currently $10,000 per year. Businesses might also be worried about outsourcing such an important piece of their online software presence. Since it’s not under their control, how can they be sure it won’t crash, or even slow below acceptable limits? How many would fear a repetition of January 23, 2001, when a boneheaded Microsoft technician made an incorrect DNS entry that blocked access to most Microsoft sites, including Passport, for almost a day? (I wonder if that technician had to use Notepad to edit a raw XML file, in which case the problem might have been avoided with a dedicated configuration tool.) And what about a falling out later? How could a Web company tell Microsoft to go to hell if Microsoft holds its login data?

The basic problem hindering the advance of Passport is customers’ willingness (or lack thereof) to allow Microsoft to hold their authentication data. I discussed Passport while teaching a class on .NET in a European country in September 2001. (Before.) I asked if any of the students’ companies had considered using Passport for basic authentication. Students representing three separate banks said that they had looked at it for their customer Web sites, but decided not to use it. The student with the best English explained, the others nodding agreement, that “As banks, the basic commodity we sell is trust. Would you trust your brother to hold your money? No, [he must know my brother] but you trust us [he must NOT know my bank, whom I trust only because I owe them far more money in loans than they owe me in deposits]. We did research and focus groups, and found that an uncomfortable [he wouldn’t quantify it] percentage of our customers would feel that we had betrayed their trust if we let Microsoft hold their authentication data instead of keeping it ourselves. They worry about it getting hacked, and they worry about it being used without their permission. I’m not necessarily saying that they’re correct to worry about this, and I’m not necessarily saying that we’re any better on our own, but like it or not, that IS how our customers told us they feel. So if we don’t want them to think that we’ve done to them the worst thing that a bank can do, betray their trust, we can’t use it, and that’s the end of that.”

Public distrust of Microsoft hinders widespread acceptance of Passport.

Microsoft seems finally to be getting the message. Bill Gates sent a company-wide e-mail on January 15, 2002, announcing that what he called “Trustworthy Computing” was Microsoft’s highest priority. Trustworthy Computing, he wrote, was composed of availability, security, and privacy. “... ensuring .NET is a platform for Trustworthy Computing is more important than any other part of our work. If we don’t do this, people simply won’t be willing— or able—to take advantage of all the other great work we do.” I’ve said for years that Microsoft needed to change priorities; that spending one single developer day, nay, one single developer minute, on a paper clip’s blinking eyes before plugging every possible security hole and fixing every possible crash is to worship false gods. I’m ecstatic (OK, I’m a geek) that they finally seem to be doing it. How far and how quickly Trustworthy Computing (TC?) will go, and how much and how quickly the market will believe it, we’ll just have to wait and see. Because of its late-breaking nature, I’ll discuss this more in my chapter on .NET My Services, available on this book’s Web site. But I see a major turn in the right direction, and I’m glad of it. Now tell those airlines, OK?

Bill Gates has declared “Trustworthy Computing” to be Microsoft’s top priority.

Passport is an interesting idea, and the market will determine its success or failure, as it should. I would not choose it as my sole authentication mechanism today, but I’d give serious thought to offering it as an option side by side with non-Passport alternatives. It will make the lives of some unknown (until you do it) percentage of your users easier, which should bring you more money, especially if your competitors don’t do it. You’ll find that the prefabricated support in ASP.NET makes it quite easy. You set the authentication mode to Passport in the web.config file. You will have to download the Passport SDK, sign a licensing agreement, and then write some simple code that delegates the authentication process to Passport.

ASP.NET includes prefabricated support for Passport authentication.

Authorization

Once the authentication process is complete, we know who the user is or know that the user is anonymous. We now need to decide whether the user should be allowed to see the page he is requesting. This is called authorization. You can perform authorization administratively by restricting access to pages in your ASP.NET application, or you can perform it programmatically at run time.

Once we’ve authenticated the user, we need to check whether the user is authorized to do what he’s trying to do.

ASP.NET contains good support for controlling access to .ASPX pages. You can administratively limit access to pages by making entries in your application’s web.config files, as shown in Listing 3-10.

You can administratively specify which users are allowed to view various pages by making entries in the web.config files for specific pages or directories.

Listing 3-10: Authorization entries in a web.config file.

start example
<!-- Authorization This allows a user named Simba, and any users belonging to the role Doctors, to access pages in this directory (and any subdirectories that don’t override this setting in their own web.config files). --> <authorization> <allow users="Simba" roles="Doctors" /> <deny users="*" /> </authorization> 
end example

The <authorization> section contains <allow> and <deny> elements that respectively allow and deny[3] the specified users and members of the specified roles (groups of users) access to pages in the directories to which the web.config files apply. These elements can also accept a verb attribute (not shown) so that you can allow some users to view the page with a get operation but forbid them to post anything back to the server. Although web.config files apply to an entire directory (and its subdirectories unless overridden lower down), you can administratively restrict access to a single file by using the <location> element (not shown).

ASP.NET applies the administrative access rules in the order in which they appear.

When a user requests a page, ASP.NET applies the rules specified in the web.config file in the order in which they appear until it finds a rule that tells it whether to grant or deny the requesting user access to the requested page. If ASP.NET can’t tell from the entries made in that file, it will look in the web.config file in that directory’s parent and so on until it reaches the master ASP.NET machine.config file discussed previously. That file, by default, grants access to all requests. So if you don’t want people to see a certain file, you’ll have to explicitly put in a <deny> element. In the example shown in Listing 3-9, ASP.NET will first apply the <allow> element. If the user is named “Simba” or is a member of a role named “Doctors,” access is granted and the checking process ends. If neither of these tests is true, ASP.NET applies the next rule, which says to deny access to everybody (the * character). ASP.NET will fail the request, and the checking process will end. In this way, only Doctors and Simba can view the pages of this subdirectory. Note that when using Windows authentication on a domain, you must prepend the domain name onto the role or user name in order for ASP.NET to recognize it, as shown in Listing 3-11.

Listing 3-11: Web.config file showing authorization entries for domain users using Windows authentication.

start example
<!-- Authorization This does the same thing as the previous example, except user ID and role names are prefixed with the domain name so as to work correctly with Windows authentication on a domain. --> <authorization> <allow users="REDHOOKESB0\Simba"/> <allow roles="REDHOOKESB0\Doctors"/> <deny users="*" /> </authorization> 
end example

Since it is likely that our Web site will be used by many anonymous users—those who have not been authenticated—we need a way of specifying what they are allowed to do. The question mark character (?) denotes anonymous users. You use it exactly like any other name or the * character. You can see an example in Listing 3-8, the web.config file used for forms-based authentication. It says that unauthenticated users aren’t allowed to view pages in that directory, thereby forcing them to the login form to become authenticated.

The “?” character allows you to set permissions for unauthenticated users.

ASP.NET allows you to authorize either individual users or entire roles. Most real-life installations perform little or no authorization on an individual user basis; it’s almost always done on a group basis. For example, a hospital prescription application might allow physician’s assistants to prescribe Tylenol, but only licensed doctors to prescribe controlled narcotics. An administrator will set permissions for each role, and add individual users to or remove them from role membership as required.

Most real-life authorization works with roles, which are groups of users.

When you use Windows authentication, ASP.NET automatically recognizes a role as any standard Windows user group set up by the administrator. Every user assigned to that group is a member of the role. You don’t have to program anything, recognition just automatically happens. When you use forms or Passport authentication, however, the definition of a role becomes much more difficult. ASP.NET doesn’t know how your user data is stored or what constitutes role membership in your application. You therefore have to write your own code and plug it into the ASP.NET environment to tell it which role(s) a user belongs to when it asks.

ASP.NET automatically determines role membership when you use Windows authentication.

I’ve written a sample program that does this, which you can download from the book’s Web site. The application file Global.asax contains handlers for application-level events. I’ve added code to the handler for the AuthenticateRequest event. Somewhat confusingly named, this event gets called at the beginning of each page request when ASP.NET has already discovered the user’s identity and authenticated it by whatever means you have told it to use. This is your code’s chance to make any changes, and where you have to place the code that tells ASP.NET the roles to which a user belongs. The code is shown in Listing 3-12. We check to see if the user has been authenticated by ASP.NET. If so, we create a new object of type GenericPrincipal, which contains the user’s ID that we’ve been given as well as the roles to which we have decided the user belongs, and set it into ASP.NET.

Listing 3-12: Global.asax.vb code to set role membership on a user’s page request.

start example
Sub Application_AuthenticateRequest(ByVal sender As Object, _ ByVal e As EventArgs) ’ If ASP.NET has figured out who the user is If (Not HttpContext.Current.User Is Nothing) Then ’ If the user has been authenticated by means of forms, ’ and thus contains the admission ticket in a cookie If (TypeOf (HttpContext.Current.User.Identity) _ Is System.Web.Security.FormsIdentity) Then ’ Fetch the object giving the identity of the user Dim id As System.Web.Security.FormsIdentity id = HttpContext.Current.User.Identity ’ Fetch the authentication ticket from this identity object Dim ticket As System.Web.Security.FormsAuthenticationTicket ticket = id.Ticket ’ Create a new object identifying the user. Pass the role ’ strings that we placed in the UserData section of the ’ ticket back in the logon form where we issued it. Dim NewPrincipal As New _ System.Security.Principal.GenericPrincipal( _ id, New String() {ticket.UserData}) ’ Place the new principal object, carrying the roles, into ’ the context to identify the user in subsequent processing ’ of this request. HttpContext.Current.User = NewPrincipal End If End If End Sub
end example

How do we know at this juncture what roles this user belongs to? I could certainly do my own lookup from within the event handler, based on the user ID I’ve been given. But this could involve an expensive database lookup and possibly a network round-trip happening every time a page request comes in, so we’d like a faster way. The sample program accomplishes this by placing the role strings in the cookie itself when it’s first issued, at login time. The code is shown in Listing 3-13. The function MyOwnGetRole looks up user names and comes back with a role string. I’ve hardwired users named Seuss and Kevorkian to members of the role Doctors, and users named Ratched and Houlihan to members of the role Nurses. In order to store this information in the cookie, I have to manually create my admission ticket, placing the role string into an element called UserData that exists for this purpose. The sample code demonstrates the degree of control that I have over the admission ticket cookie, setting its persistence and expiration time. As I described previously, my AuthenticateRequest event code reads the user data from the cookie, thereby providing me the list of roles to which my user belongs. Since every forms authentication program that wants to use role-based security needs to write this code, I wish Microsoft had provided a prefabricated implementation of it. Maybe in the next version.

Listing 3-13: Code to place role membership in authentication cookie for later use.

start example
Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click If (TextBox2.Text = "") Then ’ Create new ticket Dim ticket As New System.Web.Security.FormsAuthenticationTicket( _ 1, TextBox1.Text, Now, Now.AddYears(10), True, _ MyOwnGetRole(TextBox1.Text)) ’ Get the encrypted representation suitable for placing ’ in an HTTP cookie Dim cookieStr As String = _ System.Web.Security.FormsAuthentication.Encrypt(ticket) ’ Place ticket in cookie Dim cookie As New _ HttpCookie( _ System.Web.Security.FormsAuthentication.FormsCookieName, _ cookieStr) Response.Cookies.Add(cookie) ’ redirect to the URL user asked for Dim returnURL As String = Request("ReturnURL") Response.Redirect(returnURL, False) Else Label4.Text = "Invalid credentials, try again" End If End Sub 
end example

Administratively restricting access on a per-page basis is fine, but sometimes your application requires finer granularity. For example, several classes of user might need access to a prescription form page. Suppose that members of the role Doctors can prescribe morphine, but members of the role Nurses can only prescribe aspirin. You could provide two separate pages, administratively restricting access to the morphine page to doctors, but this would require constant page redesign as drugs change their prescription status. It would be much easier to check in the middle tier. Your page code can find out who a user is by accessing the member variable Page.User. This object contains a method called IsInRole, which you can call to see if the currently authenticated user is a member of the specified role. The page is shown in Figure 3-18, and the code in Listing 3-14. If you’d like finer granularity, you can access the object Page.User.Identity, which contains the user’s name.

click to expand
Figure 3-18: Sample application for forms role authentication.

Listing 3-14: Code to discover the role a user belongs to.

start example
Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click ’ User wants to prescribe aspirin. Our business logic allows this for ’ the roles Doctors and Nurses. Since these are the only two roles ’ allowed to see this page, the prescription is automatically approved If (RadioButton1.Checked) Then Label3.Text = "Doctors and Nurses can both prescribe " & _  "aspirin. Prescription approved." Else ’ User clicked button to prescribe morphine. Doctors are allowed ’ to do this, but Nurses are not. Check the role of the user. ’ Approve prescription if user is a Doctor, fail if it’s a Nurse. If User.IsInRole("Doctors") Then Label3.Text = "Because you are a member of the role " & _  "‘Doctors’, your prescription is approved" Else Label3.ForeColor = Color.Red Label3.Text = "Nurses may not prescribe morphine. " & _  "You are under arrest." End If End If End Sub
end example

Identity

Your Web pages usually represent the middle tier of a three-tier system, mediating access to a database behind it (the data tier). The middle tier performs business logic, such as determining whether the user attempting to prescribe morphine is a licensed doctor. If this business logic is successful, the middle tier will communicate with the data tier to subtract morphine from the pharmacy inventory and to add another item to the patient’s billing statement. If not, the middle tier will probably generate a fascinating game to keep the user occupied while it calls the police.

Your Web site is usually the middle tier of a three- tier system, mediating access to a data tier.

The back-end data tier almost certainly has its own security mechanisms. All commercial databases allow administrators to set access permissions of various granularity, specifying which users are allowed access to various databases and tables and which are not. Even the NTFS file system allows an administrator to specify which users or groups of users are allowed to perform which operations on which files and directories. The operation of these back ends depends critically on what the data tier considers to be the identity of the user making the request for services.

The security identity of the Web server process is important.

One security mechanism, and probably the one that you’ll wind up using, is called the trusted user model. In this model, the server process runs with a particular identity, say, PharmacyApp, known as the trusted user. The data tier is configured to allow this user to do anything in the database that it might need to in order to get its work done. For example, the trusted user identity used for the pharmacy application will have permission to make entries in the pharmacy inventory tables and the patient billing tables but probably not the patient census tables or the employee payroll records. The data tier trusts the middle tier server to have done all the authorization checking that needs to happen—for example, to have checked that the doctor’s license is current—so the data tier doesn’t perform a second authorization. You trust your spouse to go through your wallet, so you don’t bother asking what the money is for. This relationship is shown in Figure 3-19. You specify the identity of your server process via the <identity> element in your application’s web.config file, as shown in Listing 3-15.

The data tier usually trusts the middle tier to perform authorization.

click to expand
Figure 3-19: Trusted user model of authorization.

Listing 3-15: Web.config file specifying server process identity.

start example
<identity impersonate="false" userName="MyDomain\MyUsername password="MyPassword" />
end example

Not every database installation is comfortable with this approach. Many databases were designed and database administrators trained before three- tier programming became popular. Particularly with legacy systems, it often happens that the database layer contains security checks or audit trails that depend on the actual database entry being made under the network identity of the base client.

Sometimes the trusted user model doesn’t fit.

In this case, if you’re using Windows authentication, you can fall back on the older impersonation-delegation model, as used by original ASP. In this model, the .ASPX page code takes on the identity of (“impersonates”) the authenticated user (or uses a special identity designated for anonymous users). The page code then attempts to access the data-tier resource, and the resource itself, say, SQL Server, performs the authorization, checking to see whether the user is allowed access. This case is shown in Figure 3-20.

In this case, the Web server can impersonate the client, if you’re using Windows authentication.

click to expand
Figure 3-20: Impersonation/delegation model of authorization.

While this approach may sound attractive, it is expensive in terms of performance. It requires two authentications instead of one: the first when ASP.NET authenticates the user prior to impersonating him, and the second when the database authenticates the server object’s current impersonating identity. Furthermore, when authorization rejects a user, it does so rather late in the process. You’ve already gone down three tiers instead of two and made two network hops instead of one. It’s better that you notice that you forgot your wallet when you arrive at the supermarket instead of after you’ve shopped and waited in the checkout line. It’s better still to notice it when you first get in your car.

The impersonation-delegation model is expensive in terms of performance.

The Web server impersonates a client in one of two ways. Original ASP automatically impersonated the client every time a request was made. ASP.NET does not do this by default, but you can turn on this functionality in the web.config file by setting the impersonation attribute shown in Listing 3-16 to True. Alternatively, you can impersonate the client programmatically by calling the function System.Security.Principal.WindowsIdentity.GetCurrent().Impersonate.

A Web server can impersonate a client programmatically, if using Windows authentication.

Listing 3-16: Web.config setting for automatic impersonation.

start example
<identity> <impersonation enable="true" /> </identity>
end example

[3]Well, duh!




Introducing Microsoft. NET
Introducing Microsoft .NET (Pro-Developer)
ISBN: 0735619182
EAN: 2147483647
Year: 2003
Pages: 110

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net