转自:http://archive.msdn.microsoft.com/URLRequestSecurity
Description
An URL link with query parameters is usually a plain text which is open to manipulation. It is important to consider protecting such URL links. This article describes an effective way to protect URLs.
Tags: Antiforgery Token, Web Security, URL security, URL Hash, Query String Threat Prevention
In ASP.Net MVC the URL structure has the parts like base URL, controller name, action name and the arguments for that action. These arguments would be passed as plain text as in most of the web applications or the parameters encrypted. Though the parameters can be encrypted, random manipulations of the encrypted hash have chances to result in a valid parameter. In that case it will become escalation of parameters and gain access to restricted resources. ASP.Net provides a novel techniques for the POST request, the AntiForgeryToken. But it is not yet implemented an AntiForgeyToken for the URL parameters.
This article discuss creating and validating an anti forgery token for the URL parameters.
This is a small proof of concept question bank application where it has students. Each student is assigned to subjects and they should allow to view questions belong to the subjects assigned to them. (sample application attached) This sample application developed with Visual Studio 2010 express MVC and SQL Express .
http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=URLRequestSecurity&DownloadId=14495
The work flow of the application starts with user logged in (user name: albin, password:test123) , select a subject and it display the exams conducted in that subject. The exams contains questions. Note the below user interface shows a questions link, which is the key place we are going to talk further.
Figure 2: List of exams with link to questions showing secure and unsecured links
The above picture shows the secured link and a unsecured link which are as follows.
http://<base url here>/Questions/QuestionsView/2/RayZZsXb1M8fjToWiVgEkQGr%2bI0%3d
http://<base url here>/Questions/UnsecuredQuestionsView/2
*(change the localhost:port number to your URL)
The only difference between these two URLs is the second parameter which is a hash (security token). The security token is created using part of the URL including the controller name, action name and the parameters. So If a hacker change the parameter (In this case the exam id: 2), it won't pass the validation because if we need to change the parameter the security hash has to be recomputed with the new parameter.
Before looking into how the hash is formed let us look at a few ways how a hacker can escalate the parameters.
For example in this example the user logged in as (user name:albin, password: test123) and let us say the user trying to access an exam with id 7
http://<base url here>/Questions/UnsecuredQuestionsView/7. The exam with id 7 is a restricted resource for the user.
1) Change the parameter and paste the url in a new tab in the browser and having the link in an another website. Usually this will be prevented by validating the http referrer. Another way we can prevent by track back with parent id relation ship and trace the user to validate this request. This would be tedious and error prone if the database is complex and more over it needs specific logic for each action.
2) Executing a javascript as below from the browser navigation bar will give a link to the hacker which will not be restricted by http referrer validation. Trace back the resource to the user is tedious as said above.
javascript:document.getElementById('testplace').innerHTML='<a href="http://localhost:49510/Questions/UnsecuredQuestionsView/7">Test Me</a>';
However we can have the id parameter encrypted then it is secured, but once the database is bigger then the chance of getting a valid parameter is high by brute forcing (random manipulation of the hash). So this not again a highly secured method. So is it a better method available where the URL can't be forged?!. Yes it is, we should protect the URL itself can't manipulated as ASP.Net MVC has the antiforgery token for the posting variables. We can compute a hash out of the URL and pass that hash as a parameter and then verify it in the called method. It is a simple technique. Let us have a look how we can implement it in asp.net MVC. Below is the method to generate a security token for part of the URL including the parameters.
//This method accepts the partial path, starts from the controller and end with the parameters. Also It accepts a password
public static string generateUrlToken(string controllerName, string actionName, ArrayList argumentParams, string password) { string token = ""; //The salt can be defined global string salt = "#testsalt"; //generating the partial url string stringToToken = controllerName + "/" + actionName + "/"; foreach (string param in argumentParams) { stringToToken += "/" + param; } //Converting the salt in to a byte array byte[] saltValueBytes = System.Text.Encoding.ASCII.GetBytes(salt); //Encrypt the salt bytes with the password Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, saltValueBytes); //get the key bytes from the above process byte[] secretKey = key.GetBytes(16); //generate the hash HMACSHA1 tokenHash = new HMACSHA1(secretKey); tokenHash.ComputeHash(System.Text.Encoding.ASCII.GetBytes(stringToToken)); //convert the hash to a base64string token = Convert.ToBase64String(tokenHash.Hash); return token; }
The above method accepts part of the URL the controller name, action name and the parameter array. It returns a hash that can be added to the URL as below.
<% ArrayList args = new ArrayList(); args.Add(Convert.ToString(item.ExamId)); string token = SecureUrl.Models.SecureUrlToken.generateUrlToken("Questions", "QuestionsView", args, "QuestionList"); %> <%: Html.ActionLink("Questions- Secured Link", "QuestionsView", "Questions", new {id = item.ExamId,urltoken=token }, null)%>
The same way it can be veryfied in the controller as follows.
public ActionResult QuestionsView(string id, string urltoken) { //The url token is generated by the same way it is generated for the link ArrayList args = new ArrayList(); args.Add(Convert.ToString(id)); //This method employs a common business logic for all urls, but only the parameters are different //It helps the url password protected string token = SecureUrlToken.generateUrlToken("Questions", "QuestionsView", args, "QuestionList"); //The url token is cross checked here to ensure that url parameters are not forged if (token == urltoken){ <The action code goes here> } }
This method can be reusable anywhere in the application. Be secure!!.