Circumventing Validation Author: David Zimmer Site: http://sandsprite.com/Sleuth -------------------------------------------------------------------------- Web developers spend alot of time planning out complex chains of events to make thier web applications work. Within the planning and outlines, implicit control over the chain of events is often assumed. This paper is an introduction to breaking those assumptions and realizing just how vunurable those chaulk board outlines can be in the real world. Circumventing Validation (client side manipulation) As more complex and automated web applications arise so does the probability of creating programmatic loop holes in your account sign up and login routines. To further compound the matter HTTP is a stateless Protocol so developers frequently find the need to send the user already Authenticated data back into subsequent forms as hidden elements. While this is an easy and efficient way of storing the data and tracking from who it is coming from it can also open you up to some gaping security holes if improperly implemented. On the surface hidden form elements seem pretty fool proof. They are merely invisible variables that can not be edited by the user. Can they be altered? Why shouldn't I implicitly trust them in my web applications? The first thing every web developer reads is not to use the GET method for submitting forms with sensitive data. A GET request is the standard http browser request method and it can pass data into a script straight from a URL. http://myserver.com/foo.php?password=doh&username=oghh The above URL here passes in 2 parameters namely "password" and "username" Their values are directly readable (and editable!) in the browsers address bar. Already sound bad to you? Well it gets worse; since requested URL's are logged on servers and proxies that potentially sensitive data is now on record somewhere. So we raise the bar a little and we use the POST method for our sensitive data submissions. Let's take a peek behind the scenes at just how browsers POST data. In this example we are going to submit a form with one hidden element "password" and one textbox element named "username". Here is the HTML form we will use
Here are the actual HTTP headers submitted by the browser. POST /auth.php HTTP/1.1 Accept: */* Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) Host: 10.0.0.5:81 Content-Length: 28 Connection: Keep-Alive Cache-Control: no-cache password=doh&username=oghh Here you can clearly see that all the information being sent from browser to server is in quite a simple format and clear text. This brings us to our first form of how users can alter those hidden elements you may be taking for granted. What if I set up a local proxy? My browser would submit the form data to the proxy server, the proxy server would then prompt me and all me to change whatever data I choose to arbitrary values and then submit the data to the actual server. Who would go through all that? Well the thing is people already have. Software already exists out there to do just this to modify cookie values and form elements. Now I bet you are thinking that since SSL offers an encrypted channel you are safe from this right? Well where is the endpoint of that SSL encrypted channel? What if it is the clients proxy server? Now don't let this first example fool you...that was the worst case scenario. From here it only gets easier. Remember web pages are open source, anyone can goto view-source and see all the form elements and where your forms post to. So what happens if I download your web page, alter the hidden elements to my liking and then submit it to the script on your server? Will your script know the difference? The answer here is that it can know the difference if it checks..but do you check? or know how to check? For the sake of brevity we are going to skip ahead and get straight into how to protect yourself from these forms of attack. Here are 3 common methods of content protection all of which are unfortunately flawed: Method 1) requiring a valid referrer value in the http header. While this may stop some attempts from people trying to post forms off their desktops remember the http header can easily be faked using a simple program (read: telnet) to submit to your script instead of them just being lazy and using their browser. Another thing to think about with trying to using the referrer header for validation purposes, is that it is a pretty unreliable header. Some older browsers don't feel it necessary to include it, allot of legitimate proxies filter it out. This is not to mention that it would have absolutely no effect against the local proxy method. So clearly another technique is in order. Method 2) Requiring an active session id. Although slightly more annoying than faking a referrer value, session id values can be recovered from the actual browsers transactions and are submitted in the http header the same as referrers. Still this technique can be subjugated by the proxy method and in the end offers no implicit protection for the actual hidden elements data. Method 3) Obscurity While Obscurity most definitely does not equal security you can deter mildly interested or unskilled attackers. While this is not a main stream technique it is quite possible through client side JavaScript to write out entire forms on the fly so the html is not directly readable in page source. It is also equally possible to use confusing and complex logic routines to discreetly modify the action of the form and even its elements names and values so that would be attackers are not even probing the correct scripts. This technique uses guile more than immutable logic. For low security implementations it may prove viable but since it is all open source you are relying on would be attackers being either under skilled or less than motivated. So how do we protect our forms from tampering? Well I am afraid there is no clean absolute answer. The best practice is to try to avoid using hidden form elements to store visibly sensitive data. If you do, always consider them suspect. If you are relying on them for key information such as user verification or item pricing double check them in some way before final processing. An accepted way to do this is to include a hidden element at the end of the form that contains the hashed value of all the critical hidden elements. This hash is to be calculated with a server supplied salt so the hash itself can not be regenerated by a malicious client. When the form is submitted the hash is recalculated and compared to the one from the client. Also note that this process has to be carried out in every single instance sensitive data fields are used. There is no validity to checking the values in one place then assuming them as valid on the next. One possible sane implementation to this methodology would be to write a specific function where you can pass in the critical name=value pairs and that would then output them as html source adding in the hash element. Server salt values could be static keys that would persist on the server for intervals of 15-20 minutes, All forms being served and verified hashed with the same salt. After this timeout period old pages would be invalidated and would force the user to refresh the page. In the real world application security often suffers from rushed development time , arguments of creating undue server load, or even under trained personal. As with every threat assessment the developer has to look realistically at what he has to protect, implications of disclosure, and use that to determine what level of security to implement. As a final word, circumventing validation is but one aspect of the overall equation of web application security. In many respects maintaining a web application is like maintaining a vehicle. It is great if the car runs, but you better be sure the brakes are also in good order if you want to really be able to use it.