Securing Data Access in ASP.NET
Most ASP.NET Web applications involve data access. Many applications collect data to be stored in a database or file, and the data to be stored is often based on information that comes from users. Because the original data can come from untrusted sources, because the information is stored in a persistent format, and because you want to be sure that unauthorized users cannot access your data source directly, you need to pay particular attention to security issues surrounding data access. The information in this topic describes best practices that will help you improve the security of the data access in your ASP.NET Web application.
While following coding and configuration best practices can improve the security of your application, it is also important that you continually keep your Web server up to date with the latest security updates for Microsoft Windows and Internet Information Services (IIS), as well as any security updates for Microsoft SQL Server or other data source software.
More detailed information about best practices for writing secure code and securing applications can be found in the book "Writing Secure Code" by Michael Howard and David LeBlanc, or through the guidance provided on the Microsoft Patterns and Practices Web site.
Securing Access to a Data Source
The following sections provide information on helping secure different aspects of data access.
Connecting to a database requires a connection string. Because connection strings can contain sensitive data, you should follow these guidelines:
Do not store connection strings in a page. For example, avoid setting connection strings as declarative properties of the SqlDataSource control or other data source controls. Instead, store connection strings in the site's Web.config file. For an example, see How To: Secure Connection Strings when Using Data Source Controls.
Do not store connection strings as plain text. To help keep the connection to your database server secure, it is recommended that you encrypt connection string information in the configuration file by using protected configuration. For more information, see Encrypting Configuration Information Using Protected Configuration.
Connecting to SQL Server using Integrated Security
If possible, connect to an instance of SQL Server using integrated security instead of using an explicit user name and password. This helps avoid the possibility of the connection string being compromised and your user ID and password being exposed.
It is recommended that you ensure that the identity of the process (for example, the application pool) that is running ASP.NET be the default process account or a restricted user account. For more information, see ASP.NET Impersonation.
In scenarios where different Web sites connect to different SQL Server databases, it might not be practical to use integrated security. For example, on Web-hosting sites, each customer is typically assigned a different SQL Server database, but all users use the Web server as anonymous users. In such cases, you need to use explicit credentials to connect to an instance of SQL Server. Be sure that you store the credentials in a secure manner, as described in this topic under Connection Strings.
SQL Server Database Permissions
It is recommended that you assign the minimum privileges to the user ID that is used to connect to the SQL Server databases used in your application.
Restrict SQL Operations
Data-bound controls can support a wide variety of data operations, including selecting, inserting, deleting, and updating records in data tables. It is recommended that you configure data controls to perform the minimum functionality that is required on a page or in your application. For example, if a control should not allow users to delete data, do not include a delete query with a data source control and do not enable deleting in the control.
SQL Server Express Edition
When a process attaches to a SQL Server Express Edition database (.mdf file), the process must have administrative permissions. In general, this makes SQL Server Express Edition databases impractical for production Web sites because the ASP.NET process does not (and should not) run with administrative privileges. Therefore, use SQL Server Express Edition databases only under the following circumstances:
Use as a test database while developing your Web application. When you are ready to deploy your application, you can transfer the database from SQL Server Express Edition to a production instance of SQL Server.
Use if you are running a Web site that can use impersonation and you can control the privileges of the impersonated user. In practice, this strategy is practical only if the application is running on a local area network (not a public Web site).
Store the .mdf file in your site's App_Data folder, because the contents of the folder will not be returned to direct HTTP requests. You should also map the .mdf extension to ASP.NET in IIS and to the HttpForbiddenHandler handler in ASP.NET using the following element in the site's Web.config file:
<httpHandlers> <add verb="*" path="*.mdf" type="System.Web.HttpForbiddenHandler" /> </httpHandlers>
For information on how to map a file name extension to ASP.NET in IIS, see How to: Register HTTP Handlers.
Microsoft Access Databases
Microsoft Access databases (.mdb files) include fewer security features than SQL Server databases. Access databases are not recommended for production Web sites. However, if you have reason to use an .mdb file as part of your Web application, follow these guidelines:
Store the .mdb file in your site's App_Data folder because the contents of the folder will not be returned to direct HTTP requests. You should also map the .mdb extension to ASP.NET in IIS and to the HttpForbiddenHandler handler in ASP.NET using the following element in the site's Web.config file:
<httpHandlers> <add verb="*" path="*.mdb" type="System.Web.HttpForbiddenHandler" /> </httpHandlers>
For information on how to map a file name extension to ASP.NET in IIS, see How to: Register HTTP Handlers.
Add appropriate permissions for the user account or accounts that will be reading and writing in the .mdb file. If the Web site supports anonymous access, this is generally the local ASPNET user account or the NETWORK SERVICE account. Because Access must create an .ldb file to support locking, the user account must have write permissions for the folder that contains the .mdb file.
If the database is protected with a password, do not use the AccessDataSource control to establish a connection to it, because the AccessDataSource control does not support passing credentials. Instead, use the SqlDataSource control with the ODBC provider, and pass the credentials in the connection string. Be sure to secure the connection string as described in this topic under Connection Strings.
If you are storing data in an XML file, place the XML file in your Web site's App_Data folder, because the contents of the folder will not be returned in response to direct HTTP requests.
Guarding Against Malicious User Input
If your application accepts input from users, you need to make sure that the input does not contain malicious content that can compromise your application. Malicious user input can be used to launch the following attacks:
Script injection A script injection attack attempts to send executable script to your application with the intent of having other users run it. A typical script injection attack sends script to a page that stores the script in a database, so that another user who views the data inadvertently runs the code.
SQL injection A SQL injection attack attempts to compromise your database (and potentially the computer on which the database is running) by creating SQL commands that are executed instead of, or in addition to, the commands that you have built into your application.
For all user input, follow these guidelines:
Use validation controls whenever possible to limit user input to acceptable values.
Always be sure that the value of the IsValid property is true before running your server code. A value of false means that one or more validation controls have failed a validation check.
Always perform server-side validation even if the browser is also performing client-side validation, to guard against users bypassing client-side validation. This is especially true for CustomValidator controls; do not use only client-side validation logic.
Always re-validate user input in the business layer of your application. Do not rely on the calling process to provide safe data. For example, if you are using the ObjectDataSource control, add redundant validation and encoding into the object that performs the data updates.
To avoid script injection attacks, follow these guidelines:
Encode user input with the HtmlEncode method, which turns HTML into its text representation (for example, <b> becomes <b>), and helps prevent the markup from being executed in a browser.
When using parameter objects to pass user input to a query, add handlers for the data source control's pre-query events and perform the encoding in those events. For example, handle the SqlDataSource control's Inserting event, and in the event, encode the parameter value before the query is executed.
For controls that can be put into edit mode, it is recommended that you use templates. For example, the GridView, DetailsView, FormView, DataList, and Login controls can display editable text boxes. However, except for the GridView control (see the previous point), the controls do not automatically validate or HTML-encode the user input. Therefore, it is recommended that you create templates for these controls, and in the template, include an input control such as a TextBox control and add a validation control. In addition, when extracting the value of the control, you should encode it.
To avoid SQL injection attacks, follow these guidelines:
Do not create SQL commands by concatenating strings together, especially strings that include input from users. Instead, use parameterized queries or stored procedures.
If you are creating a parameterized query, use parameter objects to establish the values for the parameters. For details, see Using Parameters with the SqlDataSource Control and Using Parameters with Data Source Controls for Filtering.
Encrypting View-State Data
Data-bound controls, such as the GridView control, sometimes need to persist information that is considered sensitive. For example, the GridView control can maintain a list of keys in the DataKeys property, even if this information is not displayed. Between round trips, the control stores the information in view state.
View state information is encoded and stored with the contents of the page and could be decoded and exposed to an unwanted source. If you must store sensitive information in view state, you can request that the page encrypt view state data. To encrypt the data, set the page's ViewStateEncryptionMode property to true.
It is recommended that you avoid storing sensitive information in the Cache object when client impersonation is enabled and the results from the data source are retrieved based on the client identity. If caching is enabled, cached data for a single user can be viewed by all users and sensitive information could be exposed to an unwanted source. Client impersonation is enabled when the impersonate attribute of the identity configuration element is set to true and anonymous identification is disabled for the application at the Web server.