Home > Articles > Programming > ASP .NET

ASP.NET 2.0 Security

This chapter outlines some of the new security features included in ASP.NET 2.0. Many of these new features were added to address problems developers were forced to address in previous releases.
This chapter is from the book

Version 1.1 of ASP.NET provided many built-in security services for developers to take advantage of. A common favorite is Forms-based authentication.

Forms-based authentication allows Web developers to easily build applications that require authentication to access secured resources. However, rather than relying on Windows Authentication, Forms-based authentication allows us to author a simple ASP.NET login page. ASP.NET is then configured so that any unauthenticated requests are redirected to the login page (see Figure 6.1).

06fig01.gifFigure 6.1 Forms Authentication

The login page is a simple ASP.NET page used to collect and verify the user's credentials. It is the responsibility of the login page to determine whether the user credentials are valid; typically this information is stored in a database.

Listing 6.1 shows an example of a login page written in ASP.NET 1.1.

Example 6.1. Example Login Page

<%@ Page Language="VB" %>
<%@ import namespace="System.Data" %>
<%@ import namespace="System.Data.SqlClient" %>

<script runat="server">

  Public Sub Login_Click(ByVal sender As Object, ByVal e As EventArgs)

    Dim userId As Integer
    Dim reader As SqlDataReader
    Dim connectionString = _
       ConfigurationSettings.ConnectionStrings("MyConnectionString")
    Dim conn As New SqlConnection(connectionString)
    Dim command As New SqlCommand("dbo.Authenticate", conn)

    ' Set the command type to stored procedure
    command.CommandType = CommandType.StoredProcedure

    ' Set @Username and @Password
    command.Parameters.Add("@Username", _
            SqlDbType.NVarChar, 256).Value = Username.Text
    command.Parameters.Add("@Password", _
            SqlDbType.NVarChar, 256).Value = Password.Text

    ' Open the connection and execute the reader
    conn.Open()
    reader = command.ExecuteReader()

    ' Read the value we're looking for
    reader.Read()

    userId = Integer.Parse(reader("UserId"))

    ' Close connections
    reader.Close()
    conn.Close()

    ' Did we find a user?
    If (userId > 0) Then
        FormsAuthentication.RedirectFromLoginPage(Username.Text, _
                                                  False)
    Else
      Status.Text = "Invalid Credentials: Please try again"

    End If

  End Sub

</script>

<html>
  <body style="FONT-FAMILY: Verdana">

  <H1>Enter your username/password</H1>

  <form id="Form1" runat="server">
    Username: <asp:textbox id="Username" runat="server" />
    <br>
    Password: <asp:textbox id="Password" runat="server" />
    <p>
    <asp:button id="Button1"
                text="Check if Member is Valid"
                onclick="Login_Click" runat="server"/>
  </form>

  <font color="red" size="6">
    <asp:label id="Status" runat="server"/>
  </font>

  </body>
</html>

In this sample the login page raises the Login_Click event, connects to a database, calls a stored procedure to verify the submitted username and password, and then either uses the FormsAuthentication APIs to log the user in or tells the user that the credentials are invalid.

The ASP.NET FormsAuthentication class is used to encrypt the username and store it securely in an HTTP cookie. On subsequent requests this HTTP cookie, with its encrypted contents, is decrypted and the user automatically reauthenticated.

Forms Authentication is definitely a great feature, but what makes it even better is the reduction in the amount of code developers must write. Forms Authentication isn't something new introduced by ASP.NET. Rather, ASP.NET is simply providing an easier way to solve the problem; in the past, most developers would have needed to author this code plus infrastructure on their own.

One of the things you may have noticed about the ASP.NET team members: They are always looking for ways to make things easier. They want developers to solve problems without writing hundreds of lines of code. For ASP.NET 2.0 they're again tackling many security-related problems and providing new features to make things simpler.

In this chapter we're going to examine some of the security infrastructure and controls that have been added in ASP.NET 2.0. We'll start by looking at the new Membership feature. Membership solves the user credential storage problem, a problem most developers solved themselves in ASP.NET 1.0.

Membership

After Microsoft released ASP.NET 1.0, the team members immediately started looking for areas where they could simplify. One area was the management of user credentials, personalization, and user roles. These problems could be solved in ASP.NET 1.1, but the team wanted to make the process better and easier!

The Membership feature of ASP.NET does just that—makes it better and easier. Membership provides secure credential storage with simple, easy-to-use APIs. Rather than requiring you to repeatedly develop infrastructure features for authenticating users, it is now part of the platform. More importantly, it's a pluggable part of the platform through the new provider pattern, allowing you to easily extend the system (e.g., to add support for LDAP or existing corporate user account systems).

Forms Authentication and Membership complement one another. However, they can also act independently; that is, you don't have to use them together. The code sample in Listing 6.2 demonstrates how Membership is used with Forms Authentication.

Example 6.2. Using the Membership API

<script runat="server">

  Public Sub Login_Click(sender As Object, e As EventArgs e)

    ' Is the user valid?
    If (Membership.ValidateUser (Username.Text, Password.Text)) Then

      FormsAuthentication.RedirectFromLoginPage (Username.Text, false)

    Else

      Status.Text = "Invalid Credentials: Please try again"

    End If

  End Sub

</script>

<html>
    <body style="FONT-FAMILY: Verdana">

    <H1>Enter your username/password</H1>

    <form id="Form1" runat="server">
      Username: <asp:textbox id="Username" runat="server" />
      <br>
      Password: <asp:textbox id="Password" runat="server" />
      <p>
      <asp:button id="Button1"
                  text="Check if Member is Valid"
                  onclick="Login_Click" runat="server"/>
    </form>

    <font color="red" size="6">
      <asp:label id="Status" runat="server"/>
    </font>

    </body>
</html>

As you can see, our custom code to validate the credentials is now replaced with a single call to the static Membership.ValidateUser() method. The code is also much cleaner and more readable as a result—and much more concise!

The Membership class contains only static methods. You don't have to create an instance of the class to use its functionality; for example, you don't have to new the Membership class to use it. Behind the scenes the Membership class is forwarding the calls through a configured provider. The provider in turn knows which data source to contact and how to verify the credentials (see Figure 6.2).

06fig02.gifFigure 6.2 The provider model

Providers are a new design pattern introduced with ASP.NET 2.0. Providers are pluggable data abstraction layers used within ASP.NET. All ASP.NET 2.0 features that rely on data storage expose a provider layer. The provider layer allows you to take complete control over how and where data is stored. [1]

Membership Providers

The beauty of the provider model is the abstraction that it affords the developer. Rather than being pigeonholed into a particular data model or fixed API behavior, the provider pattern allows you to determine how and where the actual data storage takes place and the behavior of the API itself.

ASP.NET 2.0 will ship with several providers for Membership (not a complete list):

  • Access

  • SQL Server

  • Active Directory [2]

You can easily author your own provider and plug it in. The provider design pattern allows for one common API that developers can familiarize themselves with, such as Membership, but under the covers you still have control over what exactly is happening. For example, if you had all of your customer information stored in an AS/400, you could write a provider for Membership. Users would call the familiar Membership APIs, but the work would actually be handled by the configured AS/400 provider.

The goal of Membership is to simplify managing and storing user credentials while still allowing you to control your data, but it does much more. Let's dig deeper.

Setting Up Membership

Setting up Membership is easy: It just works. By default all the providers that ship with ASP.NET 2.0 use a Microsoft Access provider and will use the default AspNetDB.mdb file created in the \data\directory of your application. [3]

If the \data\directory of your application does not exist, ASP.NET will attempt to create it. If ASP.NET is unable to create the \data\directory or the AspNetDB.mdb file because of the security policy on the machine, an exception is thrown detailing what needs to be done.

Before we can begin using Membership for its most common task—validating user credentials—we need to have users to validate!

Creating a New User

The Membership API exposes two methods for creating new users:

CreateUser(username As String, password As String)
   
   CreateUser(username As String, password As String,
   email As String)
   

These two APIs are somewhat self-explanatory. We call them to create a user with a username and password, optionally also providing the e-mail address. Both of these methods return a MembershipUser instance, which we'll look at later in this chapter.

Which of these two methods you use is determined by the Membership configuration settings. We can examine the settings in machine.config for the defaults (see Listing 6.3, where the line in bold indicates whether or not an e-mail address must be unique). [4]

Example 6.3. Membership Configuration

<configuration>
  <system.web>

    <membership defaultProvider="AspNetAccessProvider"
                userIsOnlineTimeWindow="15">
      <providers>

        <add
          name="AspNetAccessProvider"
          type="System.Web.Security.AccessMembershipProvider,
                System.Web,
                Version=2.0.3600.0,
                Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
          connectionStringName="AccessFileName"
          enablePasswordRetrieval="false"
          enablePasswordReset="true"
          requiresQuestionAndAnswer="false"
          applicationName="/"
          requiresUniqueEmail="false"
   passwordFormat="Hashed"
   description="Stores and retrieves membership data from
   the local Microsoft Access database file"/>
   
   </providers>
   </membership>
   
   </system.web>
   </configuration>
   

Table 6.1 shows an explanation of the various configuration settings.

Table 6.1. Configuration Elements for the Membership Provider

Attribute

Description

connectionStringName

Names the key within the <connectionStrings /> configuration section where the connection string is stored. The default value for the Access provider is AccessFileName, and for the SQL Server provider it is LocalSqlServer.

enablePasswordRetrieval

Controls whether or not the password can be retrieved through the Membership APIs. When set to false, the password cannot be retrieved from the database. The default value is false.

enablePasswordReset

Allows the password to be reset. For example, although the password may not be retrieved, the APIs will allow for a new random password to be created for the user. The default value is true.

requiresQuestionAndAnswer

Allows the use of a question and answer to retrieve the user's password. Only valid when the passwordFormat setting is not Hashed and enablePasswordRetrieval is true. The default value is false.

applicationName

Indicates the application to which the Membership data store belongs. Multiple applications can share the same Membership data store by specifying the same applicationName value. The default value is /.

requiresUniqueEmail

Requires that a given e-mail address can be used only once. This attribute can be used to prevent users from creating multiple accounts. Note that the uniqueness is constrained to the applicationName the user is created within. The default value is false.

passwordFormat

Controls how the password is stored in the data store. Hashed is the most secure but does not allow password retrieval. Additional valid values include Encrypted and Clear. The default value is Hashed.

description

Describes the provider. This is an optional attribute; when present, tools capable of working with providers can optionally display this description string.

Knowing what the defaults are, we can write a simple page for creating new users (see Listing 6.4).

Example 6.4. Creating Users with the Membership API

<%@ Page Language="VB" %>

<script runat="server">

  Public Sub CreateUser_Click (sender As Object, e As EventArgs)

    Try

      ' Attempt to create the user
      Membership.CreateUser(Username.Text, Password.Text)

      Status.Text = "Created new user: " & Username.Text

    Catch ex As MembershipCreateUserException

      ' Display the status if an exception occurred
      Status.Text = ex.ToString()

    End Try


  End Sub

</script>
<html>
  <head>
  </head>

  <body style="FONT-FAMILY: Verdana">

    <H1>Create a new user</H1>

    <hr />

    <form runat="server">
    Desired username: <asp:TextBox id="Username" runat="server"/>
    <br>
    Password: <asp:TextBox id="Password" runat="server" />
    <p>
    <asp:button Text="Create Member"
                OnClick="CreateUser_Click" runat="server"/>
    </form>

    <font color="red" size="6">
    <asp:Label id="Status" runat="server" />
    </font>

  </body>
</html>

The code in Listing 6.4 calls the Membership.CreateUser() method, which accepts a username and a password. [5] If there is a problem creating the user, a MembershipCreateUserException is thrown. If there are no problems, the new user is created.

Once we've created some users, we can test the Membership.ValidateUser() method.

Validating User Credentials

The primary purpose for Membership is to validate credentials. This is accomplished through the static ValidateUser() method:

ValidateUser(username As String,
   password As String) As Boolean
   

We can use this method, as seen earlier, along with Forms Authentication to validate user credentials. Here is a partial code example:

If (Membership.ValidateUser (Username.Text, Password.Text)) Then

  FormsAuthentication.RedirectFromLoginPage (Username.Text, False)

Else

  Status.Text = "Invalid Credentials: Please try again"

End If

Apart from ValidateUser(), most of the remaining Membership APIs are used for retrieving a user or users.

Retrieving a User

There are a few ways you can retrieve users that have already been created:

GetUser() As MembershipUser

GetUser(userIsOnline As Boolean) As MembershipUser
   
   GetUser(username As String) As MembershipUser
   
   GetUser(username As String,
   userIsOnline As Boolean) As MembershipUser
   

The first two methods that don't have a username parameter will attempt to return the currently logged-on user. The parameter userIsOnline, when set to True, will update a timestamp in the data store indicating the date/time the user was last requested. This timestamp can then be used to calculate the total number of users online. [6] The remaining methods will perform similar operations but on a specified user.

Figure 6.3 shows an example of getting the MembershipUser class for the currently logged-on user.

06fig03.gifFigure 6.3 Getting a user

Listing 6.5 provides the code used for this page.

Example 6.5. Fetching the Logged-on User

<%@ Page Language="VB" %>

<script runat="server">

  Public Sub Page_Load()
    Dim user As MembershipUser

    ' Get the currently logged-on user and
    ' update the user's online timestamp
    user = Membership.GetUser(True)

    UserName.Text = user.Username

  End Sub

</script>

<html>

  <body style="FONT-FAMILY: Verdana">

  <H1>Get User</H1>

  <hr />

     <form runat="server">
       The currently logged-on user is:
       <asp:literal id="UserName" runat="server" />
  </form>

  </body>
</html>

If we want to find a user but don't have the username (e.g., the user forgot his or her username), we can use the GetUserNameByEmail() method:

GetUserNameByEmail(email As String) As String
   

Once we have the username, we can then look up the user with one of the GetUser() methods listed earlier.

We can additionally get multiple users with the following method:

Membership.GetAllUsers() As MembershipUserCollection

Membership.GetAllUsers() simply returns a MembershipUserCollection, which we can use to enumerate users or bind to a server control, such as a Repeater or DataGrid (see Figure 6.4).

06fig04.gifFigure 6.4 Getting all users

Listing 6.6 shows the code.

Example 6.6. Displaying All Users

<%@ Page Language="VB" %>

<script runat="server">

  Public Sub Page_Load()

    Users.DataSource = Membership.GetAllUsers()
    Users.DataBind()

  End Sub

</script>

<html>
  <head>
  </head>

  <body style="FONT-FAMILY: Verdana">

    <H1>Users in Membership Database</H1>

    <hr />

    <asp:repeater id="Users" runat="server">
      <headertemplate>
        <table border="1">
          <tr>
            <td bgcolor="black" style="color:white">
                Username
            </td>

            <td bgcolor="black" style="color:white">
                Email
            </td>

            <td bgcolor="black" style="color:white">
                Is Online
            </td>

            <td bgcolor="black" style="color:white">
                Is Approved
            </td>

            <td bgcolor="black" style="color:white">
                Last Logged In Date
            </td>

            <td bgcolor="black" style="color:white">
                Last Activity Date
            </td>

            <td bgcolor="black" style="color:white">
                Creation Date
            </td>

            <td bgcolor="black" style="color:white">
                Password Changed Date
            </td>

            <td bgcolor="black" style="color:white">
                Password Question
            </td>
          </tr>
      </headertemplate>

      <itemtemplate>
        <tr>
          <td>
            <%# Eval("Username") %>
          </td>

          <td>
            <%# Eval("Email") %>
          </td>

          <td>
            <%# Eval("IsOnline") %>
          </td>

          <td>
            <%# Eval("IsApproved") %>
          </td>

          <td>
            <%# Eval("LastLoginDate") %>
          </td>

          <td>
            <%# Eval("LastActivityDate") %>
          </td>

          <td>
            <%# Eval("CreationDate") %>
          </td>

          <td>
            <%# Eval("LastPasswordChangedDate") %>
          </td>

          <td>
            <%# Eval("PasswordQuestion") %>
          </td>
        </tr>
      </itemtemplate>

      <footertemplate>
        </table>
      </footertemplate>
    </asp:repeater>



  </body>
</html>

The GetAllUsers() method now also supports paging for working with large sets of users. This overloaded version expects pageIndex, pageSize, and totalRecords out parameters, where pageIndex is the location within the result set and pageSize controls the number of records returned per page. For example, a pageIndex of 2 with a pageSize of 25 in a system with 2,000 records would return users 26–50.

Now that we've looked at how to create users and retrieve named users, let's look at the MembershipUser class, which allows us to set and retrieve extended properties for each user.

The MembershipUser Class

The MembershipUser class represents a user stored in the Membership system. It provides the following methods for performing user-specific operations, such as retrieving or resetting a user's password.

GetPassword() As String

GetPassword(answer As String) As String
   
   ChangePassword(oldPassword As String,
   newPassword As String) As Boolean
   
   ChangePasswordQuestionAndAnswer(password As String,
   question As String,
   answer As String) As Boolean
   
   ResetPassword() As String
   
   ResetPassword(answer As String) As String
   

Note that if a question and answer are being used, the overloaded GetPassword(answer As String) method requires the case-insensitive question answer.

The ChangePassword() method allows changes to the user's password, and the ChangePasswordQuestionAndAnswer() method allows changes to the user's password question and answer. The code in Listing 6.7 allows the currently logged-on user to change his or her password question and answer. [7]

Example 6.7. Changing a Password

<%@ Page Language="VB" %>

<script runat="server">

  Public Sub Page_Load()

    If Not Page.IsPostBack Then
      DisplayCurrentQuestion()
    End If

  End Sub

  Public Sub SetQandA_Click(sender As Object, e As EventArgs)

    Dim u As MembershipUser = Membership.GetUser()

    u.ChangePasswordQuestionAndAnswer(CurrentPassword.Text, _
                                      Question.Text, _
                                      Answer.Text)

    Membership.UpdateUser(u)

    DisplayCurrentQuestion()
  End Sub

  Public Sub DisplayCurrentQuestion()

    Status.Text = Membership.GetUser().PasswordQuestion

  End Sub

</script>

<html>
  <body style="FONT-FAMILY: Verdana">

  <H1>Set Question Answer</H1>

  <hr />

  <form id="Form1" runat="server">
    Current Password: <asp:textbox id="CurrentPassword"
                                   runat="server" />
    <p></p>
    Question: <asp:textbox id="Question" runat="server" />
    <p></p>
    Answer:  <asp:textbox id="Answer" runat="server" />
    <p></p>
    <asp:button id="Button1" text="Set Question/Answer"
                onclick="SetQandA_Click" runat="server"/>
  </form>

  <font size="6"> Your new password question is:
  <asp:label id="Status" runat="server"/>
  </font>

</html>

The ResetPassword() methods are similar to the GetPassword() methods. However, rather than retrieving the user's password, they reset and then return a random password for the user.

Keep in mind that the ability to retrieve, change, or reset the user's password is determined by the settings within the configuration.

In addition to password management, the MembershipUser class has some useful properties that provide us some details about how and when the user last logged in, last changed passwords, and so on (see Table 6.2).

Table 6.2. MembershipUser Properties

Property

Description

LastLoginDate

Sets or returns a timestamp for the last time ValidateUser() was called for the current MembershipUser.

CreationDate

Sets or returns a timestamp value set when the user was first created.

LastActivityDate

Sets or returns a timestamp value set when the user authenticates or is retrieved using the overloaded GetUser() method that accepts a userIsOnline parameter.

LastPasswordChangedDate

Sets or returns a timestamp value set when the user last changed his or her password.

Email

Sets or returns the e-mail address, if set, of the user.

IsApproved

Sets or returns a value that indicates whether or not the user is approved. Users whose IsApproved property is set to false cannot log in, even when the specified credentials are valid.

PasswordQuestion

Returns the question used in question/answer retrieval.

Provider

Returns an instance (of type MembershipProvider) of the current provider used to manipulate the data store.

UserName

Returns the username of the current user.

Updating a User's Properties

When changes are made to the user, for example, updating the user's e-mail address, we need to use the Membership.UpdateUser(user AsMembershipUser) method to save the values. [8] For example, in Listing 6.7 earlier, the SetQandA_Click event (repeated here for convenience) shows an example of Membership.UpdateUser():

Public Sub SetQandA_Click(sender As Object, e As EventArgs)

  Dim u As MembershipUser = Membership.GetUser()

  u.ChangePasswordQuestionAndAnswer(CurrentPassword.Text,
                                    Question.Text,
                                    Answer.Text)

  Membership.UpdateUser(u)

  DisplayCurrentQuestion()
End Sub

So far we've learned how to create and update users, but what about removing users from the Membership system?

Deleting a User

Deleting a user from Membership is easy. Membership supports a single method for removing users:

DeleteUser(username As String) As Boolean
   

We simply need to name the user we wish to delete. If the operation is successful, the method returns True. If the delete operation fails, for example, if the user doesn't exist, False is returned.

Listing 6.8 shows a code example that allows us to specify a user to be removed from the Membership system.

Example 6.8. Deleting a User

<%@ Page Language="VB" %>

<script runat="server">

  Public Sub DeleteUser_Click(sender As Object, e As EventArgs)

    If (Membership.DeleteUser(Username.Text)) Then
      Status.Text = Username.Text & " deleted"
    Else
      Status.Text = Username.Text & " not deleted"
    End If

  End Sub

</script>
<html>
  <head>
  </head>

  <body style="FONT-FAMILY: Verdana">


    <H1>Delete a user</H1>

    <hr />

    <form runat="server">
      Username to delete: <asp:TextBox id="Username"
                                       runat="server"/>
      <p>
      <asp:button Text="Delete User"
                  OnClick="DeleteUser_Click" runat="server"/>
    </form>

    <font color="red" size="6">
    <asp:label id="Status" runat="server" />
    </font>

  </body>
</html>

Figure 6.5 shows how this page looks.

06fig05.gifFigure 6.5 Deleting a user

While the Membership APIs definitely simplify day-to-day tasks, there is also an alternative to using programmatic APIs: security server controls. In many cases we can use these server controls and never have to write code that uses the Membership APIs!

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020