ASP .NET OnClick Fires wrong server side method - c#

Synopsis:
I have a login page has two bootstrap modals, one for registering a new account and one for logging into an existing account. Intermittently I'm seeing an issue where trying to log in results in the method for the registering submit button being fired instead of the method for the login button (the one clicked).
Details:
I'm going to describe some of the layout and post code where necessary. I'm trying to avoid posting a ton of code since I'm not exactly sure where the issue lies. This page is a childpage of the site.master, has multiple .css and .js files associated with the theme and the site functionality.
'signup-modal' modal includes a few input fields and then the submit button 'Button1', whose onclick parameter fires the server-side 'RegisterUser' method in the code behind file (C#).
'login-modal' modal includes inputs for username/password, a remember me checkbox, a login with facebook button and the submit button, whose onclick parameter fires the server-side 'ValidateUser' method in the code behind file (C#).
Each modal is surrounded by an UpdatePanel.
When a user has the login modal open and fills valid information then clicks the login button it will typically operate as expected, firing the 'ValidateUser' method, checking the information with the database and authenticating/redirecting the user to the content page. However, occasionally when clicking the login button the 'RegisterUser' method fires instead and returns an error I coded for when the DB tells it that the username entered already exists.
Unfortunately I can't seem to consistently recreate this error, but it does seem to be related to the authentication. I'm using FormsAuthentication to set authentication cookies for the user once they've been validated by the user database. I've noticed that when this error happens, if the cache is cleared, then you are able to login successfully.
What I don't understand is why anything in Session authentication should cause the wrong method to fire onclick. Especially since when it fires the button control it's associated with is hidden and should be inaccessible. The best I can figure is that somehow all onclick methods are being fired and because the 'RegisterUser' one is first in the html, that is the one being executed?
What I've Tried:
I had read a couple posts where people would see this type of behavior as a result of blank labels:
ASP.NET: Wrong event is fired when I click a LinkButton
I don't see anything like that in my code, however I did have a class="" call out in an ASP:Button control that was generating a warning about class="" not being a valid parameter. I tried removing that but didn't see any change in behavior.
I have included on both forms (in each modal) required field parameters, which I remove/add VIA javascript when the modal is hidden or shown. The reason I remove it is that an error is thrown if a required field is hidden due to the browser trying to find the control to validate and not seeing it. Since the 'RegisterUser' method fires without the browser trying to authenticate the associate fields I can surmise that the button is actually hidden (with the required parameters removed) and not just off screen or something.
I have tried without success to determine why this only happens intermittently. It doesn't seem to be due to the number of authenticated sessions under one username. I have logged into over 5 sessions on different computers/browsers without getting the error and had it happen on the first login attempt for a user.
Also, I can confirm that I've seen this error across Chrome, IE, Edge and Firefox, again intermittent on all.
I've double checked that the 'RegisterUser' method isn't being called anywhere else besides the onclick function of the register button.
I haven't been able to find any other posts similar to this, so I'm turning to you in desperation.
The Question:
So if you've made it through all that, here's the real question; What would cause the wrong OnClick method to fire? Am I correct in my educated guess that it has something to do with the Session authentication?
I would also appreciate some advice on where to take my troubleshooting from this point. I can post code snippets as necessary, I'm just not sure what would be relevant and given the volume of code I didn't want to just post it all.
Code Snippets:
The buttons:
Register Button:
<asp:Button ID="Button1" runat="server" onclick="RegisterUser" Text="Create Account" CssClass="btn btn w-lg btn-rounded btn-lg btn-custom waves-effect waves-light" />
Login Button:
<asp:Button ID="btnSubmit" runat="server" onclick="ValidateUser" Text="Sign In" CssClass="btn btn w-lg btn-rounded btn-lg btn-custom waves-effect waves-light" />
Outline of RegisterUser Method
protected void RegisterUser(object sender, EventArgs e)
{
/* Code that registers user with database if username doesn't exists */
}
Outline of ValidateUser Method
protected void ValidateUser(object sender, EventArgs e)
{
/* Code that validates user with the database and authenticates if valid. */
}
Please let me know if there is any more information that would be helpful to include and I'll update the question.
Thank you very much in advance.
UPDATE
I̶'̶v̶e̶ ̶f̶o̶u̶n̶d̶ ̶t̶h̶a̶t̶ ̶I̶'̶m̶ ̶a̶b̶l̶e̶ ̶t̶o̶ ̶r̶e̶p̶r̶o̶d̶u̶c̶e̶ ̶t̶h̶i̶s̶ ̶e̶r̶r̶o̶r̶ ̶1̶0̶0̶%̶ ̶w̶h̶e̶n̶ ̶r̶u̶n̶n̶i̶n̶g̶ ̶o̶n̶ ̶l̶o̶c̶a̶l̶h̶o̶s̶t̶ ̶a̶s̶ ̶o̶p̶p̶o̶s̶e̶d̶ ̶t̶o̶ ̶t̶h̶e̶ ̶d̶e̶v̶e̶l̶o̶p̶m̶e̶n̶t̶ ̶s̶e̶r̶v̶e̶r̶.̶
(Turns out this isn't the case)
Here's another odd behavior I seem to have stumbled upon. If I type out the user name and password, the RegisterUser method fires. However, if the username and password are filled by a password manager, the ValidateUser method is fired (Correct action).

Check your button declaration in your .aspx source.
If you have a 'runat=server' and onclick="RegisterUser", and you have an event handler in your code-behind, it will cause the event to be fired twice.
If so try to change this
<asp:Button ID="Button1" runat="server" onclick="RegisterUser"
Text="Create Account" CssClass="btn btn w-lg btn-rounded btn-lg btn-
custom waves-effect waves-light" />
To this
<asp:Button ID="Button1" runat="server" Text="Create Account"
CssClass="btn btn w-lg btn-rounded btn-lg btn-custom waves-effect
waves-light" />
Some others say that adding type="submit" has helped them out.
Another case might be that your event handler in the server side might be causing the event to be triggered twice.
For instance if you have:
Protected Sub RegisterUser_OnClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles RegisterUser_Click
'Do Something
End Sub
The Handles RegisterUser_Click might cause the event to be fired twice.
Nice explanation btw. Hope the best. Lets us know what was the issue. Best of luck.

Related

ASP.NET WebForms Confirm

I'm new to web programming with .NET.
I am developing a web page with webforms, and I want at a certain moment to programmatically show a modal window, for the user to accept or cancel, according to a question. Exactly what does the "confirm" function of JavaScript.
I tried to get it calling a JavaScript function:
Page.ClientScript.RegisterStartupScript (this.GetType (), "CallMyFunction", "MyFunction()", true);
But I need to do it without reloading the page, and I also need to control if the user has accepted or canceled and I do not know how to do it.
I've also tried getting it using the ModExPopupExtender control from DevExpress.
Can someone tell me a simple way to get what I want?
I can not understand how something so usual in web programming, and that PHP + javascript would not pose any problem can be so complicated.
All start in a one-button event on the code behind:
protected void btn1_Click(object sender, EventArgs e)
{
//I make a series of checks
//If certain conditions I want to show the confirm
//According to the user has chosen ok or cancel will perform a certain action
}
Onclientclick does not help me because before launching the "confirm" I have to do some checks on the server side.
Thank you very much.
You can use OnClientClick which is a property on most web controls.
I like to just bring up a simple confirm() dialog which executes the server code if the user clicks OK and does nothing if the user cancels the action:
<asp:Button runat="server" ID="btnSave" Click="btnSave_Click" Text="Save"
OnClientClick="return confirm('Are you sure you want to do this thing?');" />
You can do other things with it as well, but the key thing to remember is that anything you do in OnClientClick will happen before the page gets posted back to the server.
This is also perfectly valid:
<asp:Button runat="server" ID="btnSave"
OnClientClick="showModalConfirm('some message goes here');" ... />
<script>
function showModalConfirm(msg)
{
$(".modal .message").innerHtml(msg);
$(".modal").Show();
}
</script>
You can set the action that OnClientClick should perform in your codebehind in exactly the same way:
protected void Page_Load(object sender, EventArgs e)
{
btnSave.OnClientClick = "return confirm('Are you sure you want to do this thing?');";
}
You can use below code in c# to call javascript function. Below code will execute afterpostback() javascript function:
ClientScript.RegisterStartupScript(GetType(), Javascript, "javascript:afterpostback();", true);
And you can write code in javascript function to display any div or popup:
<script language="javascript" type="text/javascript">
function afterpostback() {
//Here you can write javascript to display div/modal
}
</script>
One way I've handled this previously was to have 2 buttons on the page. The first would be initially visible and labeled "Submit". The second would be initially hidden and labeled "Confirm". The "Submit" button would postback upon click and perform your server side checks/validation. If those checks failed, an appropriate error message would be displayed. If those checks passed, an appropriate "Please confirm your submission"-type message would be displayed, the "Submit" button would become hidden, and the second "Confirm" button would become visible. When that Confirm button was clicked, it would postback again and fully submit.
EDIT: I forgot to mention, there's a bit more to this that occurred to me after I initially posted. You'll have to protect the fields from being edited in the event the server-side verification is successful as you obviously don't want the user changing values and then clicking the Confirm button. That means disabling all the input controls - which could be a pain if you have a lot. You also have to give them a way to (intentionally) Edit in case the server side verification passes, you display the Confirmation, and they change their minds - so basically you'd need a third "Cancel/Edit"-type button that would put the form back in edit mode and show your initial Submit button.

onclick event is not fired by input buttons inside a user controls

I've updated my .Net web application to use Framework 4.5, after the update, all the input buttons (not asp:Buttons), have stopped firing the onclick javascript code, this is only happening on those buttons that are inside a user control (.ascx).
Just for the record, user controls are neither being loaded dinamically nor inside update panels.
My buttons look like this
<input id="cb" onClick="myfunc()" type="button" value="Close" />
My user controls are included to the page as follows
<cc:actionbar id="theActionBar" runat="server"></cc:actionbar>
and the javascript function, which is also included within the user control, is
function myfunc() {
if (confirm("Before closing, please make sure you saved any changes.\nAre you sure you want to close?") == true) {
__doPostBack('theActionBar:theClose', '');
}
}
this works just fine on Framework 3.5 and previous versions.
any idea why is this happening??? or how can I solve this?? I have tried several suggestions I've found over the internet and nothing seems to work.
Thanks in advance.
.
I can't see an obvious reason, but have you considered simplifying your approach to avoid the custom javascript and hard-coded postback event reference? You can get exactly the same behaviour with an ASP.NET button's OnClientClick property:
<asp:Button runat="server" ID="btnClose" Text="Close" OnClick="btnClose_Click" OnClientClick="return confirm('Before closing, please make sure you saved any changes.\nAre you sure you want to close?')" />
Returning false from the OnClientClick code or function prevents the postback.
Switching to this approach may be preferable and may even solve your issue if it's something to do with the postback event reference.

Is making an asp:Button control invisible enough to be sure users won't be able to click it?

I'm making a simple website that lists files from a certain folder. If the user has admin rights, the user can delete files by clicking the "Delete" button.
In my .aspx file, I have the following code:
<asp:Button runat="server" Text="Delete" OnCommand="FileList_Delete"
CommandArgument='<%#Eval("FilePath")%>' Visible='<%CurrentUserIsAdmin()%>' />
So the button will not be rendered if CurrentUserIsAdmin() returns false.
The button is rendered like this:
<input type="submit" name="ctl00$ctl00$MainContent$LocalMainContent$FileList$ctrl0$ctl17" value="Delete" />
My question is: Can I be sure that this method is safe against a known-code attack if the user modifies the webpage client-side aiming to click this invisible button? Or do I have to take precautions in the code-behind and verify the user's rights in the button-clicked event?
Yes, setting a button's Visible property to false is enough to prevent its Click and Command events from being raised, as long as you don't turn off the default WebForms security features.
You can easily test this by temporarily adding an always-visible <input> element to your .aspx with the same name as the rendered <asp:Button>:
<input type="submit"
name="ctl00$ctl00$MainContent$LocalMainContent$FileList$ctrl0$ctl17"
value="Fake Delete" />
Click the fake Delete button when the real Delete button is invisible. You should get an "Invalid postback or callback argument. Event validation is enabled..." exception.
Important notes:
Don't set a button's Visible property to false within an if (!IsPostBack) block because it's possible for an attacker to bypass that check. See this answer for more information.
ASP.NET event validation must be enabled (which it is by default). So don't turn it off by adding EnableEventValidation="False" to the #Page directive or <pages enableEventValidation="false" /> to Web.config.
Never ever ever disable view state validation by adding EnableViewStateMac="False" to the #Page directive or <pages enableViewStateMac="false" /> to Web.config. This would allow an attacker to tamper with the hidden __EVENTVALIDATION field and do other nasty things.
If you choose a derive a custom Button server control from the standard Button control, make sure you add the [SupportsEventValidation] attribute to the derived class.
If you choose to create a custom Button server control from scratch, call RegisterForEventValidation and ValidateEvent in the appropriate places.
They simply won't see the button or even 'recieve' it. Your server will not generate any button code sent to the person.
You have to think of it this way. The user never sees any asp code or is able to process it. They only receive html. You can further ensure this by looking at the html and seeing what has been generated.
So in that regard you are safe.
My question is: can I be sure that this method is safe against known-code attack if user modifies the webpage client-side aiming to click this invisible button? Or I have to make precautions in CodeBehind and verify user rights in button clicked event?
I personally would also put another piece of code in the click event. Verifying that click comes from the user who is authorized to click that button.
What you could also do is to add a button from code behind as this (Assuming you are putting this button into a panel called pnlButtons):
Button btnDeleteList = new Button();
btnDeleteList.Text = "Delete List";
btnDeleteList.Click += btnDeleteList_Click;
pnlButtons.Controls.Add(btnDeleteList);
In other words, if user is Admin - add a button, if user is not an admin - do not add. In this case you do not have to play around with visibility.
hope this helps.

OnServerClick event not firing on some page

In the website I'm working on, there is a bug I'm unable to figure out.
The bug is the following.
I have two different pages (with different functionality/controls). Both of them include the same page header that include a logout button.
<form id="Form1" method="post" runat="server">
<uc1:pageheader id="PageHeader1" title="XXXXX" runat="server"></uc1:pageheader>
<!-- page content goes here -->
</form>
The button is the following (located in pageHeader.ascx)
<INPUT type="button" value="Log out" id="btnLogout" name="btnLogout" runat="server" onserverclick="btnLogout_ServerClick">
With a server side function btnLogout_ServerClick that handle the disconnection.
In one of the page, the button is doing its role just fine.
In the other the btnLogout_ServerClick function is never reached.
I tried to put a breakpoint in the page_Load function of both pages. They both start with a first passage with the IsPostBack value set to True but after going through the loading of every control on the page, the first one end up in the log out function, whereas the other starts a new page_Load cycle with IsPostBack set to False.
There is no trace of error/exception on what could cause this behavior, if anyone could give a hand, either in giving a solution or providing a way to find the problem, that would be welcome.
And I know that I could try to remove every control and add one at a time to see if they prevent the button from working, but both pages have numerous control and it'd be nice if I could avoid that.
Use browser tools (IE dev tools, Firebug etc) to see if the posted data is the same in both cases. If there are any redirects check if other code is not doing redirect before the event is raised.
First thing I would check is the event handler for the button. Are you sure it is correctly registered ?
Possibly related to user control event handler lost on postback

Get the validationgroup that is used on a postback

I'm working with a legacy project in C# (.NET 2.0). In this project there are two validationgroups. One for custom login control and one for users to submit to a newsletter. The problem I ran into is that when a user submits to subscribe to a newsletter some custom code is triggered in the page_prerender() method which only should be triggered when a user tries to login.
I have been looking for a solution to recognize which of the two groups is used on postback so I can ignore the custom code when needed. My idea was to try and check which of the two validation groups is being used to validate. Unfortunately after spending a fruitless few hours on google I've not been able to find anything to let me know how to actually known which validationgroup is used when validating. Is there any way to find out?
<asp:Button ID="btn_newsletter"
runat="server"
Text="Verzend"
ValidationGroup="newsLetter"
meta:resourcekey="bnt_newsletter"
OnClick="handleNewsLetter"
CssClass="roundedButtonBig"
/>
<asp:Button ID="LoginButton"
runat="server"
CommandName="Login"
Text="Inloggen"
ValidationGroup="lgnUser"
meta:resourcekey="LoginButtonResource1"
CssClass="roundedButtonBig"
/>
The following code should only trigger when the LoginButton is pressed and it needs to be done on Pre_render(). Or alternatively pass the correct ValidationGroup (where now null is passed).
protected void Page_PreRender(object sender, EventArgs e)
{
//Register custom ValdiationErrorService added errors to JavaScript so they can be added into the popup.
ValidationErrorService.RegisterServerValidationMessageScript(Page, null);
}
to check which validation group is valid, call:
Page.Validate(“newLetter”);
then check
Page.IsValid;
this will return the value. Scott Gu has more on his blog
edit you are also wanting to know which button was clicked within the prerender event it sounds like as well. While you can't find that out from the parameters passed into the page prerender, you can rely on the button events occuring prior to the page_prerender event. within the aspx pages code behind, create a member variable. this variable will be used to denote if the prerender logic should be executed.
next, within the click events of the two buttons, set that local variable to denote if that button should fire the logic you want in the page_prerender event.
last, check your local variable within the page_prerender method, and encapsulate your logic within an if statement based upon your new member variable.
Happy Trails!

Categories