enableViewStateMac="true" FAILS to Validate _ViewState - asp.net

I have my web application where I have set the enableViewStateMac="true" under attribute in web.config. I was trying to validate different security aspects of view state.
However, there is one scenario, where enableViewStateMac="true" fails to validate the _ViewState has been changed. I am using the "TamperData" plugin of Firfox browser. Using Tamperdata, I completely remove the value of _VIEWSTATE and then POST the web request. The POST request gets posted successfully and page redirects to the next page successfully without any error.
Though, as per my knowledge and security testing so far for enableViewStateMac="true", It seems to me the EnableViewStateMac only works/validate weather _VIEWSTATE is being tampered or not. But it doesn't validate if _VIEWSTATE Value is being deleted/removed completely.
Is there is a way I can validate this also (that is if someone has completely removed the value of _VIEWSTATE)?
Thanks in advance,
Happy coding :)

When the page is generated, store a value in ViewState. Then, on post back, read that value back out. If __VIEWSTATE isn't present you'll receive a null value back at read time.

Related

Session values are lost between calls

Due to an unknown reason, my website does not send ASP.NET_SessionId cookie to browser neither on local debugging IIS nor on deploying IIS, therefore my Session is always empty on each page. In IIS preferences 'Session state' is set to 'In process' (sorry, maybe not exact translation, I have localized IIS). Any ideas on this matter?
ADDITION 1: Well, I switched sessionState mode to <sessionState cookieless="UseUri" />. Url address in browser now contains (S(fn215g55r4kws155lbfaxf55)) tag, but Session property of the ASPX page is empty ANYWAY. So... my website is still sessionless without any obvious reason.
ADDITION 2. I created blank website on the same debug server and session cookie works okay there - values are persisted between calls. So, the problem is related to my main website or its web.config, I believe.
ADDITION 3. As mentioned #Damien_The_Unbeliever, the problem is really related to setting values. I do not know why, but session is completely ignores line Context.Session[promoCodeSessionKey] = (int?)promoCode.Id;. No cookie is send after this line. But if session is already created in another place and cookie is set, this line will work correctly.
ADDITION 4. I found the reason. See the answer below.
WOOHOO!! I found the reason! There was EnableSessionState="ReadOnly" directive in ASPX's <%# Page tag. Please pay attention, that a) because of this Session was not working on master page as well, and b) there are no exceptions!!

AJAX Callbacks Allowing HTML

I have a comment form on my website and I would like to stop any HTML from being posted through it. I was under the impression that ASP.NET automatically stops any HTML from being submitted by throwing a "potentially dangerous request" exception, but it's allowing HTML in this case.
All of the settings that relate to validation have been left to default so it should be set to requestValidationMode="4.0".
Anyone know what can cause this? Does it have anything to do with the fact that I am using AJAX callbacks?
Edit: I have gathered some more details:
Validation is correctly working in one sub-folder in my application, but it isn't working in any of the others. I looked into my web.config and this is the only setting I have put regarding page validation:
<pages enableViewStateMac="true" validateRequest="true">
Why is it working in one subfolder but not in the others? Does it have anything to do with the fact that this subfolder has a web.config entry regarding authentication?
Edit: Regular postbacks are being validated, just not callbacks.
Edit again: I was playing around with Fiddler and while doing so I noticed one of the callbacks was blocked by the server. Here is what the blocked request looks like:
And here is the plain text version:
__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwUKLTI4MDgzMDI5NA9kFgJmD2QWBAIBDxYCHgdwcm9maWxlBSFodHRwOi8vd3d3LnczLm9yZy8yMDA1LzEwL3Byb2ZpbGVkAgMPZBYOZg8WAh4Fc3R5bGUFkAFiYWNrZ3JvdW5kLXBvc2l0aW9uOnJpZ2h0IGJvdHRvbTtiYWNrZ3JvdW5kLXJlcGVhdDpOby1SZXBlYXQ7YmFja2dyb3VuZC1pbWFnZTp1cmwoaHR0cDovL2xvY2FsaG9zdDo4MS9JbWFnZXMvTGF5b3V0LUltYWdlcy9UaXRsZUJhY2tncm91bmQucG5nKTtkAgIPFgIeCWlubmVyaHRtbAWlAjxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij48IS0tCmdvb2dsZV9hZF9jbGllbnQgPSAiY2EtcHViLTk2MTM2OTA0OTA1Mjg4MTQiOwovKiBCT0lHIFRvcCAqLwpnb29nbGVfYWRfc2xvdCA9ICI0MjcwOTc3NjY2IjsKZ29vZ2xlX2FkX3dpZHRoID0gNzI4Owpnb29nbGVfYWRfaGVpZ2h0ID0gMTU7Ci8vLS0%2BCjwvc2NyaXB0Pgo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIKc3JjPSJodHRwOi8vcGFnZWFkMi5nb29nbGVzeW5kaWNhdGlvbi5jb20vcGFnZWFkL3Nob3dfYWRzLmpzIj4KPC9zY3JpcHQ%2BZAIDDxYCHwIFqgI8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI%2BPCEtLQpnb29nbGVfYWRfY2xpZW50ID0gImNhLXB1Yi05NjEzNjkwNDkwNTI4ODE0IjsKLyogQk9JRyBTaWRlYmFyICovCmdvb2dsZV9hZF9zbG90ID0gIjIyMDAxMDYxMTAiOwpnb29nbGVfYWRfd2lkdGggPSAxNjA7Cmdvb2dsZV9hZF9oZWlnaHQgPSA2MDA7Ci8vLS0%2BCjwvc2NyaXB0Pgo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIKc3JjPSJodHRwOi8vcGFnZWFkMi5nb29nbGVzeW5kaWNhdGlvbi5jb20vcGFnZWFkL3Nob3dfYWRzLmpzIj4KPC9zY3JpcHQ%2BZAIEDw8WAh4HVmlzaWJsZWdkZAIFDxYCHwIFEjxwPkxpbmsgMSB0ZXh0PC9wPmQCBg9kFgICAw8WAh8DaGQCBw8WAh4EVGV4dAU%2BPHNwYW4gc3R5bGU9Im1hcmdpbi1yaWdodDogNXB4OyI%2BwqkgQmluZGluZ09mSXNhYWNHdWlkZTwvc3Bhbj5kZKMbP1fMlxWhgVw8zpEPBPGzlw5j&=sdfdsgd%40sfds.com&=%3Cp%3Efghfghfg%3C%2Fp%3E&=%3Cp%3Efghfghfg%3C%2Fp%3E&=%3Cp%3Efghfghfg%3C%2Fp%3E&__CALLBACKID=__Page&__CALLBACKPARAM=sdfdsgd%40sfds.com--%7C%7C--%3Cp%3Efghfghfg%3C%2Fp%3E--%7C%7C--%3Cp%3Efghfghfg%3C%2Fp%3E--%7C%7C--%3Cp%3Efghfghfg%3C%2Fp%3E
Here is a typical request that isn't blocked:
Plain text:
__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwUKLTI4MDgzMDI5NA9kFgJmD2QWBAIBDxYCHgdwcm9maWxlBSFodHRwOi8vd3d3LnczLm9yZy8yMDA1LzEwL3Byb2ZpbGVkAgMPZBYOZg8WAh4Fc3R5bGUFkAFiYWNrZ3JvdW5kLXBvc2l0aW9uOnJpZ2h0IGJvdHRvbTtiYWNrZ3JvdW5kLXJlcGVhdDpOby1SZXBlYXQ7YmFja2dyb3VuZC1pbWFnZTp1cmwoaHR0cDovL2xvY2FsaG9zdDo4MS9JbWFnZXMvTGF5b3V0LUltYWdlcy9UaXRsZUJhY2tncm91bmQucG5nKTtkAgIPFgIeCWlubmVyaHRtbAWlAjxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij48IS0tCmdvb2dsZV9hZF9jbGllbnQgPSAiY2EtcHViLTk2MTM2OTA0OTA1Mjg4MTQiOwovKiBCT0lHIFRvcCAqLwpnb29nbGVfYWRfc2xvdCA9ICI0MjcwOTc3NjY2IjsKZ29vZ2xlX2FkX3dpZHRoID0gNzI4Owpnb29nbGVfYWRfaGVpZ2h0ID0gMTU7Ci8vLS0%2BCjwvc2NyaXB0Pgo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIKc3JjPSJodHRwOi8vcGFnZWFkMi5nb29nbGVzeW5kaWNhdGlvbi5jb20vcGFnZWFkL3Nob3dfYWRzLmpzIj4KPC9zY3JpcHQ%2BZAIDDxYCHwIFqgI8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI%2BPCEtLQpnb29nbGVfYWRfY2xpZW50ID0gImNhLXB1Yi05NjEzNjkwNDkwNTI4ODE0IjsKLyogQk9JRyBTaWRlYmFyICovCmdvb2dsZV9hZF9zbG90ID0gIjIyMDAxMDYxMTAiOwpnb29nbGVfYWRfd2lkdGggPSAxNjA7Cmdvb2dsZV9hZF9oZWlnaHQgPSA2MDA7Ci8vLS0%2BCjwvc2NyaXB0Pgo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIKc3JjPSJodHRwOi8vcGFnZWFkMi5nb29nbGVzeW5kaWNhdGlvbi5jb20vcGFnZWFkL3Nob3dfYWRzLmpzIj4KPC9zY3JpcHQ%2BZAIEDw8WAh4HVmlzaWJsZWdkZAIFDxYCHwIFEjxwPkxpbmsgNSB0ZXh0PC9wPmQCBg9kFgICAw8WAh8DaGQCBw8WAh4EVGV4dAU%2BPHNwYW4gc3R5bGU9Im1hcmdpbi1yaWdodDogNXB4OyI%2BwqkgQmluZGluZ09mSXNhYWNHdWlkZTwvc3Bhbj5kZCu6t45MzsFLBRWYDAvPXYbIXKqE&=&=&=&=&__CALLBACKID=__Page&__CALLBACKPARAM=cfdsdg%40adfds.com--%7C%7C--%3Cp%3Esdfdgdfg%3C%2Fp%3E--%7C%7C--%3Cp%3Esdfdgdfg%3C%2Fp%3E--%7C%7C--%3Cp%3Esdfdgdfg%3C%2Fp%3E
I don't know why the requests are different, nothing changed on the page. I noticed that the first one seems to have split the parameters into the boxes while the second one hasn't. Is this the issue?
I just checked the callbacks being sent from the sub-folder and they are all split into parameters just like the first request. I guess this is the problem... but why is it happening?
I made the inputs runat=server and the request changed a bit, but the values are still not being assigned.
Here is what I found:
___CALLBACKPARAM is not actually validated by the server, only the parameters as seen in the first image are. With this in mind I validated the request myself using the following regex <\/*(p|div|span|a|script|br|b|i|u|h1|h2|h3|ol|ul|li)\s*.*>. You can find more online; hope this helps.

Should Session be checked on Page Load in ASP.Net?

Page Load, as a sentence of 2 words, means when the page is loaded, means, when all elements are loaded.
Let's say I have a page called Ask.aspx, and this page is only allowed to users who have signed in, so technically I would write something like this :
if(Session["id"]==null)
Response.Redirect("Login.aspx");
This mean, that I'm testing the Session AFTER the page loads, theoretically, I think it sounds wrong, now of course I won't notice it, it will be fast, I will try to access the page, then I'm redirected to Login.aspx, but... is it correct to test the Session on Page Load method?
The Page_Load is part of the page lifecycle. It is called when the Server loads the page, not when the Client loads the page...
So this is the correct place to check the Session Variable...
You're actually saying: Before I post the page back to the client, check if I have the ID property set for this session... If I don't - tell the client to redirect to the Login.aspx page...
This is the correct way of doing this...
I recommened you also read about Server.Transfer. The difference between it and Response.Redirect is that in Server.Transfer the server itself "redirects" to another page and outputs the result of the new page back to the client (without the client knowing about it).
If you are trying to limit access to specific pages, you would be better off using forms authentication.
http://support.microsoft.com/kb/301240
It is fairly easy to setup and it allows checking of credentials before the request is passed to the asp.net pipeline. In what you are doing, your page goes through the entire lifecycle (controls are rendred and bound to data, access to database, calls to web services etc.) before the request is rejected. Depending on your situation, this might be costly and will not scale well.
Edit: You can also hook in to the AcquireRequestState event in the global.asax. This will also spare the entire page life cycle.

IE7 Classic ASP Cache

I have a classic asp website that uses Session variables to store login state ie. userid, isloggedin, etc. On logout, the session variables are reset and Session.Abandon() is called followed by a redirect to the login page. In IE7 I have noticed that after logout I can type in a previously visited url and see what appears to be a cached version of its state prior to the logout. Hitting ctl-f5 will reload from the server again and redirect to the login page. This is the behavior I want to occur even if the url is type in without the ctl-f5. Does anyone know how to get this behavior?
set the no-cache headers so that the pages do not get cached in the first place. see:
http://support.microsoft.com/kb/234067
I think mkoryak's answer (using no-cache headers) seems best. If you want certain pages to be seen only when a user is logged in, the best way is to instruct the browser to simply not cache the page. Furthermore, schemes such as tweaking cookies and using javascript do determine login state on the client are simply reinventing the wheel.
If you want to leverage some caching and your page isn't something that is constantly updating, a good compromise is to set the Response.Expires header to some value you deem appropriate (it's measured in minutes I believe).
I've had a similar problem before, but whenever I've clicked a link on that page, it's asked me to log back in.
You could try either resetting sessionID = "" or sessionID = "XYZ" and make XYZ something your code ignores on log out.
You could also try setting no-cache headers.
You could send no-cache however thats quiet a performance hit just to get what you want. I prefer Liams suggestion and ensuring that everything you do from that page requires you to be logged in, that way no one can do anything they shouldn't. What if its a email system though or similar, the people "could" view other peoples emails which are cached, in those instances then yes, not caching sensitive information is the way to go (you can't cache HTTPS pages by default for instance).
You could also include some javascript in the head which could check for the existance of a "logged in" cookie. This would run every time they loaded the page, if no cookie exists then JS could redirect you off to the login page. Not 100% fool proof but good enough. You logout page would need to clear this cookie and you login page set it.

Http Exception generated while validating viewstate

I am getting the following error whenever I click on a postbacking control
HttpException (0x80004005): Validation
of viewstate MAC failed. If this
application is hosted by a Web Farm
or cluster, ensure that configuration
specifies the same validationKey and
validation algorithm. AutoGenerate
cannot be used in a cluster.
I am not using a Web Farm or cluster server. I have even tried setting the page property EnableViewStateMac to false but it changes the error message stating
The state information is invalid for
this page and might be corrupted.
What could possibly be wrong?
There is an article about this here: http://blogs.msdn.com/tom/archive/2008/03/14/validation-of-viewstate-mac-failed-error.aspx .
The basic problem is that Your page hasn't completed loading before You perform the postback.
A few different solutions are in the article listed above:
1. Set enableEventValidation to false and viewStateEncryptionMode to Never
2. Mark the form as disabled and then enable it in script once the load is complete.
3. override the Render Event of the page to place the hidden fields for Encrypted Viewstate and Event validation on the top of the form.
But the main problem is that the page load slow, which should be fixed (if possible ASAP). It can also be good to apply solution 2 above as well as there will always be trigger happy users that will click faster that the page loads no matter how fast it loads :-).
/Andreas
I have encountered the same problem with a custom build ASP.NET control which was dynamically reloaded and rebuild on every POST / GET request. Thus the page sending the POST request was not the same as the one recieving the response.
If you use any custom or databound controls look closly how they behave on a POST back.

Resources