Verify ASP. NET query string [Share]

Source: Internet
Author: User
Get the sample code for this article.

NEW: getting e the sample code online!

-Or-

Download Code: CuttingEdge2007_03.exe (168KB)

Directory Problems
Define Policy
Declarative query string
Encode the QueryString HTTP Module
Query string Verification
Precautions and alternative solutions
Summary

Over the years, typical ASP developers have been inserting some generic code at the top of each page to implement page authentication, which extracts user creden。, attaches cookies, and redirects them. The ASP. net http module eliminates all the repetitive code during authentication. Therefore, each page linked to an ASP. NET application does not have to be protected by the selected authentication module. You can use the web. config file and a large number of external resources (such as logon pages and member databases) to complete all the work in a declared manner.

ASP. NET also introduces other system modules and programming technologies to minimize repetitive code and rationalize the implementation of common functions of Web applications. For example, site maps, anonymous users, and configuration files are all built-in functions, so you do not have to write or copy code again.

The focus on security makes ASP. NET Runtime Library adds a large number of local barrier, which eliminates the burden on developers for cross-checking input data to withstand some possible forms of attacks. Of course, this does not mean that ASP. NET applications are designed to be secure, but it does mean that the security level is higher than in the past. However, further security improvement still depends on developers.

The ASP. NET page is designed to publish data to these pages and group the input parameters in the body of the http post packet. Most ASP. NET applications use query strings to transmit input data less frequently than typical ASP applications. However, querying strings is still a reasonable way to import external data to the ASP. NET page. But who will verify the data?

Recent statistics show that cross-site scripting (XSS) attacks are increasingly rampant, and they account for the highest proportion of detected attacks. The reason for XSS attacks has always been that the input data is not verified or improperly verified, which is often obtained by querying strings.

First, ASP. NET 1.1 is used to pre-process all published data (Forms and query strings) to find suspicious character combinations that may be exploited by XSS attackers. But this barrier is not a silver bullet, as Michael Howard wrote in The November 2006 MSDN Magazine "security habits: eight simple rules for developing safer Code" (available in msdn.microsoft.com/msdnmag/issues/06/11/SecureHabits) you must assume the responsibility. If the page uses query string parameters, make sure they are properly verified before use. How can we achieve this?

In this column, I will build an HTTP module for reading XML files, which has hardcoded the expected structure of the query string. This module verifies the query string of any requested page against the given architecture. You do not need to access any page code. (For more information about how to defend against XSS attacks, see Microsoft Anti-Cross Site Scripting Library 1.5)

Problem

If you allow the page to accept input from the query string, developers cannot bear the consequences of this situation. You must verify the value and carefully check the format of the query string. A verification process like this involves two explicit steps: static verification (used to check the type of the required parameter and whether it exists) and dynamic verification (used to confirm whether the specified value is as expected in other parts of the Code ). Dynamic verification is specific to each page and cannot be delegated to external components unrelated to the page. Instead, static verification relies on a series of common checks (required parameters, types, and lengths) that can be executed without page instantiation.

For a typical ASP, the generic authentication code must be included in each secure page. Similarly, the query string authentication code must be included in each page in ASP. NET. ASP. NET moves standard authentication code to a small number of HTTP modules provided by the system, but does not process query strings. On the other hand, the development of XSS and SQL Injection attacks has recently caused any possible input sources for cross-checking. Using an external component to link to an application that strictly performs static verification on query string parameters can greatly improve this situation, because it automatically ensures that no ASP is executed when the query string does not conform to the declared architecture.. NET page request.

More importantly, with external components, you do not need to make any changes to the page source code. All you need to do is register the component with the application through the configuration file, and add an XML file to describe the query string syntax for each page of interest. Next, we will introduce this policy in more detail.

Define Policy

ASP. NET provides the HTTP module as a tool for injecting your code into the Runtime Library pipeline before instantiating and processing the requested page class. From the perspective of syntax, the HTTP module is just a class used to implement a given interface. From a broader architecture perspective, the HTTP module is an observer with the same lifetime as the application. This module can observe and register request processing activities to listen for specific events, such as BeginRequest, EndRequest, or PostMapRequestHandler. The complete list of application events requested by ASP. NET can be found in the documents of the System. Web. HttpApplication class (msdn2.microsoft.com/0dbhtdck.aspx ).

After the installation is complete, the HTTP module plays a role each time the request processed by the ASP. NET Runtime Library reaches the stage of triggering the observed event. Note that the ASP. NET runtime does not necessarily process requests for all resources hosted by ASP. NET applications. By default, the Web server directly processes static resources, such as Cascading Style Sheets (CSS) and JPG files, without making ASP. NET application, unless IIS is configured to allow ASP.. NET processes these resources.

The HTTP module of my query string listens to the begin-request event and verifies the query string content against the previously loaded architecture. If the number of parameters matches and the provided values are compatible with the expected type, the module takes the request to the next stage. Otherwise, the request is terminated and an HTTP status code or ASP. NET exception is thrown.

I mentioned an XML file used to store the query string syntax. In fact, it is not necessarily an XML file. (For XML files, the architecture depends entirely on you .) You only need one data source to save information about the expected structure of the query string on the page in a declared manner. It can be a simple XML file or a complex provider-based service. In my June 2006 column, I provided an example of a custom application service dedicated to using the provider (msdn.microsoft.com/msdnmag/issues/06/06/CuttingEdge ).

Declarative query string

Figure 1 shows an XML file example and the structure to be recognized by the query string HTTP model. Under the root node <querystring>, there are <page> nodes with the same number of pages as the application. They can process the values from the query string. In the Code included in this column, the file shown in Figure 1 is named web. querystring. Of course, the name and architecture are arbitrary.

(From the security point of view, the main problem is not to query the received values of strings on the page, but to use these values on the page. If some code on the page needs to process the input sent by the query string, you must ensure that the input is safe and trusted as a developer. Therefore, you may want to add a <page> node to the XML file and add only the pages in the application that actually use the data passed through the query string .)

In the architecture example, the <page> element has two attributes: url and abortOnError. The former indicates the relative URL of the page, and the latter is an optional Boolean attribute, used to indicate whether the page request should be aborted when an error is entered. If you choose to abort the page, the user will receive an HTTP Error or ASP. NET exception based on the measures that are determined after unacceptable data is found in the query string. No matter how the result is displayed, you do not need to edit the code of the ASP. NET page involved. In the HTTP module, request termination may occur before page classes are identified and instantiated.

There is an alternative method. In this method, the HTTP module makes the request pass smoothly, but adds details to the HTTP context to notify the page class of the detected content. Then the page is responsible for taking appropriate measures, such as displaying a special error page. In this case, the author of this page must integrate all query string exceptions into the context of the error handling policy set of the application. The disadvantage of this method is that you need to modify the code of each page involving the query string. (I will discuss this later .)

By default, the abortOnError attribute is set to "true", meaning that any exception in the query string will abort the page request. Each <page> node has a <param> column. Each supported query string parameter has a node. In the sample code, you can use the attribute defined parameters in Figure 2.

ASP. NET receives all the values passed on the query string as a string. Therefore, the QueryString attribute defined on the HttpRequest object is the NameValueCollection object of which the key and value are both strings. However, the string format is purely serialized. Of course, each query string parameter can not only represent a string, but also a Boolean value or value, as well as a special string subtype, such as URL, GUID, and file name. Therefore, in the web. querystring file, you can use the value of QueryStringParamTypes of the custom Enumeration type to specify the expected parameter type:

Friend Enum QueryStringParamTypes As IntegerText = 1Int = 2Bool = 3End Enum

 

The list of supported types can be expanded, such as adding various numeric types. You can also use the Length attribute to specify the maximum Length of a Text parameter. If a page can accept a customer ID of 5 characters from the query string, it is necessary to limit the length of this parameter. In addition, web. querystring can be used to enable the case-sensitive check of parameter names, and can be specified as optional. The content of the web. querystring file is parsed by the HTTP module of the query string and converted to an object in memory.

Encode the QueryString HTTP Module

Figure 3 shows the source code of the QueryString HTTP module. As mentioned above, the HTTP module class can implement the IHttpModule consisting of the Init and Dispose methods. These methods are called when the module is loaded and uninstalled in the application context. In the Init method, the HTTP module usually registers a listener for the Application events it wants to observe. In this example, it registers a handler for the BeginRequest event. In addition, this module processes the web. querystring file and creates a representation of its content in the memory. Each application calls the Init method only once, reads the content of the configuration file at a time and caches it. Changes to the Web. querystring file are detected only when the web application restarts. This may not cause problems, because in production, if you do not stop or restart the application, there is almost no need to change the web. querystring file. However, you can also expand the code in Figure 3, use a file to observe the program object to detect any changes to the web. querystring file, and reload it in time.

The content of the web. querystring file is mapped to a QueryStringDescriptor object, as shown in 4. The descriptor contains the URL of the page, a sign used to indicate the actions to be taken when verification fails, and a list of supported query string parameters. Describes each parameter through an instance of the QueryStringParamInfo class. QueryStringParamCollection is a collection class. It is a typical generic collection class, which contains a pair of Find methods: a parameter used to confirm whether a given name exists in the set, and a parameter descriptor instance is returned.

The query string descriptor caches the query string information on the given page. However, the web. querystring file can reference multiple pages. Therefore, the page URL is used as the key to group all the page descriptors referenced by web. querystring in a hash table. The following code snippet shows how the BeginRequest handler of the HTTP module retrieves the descriptor of the current request page:

Dim currentPage As StringcurrentPage = HttpContext.Current.Request.Path.ToLower()Dim qsDesc As QueryStringDescriptor = __queryStringData.Item(currentPage)

 

The query string descriptor is the memory representation of the correct syntax of the query string on the page. The next step is to verify the released query string against this architecture.

Query string Verification

The verification process is divided into three steps. First, the module counts the parameters in the released query string. If the number of published query strings is more than expected, verification fails. Next, the module cyclically accesses the released query string parameters and ensures that each parameter matches a specific item in the declared architecture. If an extra unknown parameter is found, verification fails. Finally, the module cyclically accesses all parameters defined in the schema, and confirms that all required parameters are specified, and each specified parameter has a value of a certain correct type.

The data verification step attempts to resolve the value of a given parameter to the type it declares. The following code snippet is used to verify the value:

If paramType = QueryStringParamTypes.Int ThenDim result As IntegerDim success As Boolean = Int32.TryParse(paramValue, result)If Not success Then Return FalseEnd If

 

It is designed to parse Boolean values only from strings such as "true" and "false. The validation subsystem of the Querystring HTTP module also accepts strings such as "yes" and "no.

Finally, as the first step in the request pipeline, parse the content of the query string and verify its type. If everything is completed successfully, the request is processed. Otherwise, the request is immediately terminated and an appropriate HTTP status code is displayed. For example:

HttpContext.Current.Response.StatusCode = 500HttpContext.Current.Response.[End]()

 

5 pages are provided for users. You may complain that it does not indicate the actual cause of the IIS error, however, the HTTP status code and generic description clearly indicate the internal server Errors generated during request processing. As mentioned above, Michael Howard explained in his article that the least information should always be leaked on the error page to avoid the risk of inadvertently spreading details to potential hackers. At this point, HTTP 500 errors are common enough to indicate actual errors. In short, as shown in the code segment above, the HTTP status code can be set at will.


Figure 5 Error query string results (click the image to get a smaller view)
Figure 5 Error query string results (click the image to get a larger view)

Precautions and alternative solutions

Should I abort the request if the format is incorrect? Or is it better to cache the verification results somewhere and make the page Code make a final decision to the user? In addition, should I capture and process query strings at such an early stage of the Request lifecycle? First, we will solve the next problem.

Figure 6 lists application-level events that indicate request processing features. If the query string is not checked when the request starts, when should the query string be checked? A good check point is to check immediately after authorization. If the request processing has passed the authorization phase, you can be sure to call the HTTP processing program of the page.

But can I check it later? In general, PostAcquireRequestState and any previous event handler can be used. User code (the author of the code page writes the code hidden or embedded in the ASPX file) is executed only after the PostAcquireRequestState event. Then, the query string can be processed only after the global PostAcquireRequestState event is triggered. However, you should not wait for such a long time. Checking query strings after authorization and before executing on the page can reduce the number of additional operations, that is, retrieving session Status and checking the output cache. If the query string is incorrect, you need to terminate the Error! Hyperlink reference not valid. You do not need to load the session status first, especially when it comes from external sources such as SQL Server Processes.

Finally, the query string check should be placed only at the location of two application events: BeginRequest or PostAuthorizeRequest. If user information is required to process the query string, select the latter. For example, if some users are allowed to specify certain parameters based on their roles. In this case, you can also add the roles attribute to the architecture in Figure 1. In any other situation, you can set interception in BeginRequest to terminate the page at an early stage of the MPs queue to prevent further processing.

If you still want the Page code to process the wrong query string and try to downgrade or restore normally, the situation will be different. In this regard, I think any event before the page is executed will run normally. I will select PostAcquireRequestState, which is the last point in the pipeline that can check the query string before code execution on the page. The session status is also available at this point. I have not mentioned this yet, but the context has clearly explained this point: the query string information is provided from the beginning of the QueryString set of the object in the Request.

Therefore, it is assumed that you want the HTTP module to check the query string and pass its results along the pipeline until the Page code. You can take several possible methods. Before discussing these methods, we should first point out that these methods will affect the code and the source code of each page with query strings needs to be modified.

The simplest way for the HTTP module to communicate with the processing program responsible for the given request is to enter the data in the Items set of the HttpContext object. The Items attribute is a hash table of the HTTP module and processing program for writing and reading information. Any data stored in the Items table has the same lifetime as the request.

The HTTP module uses the static Current attribute in the HttpContext class to obtain the access permission for the context object of the Current request, as shown below:

HttpContext.Current.Items("QueryStringStatus") = errorCode

 

Items is System. Collections. Hashtable, and keys and values can all be of any. NET type. The query string module uses the public Enumeration type to list all possible error codes:

<Flags()> _Public Enum QueryStringErrorCodesNoError = 0TooManyParameters = 1InvalidQueryParameter = 2MissingRequiredParameter = 4InvalidContent = 8End Enum

 

The combination of these codes can better describe the errors in the query string. The combination will be filled in a location in the hash table that meets the naming conventions. The HTTP module and page must agree on the naming conventions so that the page can retrieve and use this information. The HTTP module defines a public constant to indicate the location name:

Public Const QueryStringValidationStatus As String = _"QueryStringValidationStatus"

 

You can use the following code to retrieve a message from the HTTP module and decide how to process the message:

Dim result As QueryStringErrorCodes = _DirectCast(Context.Items( _QueryStringHelper.QueryStringValidationStatus), _QueryStringErrorCodes)

 

Assume that you want this module to provide the type value obtained from a valid query string for the page. Consider the following URL and assume that the query string is correct:

http://www.yourserver.com/page.aspx?detailed=true

 

The page should combine the code to parse and query the string value and convert it into a Boolean value. During verification, the HTTP module has completed this conversion. The simplest way is to place the hash table of the type value into another Items location and share the type value with the target page (for more information, see source code ).

A more concise method is to add new read-only attributes to each page with query strings. If IsValidQueryString is called, the method is as follows:

Public Property IsValidQueryString As BooleanGetDim result As QueryStringErrorCodes = DirectCast( _Context.Items(QueryStringHelper.QueryStringValidationStatus), _QueryStringErrorCodes)Return (result = QueryStringErrorCodes.NoError)End GetEnd Property

 

A better way is to define such an attribute on the base class and derive all pages with query strings enabled from this class.

Summary

Not all ASP. NET pages use query strings. However, the query string can be used as the Web page input. Therefore, this is a possible attack point on the page with security vulnerabilities. If the page needs to query the string barrier, you are prepared to repeat the same code on all pages where you want to use the query string.

The QueryString module described in this column does not need to be encoded on the Source Page. It automatically checks the published query string against the given architecture saved in a separate XML file. This means there is no impact on the existing code, and it also provides an additional built-in barrier to defend against attackers. But remember, this is not a silver bullet.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.