In the previous
chapter, you learned how to use the Login controls to create an entire
user registration system. This chapter looks under the covers and
examines the security frameworks on which the Login controls are built.
The ASP.NET Framework includes four frameworks related to security:
- ASP.NET Authentication—Enables you to identify users.
- ASP.NET Authorization—Enables you to authorize users to request particular resources.
- ASP.NET Membership—Enables you to represent users and modify their properties.
- Role Manager—Enables you to represent user roles and modify their properties.
Configuring Authentication
Authentication refers to the process of identifying who you are. The ASP.NET Framework supports three types of authentication:
- Windows Authentication
- NET Passport Authentication
- Forms Authentication
A particular
application can have only one type of authentication enabled. You can’t,
for example, enable both Windows and Forms authentication at the same
time. Windows authentication is enabled by default. When Windows
authentication is enabled, users are identified by their Microsoft
Windows account names. Roles correspond to Microsoft Windows groups.
Windows
authentication delegates the responsibility of identifying users to
Internet Information Server. Internet Information Server can be
configured to use Basic, Integrated Windows, or Digest authentication.
.NET
Passport authentication is the same type of authentication used at
Microsoft websites such as MSN and Hotmail. If you want to enable users
to log in to your application by using their existing Hotmail usernames
and passwords, then you can enable .NET Passport authentication.
You must
download and install the Microsoft .NET Passport SDK, register with
Microsoft, and pay Microsoft a fee before you can use .NET Passport
authentication. For more information, see the MSDN website
(msdn.microsoft.com). The final type of authentication is Forms
authentication. When Forms authentication is enabled, users are
typically identified by a cookie (but see the next section). When a user
is authenticated, an encrypted cookie is added to the user’s browser.
As the user moves from page to page, the user is identified by the
cookie.
When Forms
authentication is enabled, user and role information is stored in a
custom data store. You can store user information anywhere that you
want. For example, you can store usernames and passwords in a database,
an XML file, or even a plain text file. In ASP.NET 1.x, after enabling
Forms authentication, you had to write all the code for storing and
retrieving user information. When building an ASP.NET 3.5 application,
on the other hand, you can let ASP.NET Membership do all this work for
you. ASP.NET Membership can handle all the details of storing and
retrieving user and role information. You enable a particular type of
authentication for an application in an application’s root web
configuration file. The file in Listing enables Forms authentication.
<configuration>
<system.web>
<authentication mode=”Forms” />
</system.web>
</configuration>
In Listing,
the authentication element’s mode attribute is set to the value Forms.
The possible values for the mode attribute are None, Windows, Forms, and
Passport. Windows, Forms, and Passport authentication are implemented
with HTTP Modules. If you need to implement a custom authentication
scheme, then you can create a custom HTTP Module.
If you
prefer, you can enable a particular type of authentication by using the
Web Site Administration Tool. This tool provides you with a form
interface for modifying the web configuration file. You can open the Web
Site Administration Tool by selecting the menu option Website, ASP.NET
Configuration.
Configuring Forms Authentication
Several configuration options are specific to Forms authentication:
- cookieless—Enables you to use Forms authentication even when a browser does not support cookies. Possible values are UseCookies, UseUri, AutoDetect, and UseDeviceProfile. The default value is UseDeviceProfile.
- defaultUrl—Enables you to specify the page to which a user is redirected after being authenticated. The default value is Default.aspx.
- domain—Enables you to specify the domain associated with the authentication cookie. The default value is an empty string.
- enableCrossAppRedirects—Enables you to authenticate users across applications by passing an authentication ticket in a query string. The default value is false.
- loginUrl—Enables you to specify the path to the Login page. The default value is Login.aspx.
- name—Enables you to specify the name of the authentication cookie. The default value is .ASPXAUTH.
- path—Enables you to specify the path associated with the authentication cookie. The default value is /.
- protection—Enables you to specify how the authentication cookie is encrypted. Possible values are All, Encryption, None, and Validation. The default value is All.
- requiresSSL—Enables you to require a SSL (Secure Sockets Layer) connection when transmitting the authentication cookie. The default value is false.
- slidingExpiration—Enables you to prevent the authentication cookie from expiring as long as a user continues to make requests within an interval of time. Possible values are True and False. The default value is True.
- timeout—Enables you to specify the amount of time in minutes before the authentication cookie expires. The default value is 30.
Several of these configuration settings are related to the authentication cookie. Several
of these options require additional explanation. In the following
sections, you learn how to enable cookieless authentication, modify the
cookie expiration policy, and enable authentication across applications.
Using
Cookieless Forms Authentication Normally, Forms authentication uses a
cookie to identify a user. However, Forms authentication also supports a
feature named cookieless authentication. When cookieless authentication
is enabled, a user can be identified without a browser cookie.
By taking
advantage of cookieless authentication, you can use Forms Authentication
and ASP.NET Membership to authenticate users even when someone is using
a browser that does not support cookies or a browser with cookies
disabled. When cookieless authentication is enabled, a user can be
identified by a unique token added to a page’s URL. If a user uses
relative URLs to link from one page to another, then the token is passed
from page to page automatically and the user can be identified across
multiple page requests.
When you
request a page that requires authentication and cookieless
authentication is enabled, the URL in the browser address bar looks like
this:
http://localhost:2500/Original/(F(WfAnevWxFyuN4SpenRclAEh_lY6OKWVllOKdQkRk
tOqV7cfcrgUJ2NKxNhH9dTA7fgzZ-cZwyr4ojyU6EnarC-bbf8g4sl6m4k5kk6Nmcsg1))
/SecretFiles/Secret2.aspx
That long,
ugly code in the URL is the user’s encoded authentication ticket. You
configure cookieless authentication by assigning a value to the
cookieless attribute of the forms element in the web configuration file.
The cookieless attribute accepts any of the following four values:
- UseCookies—Always use an authentication cookie.
- UseUri—Never use an authentication cookie.
- AutoDetect—Automatically detect when to use an authentication cookie.
- UseDeviceProfile—Use the device profile to determine when to use an authentication cookie.
The default value
is UseDeviceProfile. By default, the ASP.NET Framework issues a cookie
only when a particular type of device supports cookies. The ASP.NET
Framework maintains a database of device capabilities in a set of files
contained in the following folder:
\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers
By default,
the ASP.NET Framework never uses cookieless authentication with a
browser such as Microsoft Internet Explorer. According to the device
profile for Internet Explorer, Internet Explorer supports cookies, so
cookieless authentication is not used. The Framework doesn’t use
cookieless authentication even when cookies are disabled in a browser.
If you want the ASP.NET Framework to automatically detect whether a
browser supports cookies, then you need to set the cookieless attribute
to the value AutoDetect. When AutoDetect is enabled, the ASP.NET
Framework checks whether a browser sends an HTTP COOKIE header. If the
COOKIE header is present, then an authentication cookie is assigned to
the browser. Otherwise, the ASP.NET Framework uses cookieless
authentication.
Using Sliding Expiration with Forms Authentication
By
default, Forms authentication uses a sliding expiration policy. As long
as a user lets no more than 30 minutes pass without requesting a page,
the user continues to be authenticated. However, if the user does not
request a page for 30 minutes, then the user is logged out
automatically. If you have strict security requirements, you can use an
absolute expiration policy rather than a sliding expiration policy. In
other words, you can force a user to log in again after a particular
interval of time. The web configuration file in Listing forces a user to
log in again every minute.
<configuration>
<system.web>
<authentication mode=”Forms”>
<forms slidingExpiration=”false” timeout=”1” />
</authentication>
</system.web>
</configuration>
Using Forms Authentication Across Applications
By
default, Forms authentication is application relative. In other words,
if you log in to one application, you aren’t logged in to any other
application—even when the other application is located on the same web
server. This creates problems in two situations. First, you don’t want
to require the employees of
your
company to log in multiple times as they move between different
applications hosted by your company. An employee should be able to log
in once and use any application provided by your company automatically.
Second, if you are hosting a web farm, you don’t want to force a user to
log in whenever a request is served by a different web server. From the
perspective of a user, a web farm should seem just like a single
server.
By default,
the Forms authentication cookie is encrypted and signed. Furthermore,
by default, each application generates a unique decryption and
validation key. Therefore, by default, you can’t share the same
authentication cookie across applications. You specify encryption and
validation options with the machineKey element in the web configuration
file. Here are the default settings for this element:
<machineKey decryption=”Auto” validation=”SHA1” decryptionKey=”AutoGenerate,IsolateApps”
validationKey=”AutoGenerate,IsolateApps” />
The
decryption attribute specifies the algorithm used to encrypt and decrypt
the forms authentication cookie. Possible values are Auto, AES (the
government standard encryption algorithm), and 3DES (Triple DES). By
default, the decryption attribute is set to Auto, which causes the
ASP.NET Framework to select the encryption algorithm based on the
capabilities of the web server.
The
validation attribute specifies the hash or encryption algorithm used
when an authentication cookie is signed. Possible values are AES, MD5,
SHA1, and TripleDES. The decryptionKey attribute represents the key used
to encrypt and decrypt the authentication cookie. The validationKey
represents the key used when the authentication cookie is signed. By
default, both attributes are set to the value AutoGenerate, which causes
the ASP.NET Framework to generate a random key and store it in the LSA
(your web server’s Local Security Authority).
Notice that
both the decryptionKey and validationKey attributes include an
IsolateApps modifier. When the IsolateApps modifier is present, a unique
key is created for each application on the same web server.
If
you want to share the same authentication cookie across every
application hosted on the same web server, then you can override the
default machineKey element in the machine root web configuration file
and remove the IsolateApps attribute from both the decryptionKey and
validationKey attributes. You can add the following machineKey element
anywhere within the system.web section in the web configuration file:
<machineKey decryption=”Auto” validation=”SHA1” decryptionKey=”AutoGenerate”
validationKey=”AutoGenerate” />
The root web configuration file is located at the following path:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\Web.Config
Using Forms Authentication Across Domains
In
the previous section, you learned how to share the same authentication
cookie across applications located on the same server or a different
server. But how do you share the same authentication cookie across
domains? A browser cookie is always domain relative. For example, the
Amazon website cannot
read
cookies set by the Barnes and Noble website, which is a good thing.
However, you might discover that you need to share authentication
information across websites with different domains. You can work around
this problem by passing an authentication ticket in a query string
parameter rather than in a cookie. There is nothing to prevent you from
passing query strings between domains. To enable this scenario, you must
configure your applications to accept authentication tickets passed in a
query string. The web configuration file in Listing includes an
enableCrossAppRedirects attribute that enables sharing authentication
tickets across domains.
<configuration>
<system.web>
<authentication mode=”Forms”>
<forms enableCrossAppRedirects=”true” />
</authentication>
<machineKey
decryption=”AES”
validation=”SHA1”
decryptionKey=”306C1FA852AB3B0115150DD8BA30821CDFD125538A0C606
➥DACA53DBB3C3E0AD2”
Configuring Authentication
validationKey=”61A8E04A146AFFAB81B6AD19654F99EA7370807F18F5002725DAB98B
➥8EFD19C711337E26948E26D1D174B159973EA0BE8CC9CAA6AAF513BF84E44B2247792265” />
</system.web>
</configuration>
If you add
the web configuration file in Listing 23.6 to two applications located
in different domains, the two applications can share the same
authentication ticket. Make sure that you change the validation and
encryption keys in Listing. You can use the GenerateKeys.aspx page
discussed in the previous section to generate new random keys.
Using the FormsAuthentication Class
The
main application programming interface for interacting with Forms
authentication is the FormsAuthentication class. This class supports the
following properties:
- CookieDomain—Returns the domain associated with the authentication cookie.
- CookieMode—Returns the cookieless authentication mode. Possible values are AutoDetect, UseCookies, UseDeviceProfile, and UseUri.
- CookiesSupported—Returns true when a browser supports cookies and Forms authentication is configured to use cookies.
- DefaultUrl—Returns the URL of the page to which a user is redirected after being authenticated.
- EnableCrossAppRedirects—Returns true when an authentication ticket can be removed from a query string.
- FormsCookieName—Returns the name of the authentication cookie.
- FormsCookiePath—Returns the path associated with the authentication cookie.
- LoginUrl—Returns the URL of the page to which a user is redirected when being authenticated.
- RequireSSL—Returns True when the authentication cookie must be transmitted with SSL (the Secure Sockets Layer).
- SlidingExpiration—Returns True when the authentication cookie uses a sliding expiration policy.
These properties
return the configuration settings for Forms authentication from the web
configuration file. The FormsAuthentication class supports the following
methods:
- Authenticate—Enables you to validate a username and password against a list of usernames and passwords stored in the web configuration file.
- Decrypt—Enables you to decrypt an authentication cookie.
- GetAuthCookie—Enables you to retrieve an authentication cookie.
- GetRedirectUrl—Enables you to retrieve the path to the original page that caused the redirect to the Login page.
- HashPasswordForStoringInConfigFile—Enables you to hash a password so that it can be stored in the web configuration file.
- RedirectFromLoginPage—Enables you to redirect a user back to the original page requested before the user was redirected to the Login page.
- RedirectToLoginPage—Enables you to redirect the user to the Login page.
- RenewTicketIfOld—Enables you to update the expiration time of an authentication cookie.
- SetAuthCookie—Enables you to create and issue an authentication cookie.
- SignOut—Enables you to remove an authentication cookie and log out a user.
Using the User Class
You
can use the Page.User or the HttpContext.User property to retrieve
information about the current user. The Page.User property exposes a
Principal object that supports the following method:
- IsInRole—Enables you to check whether a user is a member of a particular role.
For
example, when Windows authentication is enabled, you can use the
IsInRole() method to check whether a user is a member of a particular
Microsoft Windows group such as the BUILTIN\Administrators group:
if (User.IsInRole(“BUILTIN\Administrators”))
{
// Do some Administrator only operation
}
If the Role
Manager is enabled, then you must configure the Role Manager to use the
WindowsTokenRoleProvider before you can use the User.IsInRole() method
with Windows groups. The Principal object also includes an Identity
property that enables you to get information about the current user’s
identity. The Identity object supports the following three properties:
- AuthenticationType—Enables you to determine how the user was authenticated. Examples of possible values are Forms, Basic, and NTLM.
- IsAuthenticated—Enables you to determine whether a user is authenticated.
- Name—Enables you to retrieve the user’s name.
If you want to
get the name of the current user, then you can use logic that looks like
this: Dim name As String = User.Identity.Name
If a user is not authenticated, the User.Identity.Name property returns an empty string.
Configuring Authorization
Authorization
refers to the process of identifying the resources that you are allowed
to access. You control authorization by adding an authorization element
to a web configuration file. Authorization works the same way
regardless of the type of authentication that is enabled. In other
words, you configure authorization in the same way when using Forms,
Windows, and .NET Passport authentication. Typically, you place all the
pages that you want to password-protect in a separate folder. If you add
a web configuration file to the folder, then the settings in the web
configuration file apply to all pages in the folder and all subfolders.
For example, if you add the web configuration file in Listing to a folder, then unauthenticated users are blocked from accessing pages in the folder.
<configuration>
<system.web>
<authorization>
<deny users=”?”/>
</authorization>
</system.web>
</configuration>
If you
prefer, you can configure authorization rules by using the Web Site
Administration Tool. This tool provides you with a form interface for
configuring authorization rules for different folders. You can open the
Web Site Administration Tool by selecting the menu option Website,
ASP.NET Configuration.
Authorizing by Role
When
creating authorization rules, you can authorize by user role. For
example, the web configuration file in Listing prevents access to any
pages in a folder by anyone except members of the Administrators role.
<configuration>
<system.web>
<authorization>
<allow roles=”Administrator”/>
<deny users=”*”/>
</authorization>
</system.web>
</configuration>
When Forms
authentication is enabled, the role refers to a custom role. In the
final section of this chapter, “Using the Role Manager,” you learn how
to configure and create custom roles. When Windows authentication is
enabled, the role refers to a Microsoft Windows group.
Authorizing Files by Location
By
default, authorization rules are applied to all pages in a folder and
all subfolders. However, you also have the option of using the location
element with the authorization element. The location element enables you
to apply a set of authorization rules to a folder or page at a
particular path. For example, imagine that you want to password-protect
one, and only one, page in a folder. In that case, you can use the
location element to specify the path of the single page. The web
configuration file in Listing password-protects a page named Secret.aspx.
<configuration>
<system.web>
<authentication mode=”Forms” />
</system.web>
<location path=”Secret.aspx”>
<system.web>
<authorization>
<deny users=”?”/>
</authorization>
</system.web>
</location>
</configuration>
Using Authorization with Images and Other File Types
Authorization
rules are applied only to files mapped into the ASP.NET Framework. The
Visual Web Developer web server maps all file types to the ASP.NET
Framework. Internet Information Server, on the other hand, maps only
particular file types to the ASP.NET Framework.
If you are
using Internet Information Server, and you add an image to a
passwordprotected folder, then users aren’t blocked from requesting the
image. By default, authorization rules apply only to ASP.NET file types
such as ASP.NET pages. Files such as images, Microsoft Word documents,
and classic ASP pages are ignored by the ASP.NET Framework. If you need
to password-protect a particular type of static file, such as an image
or Microsoft Word document, then you need to map the file’s extension to
the ASP.NET ISAPI extension.
For example, follow these steps to enable authorization for .gif image files:
- Open Internet Information Services by selecting Start, Control Panel, Administrative Tools, Internet Information Services.
- Open the property sheet for a particular website or virtual directory.
- Open the Application Configuration dialog box by selecting the Directory tab and clicking the Configuration button.
- Select the Mappings tab.
- Click the Add button to open the Add/Edit Application Extension Mapping dialog box.
- In the Executable field, enter the path to the ASP.NET ISAPI DLL. (You can copy and paste this path from the Application Mapping for the .aspx extension.)
- In the Extension field, enter .gif.
After you
complete these steps, requests for .gif images are passed to the ASP.NET
Framework. You can then use authentication and authorization rules with
.gif images. You can complete the same sequence of steps to
password-protect other static file types, such as Microsoft Word
documents, Excel spreadsheets, or video files. Using Authorization with
ASP Classic Pages You can mix ASP.NET pages and ASP classic pages in the
same application. However, normally ASP.NET pages and ASP classic pages
live in parallel but separate universes. In particular, ASP.NET
authentication and authorization is not applied to ASP classic pages. If
you are using Internet Information Server 6 (available with Windows
Server 2003), then you can map ASP classic pages into the ASP.NET
Framework. In that case, you can apply
ASP.NET authorization rules to ASP classic pages. Internet Information Server 6 supports a feature named wildcard application mappings.
You can use a wildcard mapping to intercept requests for ASP classic
pages and process the requests with the ASP.NET Framework. The ASP.NET
Framework can then pass the request back to be executed by ASP classic.
To enable wildcard mapping for ASP.NET, follow these steps:
- Open Internet Information Services by selecting Start, Control Panel, Administrative Tools, Internet Information Services.
- Open the property sheet for a particular website or virtual directory.
- Open the Application Configuration dialog box by selecting the Directory tab and clicking the Configuration button.
- Select the Mappings tab.
- Click the Insert button at the bottom of the Mappings tab to open the Add/Edit Application Extension Mapping dialog box.
- In the Executable field, enter the path to the ASP.NET ISAPI DLL. (You can copy and paste this path from the Application Mapping for the .aspx extension.)
After you
complete these steps, then all files, not only ASP classic files, are
mapped to the ASP.NET Framework. You can use ASP.NET authorization rules
to password-protect ASP classic pages in the same way that you can use
these rules to password-protect ASP.NET pages. The authorization rules
also work with image files, Microsoft Word documents, and any other type
of file.
Using ASP.NET Membership
ASP.NET
Membership enables you to create new users, delete users, and edit user
properties. It’s the framework that is used behind the scenes by the
Login controls. ASP.NET Membership picks up where Forms authentication
leaves off. Forms authentication provides you with a way of identifying
users. ASP.NET Membership is responsible for representing the user
information. ASP.NET Membership uses the provider model. The ASP.NET
Framework includes two Membership providers:
- SqlMembershipProvider—Stores user information in a Microsoft SQL Server database.
- ActiveDirectoryMembershipProvider—Stores user information in the Active Directory or an Active Directory Application Mode server.
Using the Membership Application Programming Interface
The
main application programming interface for ASP.NET Membership is the
Membership class. This class supports the following methods:
- CreateUser—Enables you to create a new user.
- DeleteUser—Enables you to delete an existing user.
- FindUsersByEmail—Enables you to retrieve all users who have a particular email address.
- FindUsersByName—Enables you to retrieve all users who have a particular username.
- GeneratePassword—Enables you to generate a random password.
- GetAllUsers—Enables you to retrieve all users.
- GetNumberOfUsersOnline—Enables you to retrieve a count of all users online.
- GetUser—Enables you to retrieve a user by username.
- GetUserNameByEmail—Enables you to retrieve the username for a user with a particular email address.
- UpdateUser—Enables you to update a user.
- ValidateUser—Enables you to validate a username and password. This class also supports the following event:
- ValidatingPassword—Raised when a user password is validated. You can handle this event to implement a custom validation algorithm.
Several of the methods of the Membership class return one or
more MembershipUser objects. The MembershipUser object is used to
represent a particular website member. This class supports the following
properties:
- Comment—Enables you to associate a comment with the user.
- CreationDate—Enables you to get the date when the user was created.
- Email—Enables you to get or set the user’s email address.
- IsApproved—Enables you to get or set whether the user is approved and her account is active.
- IsLockedOut—Enables you to get the user’s lockout status.
- IsOnline—Enables you to determine whether the user is online.
- LastActivityDate—Enables you to get or set the date of the user’s last activity. This date is updated automatically with a call to CreateUser(), ValidateUser(), or GetUser().
- LastLockoutDate—Enables you to get the date that the user was last locked out.
- LastLoginDate—Enables you to get the date that the user last logged in.
- LastPasswordChangedDate—Enables you to get the date that the user last changed her password.
- PasswordQuestion—Enables you to get the user’s password question.
- ProviderName—Enables you to retrieve the name of the Membership provider associated with this user.
- ProviderUserKey—Enables you to retrieve a unique key associated with the user. In the case of the SqlMembershipProvider, this is the value of a GUID column.
- UserName—Enables you to get the name of the user. Notice that the MembershipUser class does not contain a property for the user’s password or password answer. This is intentional. If you need to change a user’s password, then you need to call a method.
The MembershipUser class supports the following methods:
- ChangePassword—Enables you to change a user’s password.
- ChangePasswordQuestionAndAnswer—Enables you to change a user’s password question and answer.
- GetPassword—Enables you to get a user’s password.
- ResetPassword—Enables you to reset a user’s password to a randomly generated password.
- UnlockUser—Enables you to unlock a user account that has been locked out.
Encrypting and Hashing User Passwords
Both of the default Membership providers included in the ASP.NET Framework enable you to store user passwords in three ways:
- Clear—Passwords are stored in clear text.
- Encrypted—Passwords are encrypted before they are stored.
- Hashed—Passwords are not stored. Only the hash values of passwords are stored. (This is the default value.)
You configure how
passwords are stored by setting the passwordFormat attribute in the web
configuration file. For example, the web configuration file in Listing
configures the SqlMembershipProvider to store passwords in plain text.
<configuration>
<system.web>
<authentication mode=”Forms” />
<membership defaultProvider=”MyProvider”>
<providers>
<add name=”MyProvider” type=”System.Web.Security.SqlMembershipProvider”
passwordFormat=”Clear” connectionStringName=”LocalSqlServer”/>
</providers>
</membership>
</system.web>
</configuration>
The default
value of the passwordFormat attribute is Hashed. By default, actual
passwords are not stored anywhere. A hash value is generated for a
password and the hash value is stored. A hash algorithm generates a
unique value for each input. The distinctive thing about a hash
algorithm is that it works in only one direction. You can easily
generate a hash value from any value. However, you cannot easily
determine the original value from a hash value.
The
advantage of storing hash values is that even if your website is
compromised by a hacker, the hacker cannot steal anyone’s passwords. The
disadvantage of using hash values is that you also cannot retrieve user
passwords. For example, you cannot use the PasswordRecovery control to
email a user his original password. Instead of hashing passwords, you
can encrypt the passwords. The disadvantage of
encrypting
passwords is that it is more processor intensive than hashing passwords. The advantage of encrypting passwords is that you can
retrieve user passwords.
Modifying User Password Requirements
By
default, passwords are required to contain at least seven characters
and one nonalphanumeric character (a character that is not a letter or a
number such as *,_, or !). You can set three Membership provider attributes that determine password policy:
- minRequiredPasswordLength—The minimum required password length (the default value is 7).
- minRequiredNonalphanumericCharacters—The minimum number of nonalphanumeric characters (the default value is 1).
- passwordStrengthRegularExpression—The regular expression pattern that a valid password must match (the default value is an empty string).
The
minRequiredNonAlphanumericCharacters attribute confuses everyone.
Website users are not familiar with the requirement that they must enter
a nonalphanumeric character.