CSRF fix in aspx page - asp.net

I need the fix for CSRF flaw for aspx page. The code is like this -
ASPX -
<asp:Content runat='server'>
<asp:Panel runat='server'>
<table>
<tr>
<td>Username</td>
<td><asp:TextBox runat="server" ID="Username" autocomplete="off"></asp:TextBox></td>
</tr>
<tr>
<td>Password</td>
<td><asp:TextBox runat="server" ID="Password" TextMode="Password" autocomplete="off"></asp:TextBox></td>
</tr>
<tr>
<asp:Button ID="Submit" runat="server" Text="Submit"
OnClick="SubmitButton_Click" CssClass="Resizable" />
</tr>
</table>
</asp:Panel>
</asp:Content>
ASPX.cs -
protected void SubmitButton_Click(object sender, EventArgs e)
{
//Code here
}
Now while inserting <%# Html.AntiForgeryToken() %> at the top throws error "The server block is not well formed". So how should I proceed with the fix.

You're using webforms here. They already have anti-xsrf set up in the template of the master page (I think it's tucked in with all of the viewstate data).
So as long as you are using a master page then you needn't worry.
If you're not using a master page just build your own using session state, a hidden field and a guid. I've taken the below from http://willseitz-code.blogspot.com/2013/06/cross-site-request-forgery-for-web-forms.html
Your hiddenfield...
<asp:HiddenField ID="antiforgery" runat="server"/>
The code that does the work server side...
public static class AntiforgeryChecker
{
public static void Check(Page page, HiddenField antiforgery)
{
if (!page.IsPostBack)
{
Guid antiforgeryToken = Guid.NewGuid();
page.Session["AntiforgeryToken"] = antiforgeryToken;
antiforgery.Value = antiforgeryToken.ToString();
}
else
{
Guid stored = (Guid) page.Session["AntiforgeryToken"];
Guid sent = new Guid(antiforgery.Value);
if (sent != stored)
{
throw new SecurityException("XSRF Attack Detected!");
}
}
}
}
And finally the following in your Page_Load method in code behind...
AntiforgeryChecker.Check(this, antiforgery);

Related

Repeater causes postback of the whole page even if it's inside an update panel

I have an user control that contains an update panel with a repeater. The repeater has a button used to delete records.
The problem is when I press the delete button, and a record from the repeater gets deleted, a postback on the whole page is triggered. From my understanding, only the section inside the update panel should refresh.
I should also mention that on my master page I have a script manager with the property "EnablePartialRendering" set to true.
Can someone help me with this problem? Thanks in advance.
ASP file:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="ActivityFiles.ascx.cs" Inherits="Training.User_Controls.ActivityFiles" %>
<asp:Repeater ID="FilesRepeater" runat="server">
<HeaderTemplate>
<table class="table table-bordered">
<tr>
<td><b>Name</b></td>
<td><b>Description</b></td>
<td><b>Actions</b></td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<tr>
<td><%# Eval("Name")%></td>
<td><%# Eval("Description")%></td>
<td>
<asp:LinkButton ID="DownloadFile" runat="server" OnClick="DownloadFile_Click" Font-Size="Large"
file-path='<%# Eval("Url")%>'>
<span class="glyphicon glyphicon-floppy-disk text-info" aria-hidden="true"></span>
</asp:LinkButton>
<asp:LinkButton ID="DeleteFile" runat="server" OnClick="DeleteFile_Click" Font-Size="Large"
file-id='<%# Eval("Id") %>'
file-path='<%# Eval("Url") %>'>
<span class="glyphicon glyphicon-trash text-danger" aria-hidden="true"></span>
</asp:LinkButton>
</td>
</tr>
</ContentTemplate>
</asp:UpdatePanel>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
.cs File:
protected void Page_Load(object sender, EventArgs e)
{
activityId = (int)Context.Items["activityId"];
if ( ! IsPostBack && Visible)
{
if (activityId != 0)
{
LoadFiles();
}
}
}
private void LoadFiles()
{
DataTable files = DatabaseHelper.SelectAsDatatable(FilesQueries.GET_ACTIVITY_FILES, new Dictionary<string, object> {
{ "activityId", activityId }
});
FilesRepeater.DataSource = files;
FilesRepeater.DataBind();
if (files.Rows.Count == 0)
{
FilesRepeater.Visible = false;
NoRecords.Visible = true;
}
}
protected void DeleteFile_Click(object sender, EventArgs e)
{
// TODO: modify this function to work only with the fild id
LinkButton deleteButton = (LinkButton)sender;
string fileId = deleteButton.Attributes["file-id"];
string filePath = deleteButton.Attributes["file-path"];
DatabaseHelper.ExecuteNonQuery(FilesQueries.DELETE_FILE, new Dictionary<string, Object>() {
{ "#fileId",fileId },
});
//delete file from disk
string path = Server.MapPath(filePath);
FileInfo file = new FileInfo(path);
if (file.Exists)
{
file.Delete();
}
LoadFiles();
}
Found the solution on another stackoverflow post (See Eugene S answer)
You have to manually add you control to Script Manager. You should do that inside File Repeater's Item created event. Good luck.

Unable to pass data from one content page to another using master page

I'm trying to make an asp webform that posts data to another webform.
I've made two separate projects, one that uses master page and one the doesn't.
Senario:
WebForm1.aspx has two text boxes and a submit button
<table>
<tr>
<td >Name:</td>
<td >
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</td>
<td class="auto-style1"></td>
</tr>
<tr>
<td>Id:</td>
<td>
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
</td>
<td> </td>
</tr>
<tr>
<td> </td>
<td>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
</td>
<td> </td>
</tr>
</table>
WebForm2.aspx.cs has two labels which should display the data received from WebForm1.aspx
Page prevPage = this.PreviousPage;
if (prevPage != null)
{
Label1.Text = ((TextBox)prevPage.FindControl("TextBox1")).Text;
Label2.Text = ((TextBox)prevPage.FindControl("TextBox2")).Text;
}
Case 1: [Posting without master page]
The data is posted normally.
Case 2: [Posting with master page]
I get NullReferenceException.
So I broke down the code.
Page prevPage = this.PreviousPage;
if (prevPage != null)
{
ControlCollection collec = prevPage.Controls;
Control ctrl= prevPage.FindControl("TextBox1");
TextBox txtbx = (TextBox)ctrl;
Label1.Text = txtbx.Text; //Exception raised here
Label2.Text = ((TextBox)prevPage.FindControl("TextBox2")).Text;
}
While debugging:
I executed "collec.Count" in the Immediate Window.
Case 1: [Posting without master page]
collec.Count returned 5
Case 2: [Posting with master page]
collec.Count returned 1 [ WHY? ]
Later,
I tried to pass data using public properties
WebForm1.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
Server.Transfer("WebForm2.aspx");
}
public string Name { get { return TextBox1.Text; } }
public string ID { get { return TextBox2.Text; } }
WebForm2.aspx.cs
WebForm1 prevPage = (WebForm1)this.PreviousPage;
if (prevPage != null)
{
ControlCollection c = prevPage.Controls;
Label1.Text = prevPage.Name;
Label2.Text = prevPage.ID;
}
and now it works correctly, even with master page.
So could anybody explain me whats going on and why posting from one content page to another content page with master giving me NullReferenceException ?
First you must look in the Content Placeholder of the submitting page
Therefore, the code would look more like this:
ContentPlaceHolder placeHolder = (ContentPlaceHolder)PreviousPage.Master.FindControl("ContentPlaceHolder1");
TextBox txt1 = (TextBox)placeHolder.FindControl("TextBox1");
When you are using master page a TextBox with an id of TextBox1 inside a Content control tied to ContentPlaceHolder1 will have its id attribute extended like this:
<input name="ctl00$ContentPlaceHolder1$TextBox1" type="text" id="ContentPlaceHolder1_TextBox1" />
But when you are not using Master page there is no 'ContentPlaceHolder' so TextBox1 will rendered like this:
<input name="TextBox1" type="text" id="TextBox1" />

Retrieve value for selected radiobutton in ListView asp.net

I would like to send a Guid which should be associated with each radio button as eventargs when the user clicks checkout. I was able to achieve this functionality with just a RadioButtonList but I cannot use that here as the rest of the fields are pulled from the database.
There are numerous questions dealing with this type of topic but I could not find one that addresses exactly what I am trying to achieve.
I have the below list
<asp:Content ID="SubscriptionContent" ContentPlaceHolderID="MainContent" ViewStateMode="Enabled" runat="server">
<asp:Panel ID="SubscriptionPanel" CssClass="shopping-cart" ViewStateMode="Enabled" runat="server">
<asp:ListView ID="NewSubscription" runat="server">
<LayoutTemplate>
<table class="table">
<thead>
<th>Select a Subscription</th>
<th>Subscription Level
</th>
<th>Description
</th>
<th>Price
</th>
</thead>
<tbody>
<tr id="itemPlaceholder" runat="server" />
</tbody>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td class="description"><asp:RadioButton ID="SubscriptionLevel" GroupName="SubscriptionRadio" Text='<%# Eval("SubscriptionLevel") %>' runat="server" /></td>
<td class="description"><asp:Label ID="Details" Text='<%# Eval("Details") %>' runat="server"></asp:Label></td>
<td class="price"><asp:Label runat="server" Text='<%# Eval("Price", "{0:C2}") %>'></asp:Label></td>
<asp:TextBox ID="Id" runat="server" Visible="false" Text='<%# Eval("Id") %>' />
</tr>
</ItemTemplate>
</asp:ListView>
<asp:Button ID="Subscribe" CssClass="btn btn-primary" runat="server" Text="<%$ Snippet: Ecommerce/ShoppingCart/CheckoutButtonLabel, Checkout %>" OnClick="BuySubscription" />
<script type="text/javascript">
$(document).ready(function () {
$("input:radio").attr('name', 'SubscriptionRadio');//Override the naming that asp does
});
</script>
</asp:Panel>
</asp:Content>
I am thinking that if I could update a hidden field with the corresponding guid value for each radio button and submit that when the user triggers BuySubscription. I am not sure how to do this though. Ultimately I just want the user to be able to select one of the subscription options and pass that guid back to the function.
Thank you in advance for any input.
The first problem you're going to run into is that ASP.NET gives each <input type="radio" /> a different name, because it's in a different NamingContainer.
You've added some script to try to work around that by changing the name attribute on the client. Unfortunately, this won't work. When you post the form back to the server, ASP.NET will still be looking for a value using the generated name, which won't exist.
The quick and dirty solution would be to update your script to copy the value from the hidden TextBox to the value attribute of the radiobutton. You would then have to use Request.Form["SubscriptionRadio"] to retrieve the value of the selected option:
<ItemTemplate>
<tr>
<td class="description">
<asp:RadioButton ID="SubscriptionLevel" runat="server"
GroupName="SubscriptionRadio"
Text='<%# Eval("SubscriptionLevel") %>'
/>
<%-- NB: Can't set Visible="False", otherwise it's not rendered: --%>
<asp:TextBox ID="Id" runat="server"
Style="display:none;"
Text='<%# Eval("Id") %>'
/>
</td>
...
</tr>
</ItemTemplate>
...
<script>
$(document).ready(function() {
$("input:radio").each(function(){
var me = $(this);
var id = me.closest("tr").find("input[name$=Id]").val();
me.attr("value", id);
me.attr('name', 'SubscriptionRadio');
});
});
</script>
Alternatively, you could use a custom RadioButton control which works within a data-bound control. I posted a simple example back in 2012: https://stackoverflow.com/a/13271444/124386
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SiteControls
{
[ToolboxData("<{0}:ListRadioButton runat=\"server\" />")]
public class ListRadioButton : RadioButton
{
private static readonly FieldInfo UniqueGroupNameField = FindUniqueGroupNameField();
private string _uniqueGroupName;
private static FieldInfo FindUniqueGroupNameField()
{
return typeof(RadioButton).GetField("_uniqueGroupName",
BindingFlags.NonPublic | BindingFlags.Instance);
}
public string Value
{
get { return Attributes["value"]; }
set { Attributes["value"] = value; }
}
protected virtual string CreateUniqueGroupName()
{
string result = GroupName;
if (string.IsNullOrEmpty(result))
{
result = ID;
}
if (string.IsNullOrEmpty(result))
{
result = UniqueID;
}
else
{
Control container = NamingContainer;
if (container != null)
{
if (container is IDataItemContainer)
{
container = container.NamingContainer ?? container;
}
result = container.UniqueID + base.IdSeparator + result;
}
else
{
string uniqueID = UniqueID;
if (!string.IsNullOrEmpty(uniqueID))
{
int index = uniqueID.LastIndexOf(base.IdSeparator);
if (index != -1)
{
result = uniqueID.Substring(0, 1 + index) + result;
}
}
}
}
return result;
}
private void EnsureUniqueGroupName()
{
if (_uniqueGroupName == null)
{
string value = CreateUniqueGroupName();
if (UniqueGroupNameField != null) UniqueGroupNameField.SetValue(this, value);
_uniqueGroupName = value;
value = base.Attributes["value"];
if (string.IsNullOrEmpty(value))
{
base.Attributes["value"] = UniqueID;
}
}
}
protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
EnsureUniqueGroupName();
return base.LoadPostData(postDataKey, postCollection);
}
protected override void Render(HtmlTextWriter writer)
{
EnsureUniqueGroupName();
base.Render(writer);
}
}
}
You can either register the control in the page markup:
<%# Register tagPrefix="site" namespace="SiteControls" %>
or in the web.config file:
<?xml version="1.0"?>
<configuration>
<system.web>
<pages>
<controls>
<add
tagPrefix="site"
namespace="SiteControls"
/>
</controls>
</pages>
</system.web>
</configuration>
With that in place, you can lose the script and the hidden TextBox:
<ItemTemplate>
<tr>
<td class="description"><site:ListRadioButton ID="SubscriptionLevel" runat="server"
GroupName="SubscriptionRadio"
Text='<%# Eval("SubscriptionLevel") %>'
Value='<%# Eval("Id") %>'
/></td>
...
To find the selected item, you would then need to loop through the ListView's Items, find the RadioButton control, and look at the Checked property:
ListRadioButton selectedItem = NewSubscription.Items
.Select(item => (ListRadioButton)item.FindControl("SubscriptionLevel"))
.FirstOrDefault(radio => radio != null && radio.Checked);
string selectedValue = (selectedItem == null) ? null : selectedItem.Value;

Getting the password value from a Login control in ASP.net page

I've got my login control in my site Master page:
<AnonymousTemplate>
<asp:Login runat="server" OnLoggedIn="Login1_LoggedIn" CssClass="LoginForm" />
</AnonymousTemplate>
In the code-behind page of this Master page I am trying to capture the value entered in the Password form field. The code works in the homepage, but doesn't work in all other pages!
The code used is:
Page page = (Page)HttpContext.Current.Handler;
TextBox tbtemp = (TextBox)page.FindControl("Password");
_password = tbtemp.ToString();
On the homepage, looking at the trace the value of the Text box is:
ctl00$LoginView1$ctl01$Password
On the other pages the value is:
ctl00$ctl00$LoginView1$ctl01$Password
The error that is thrown on the non-homepage pages is:
due to Exception of type
'System.Web.HttpUnhandledException'
was thrown.
Any ideas how to access the value?
Update:
My login form looks like this:
<asp:loginview id="LoginView1" runat="server">
<LoggedInTemplate >
<asp:LoginStatus ID="LoginStatus1" runat="server" OnLoggedOut="LoginStatus1_LoggedOut" /> <%--Displays the text logged in--%>
<asp:LoginName ID="LoginName1" runat="server" /> <%--displays the username--%>
</LoggedInTemplate>
<AnonymousTemplate>
<asp:Login RememberMeSet="true" ID="loginForm" runat="server" OnLoggedIn="Login1_LoggedIn" CssClass="LoginForm" >
<LayoutTemplate>
<table>
<tr>
<td><asp:Label ID="UserNameLabel" runat="server">Username:</asp:Label></td>
<td><asp:TextBox ID="UserName" runat="server" /></td>
</tr>
<tr>
<td><asp:Label ID="PasswordLabel" runat="server" >Password:</asp:Label></td>
<td><asp:TextBox ID="Password" runat="server" TextMode="Password" /></td>
</tr>
<tr>
<td><asp:Label ID="RememberMeLabel" runat="server" >Remember me: </asp:Label></td>
<td><asp:CheckBox ID="RememberMe" runat="server" /></td>
</tr>
<tr>
<td> </td>
<td> <asp:Button ID="LoginButton" runat="server" CommandName="Login" Text="Log In" /></td>
</tr>
</table>
</LayoutTemplate>
</asp:Login>
</AnonymousTemplate>
</asp:loginview>
Why are you getting the password control explicitly? Did you try just getting the password directly from
string password = LoginCtrl.Password //Assuming LoginCtrl is the Id of your control.
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.login.aspx
string username = ((Login)this.LoginView.FindControl("LoginControl")).UserName;
// Search recursively a control sub-tree for a specific control.
// It searches every control in the sub-tree, so it potentially
// could be optimized to search only, say, INamingContainers.
public Control FindControlRecursive(Control root, string id)
{
if (root.ID == id) return root;
foreach (Control c in root.Controls)
{
var ctlFound = FindControlRecursive(c, id);
if (((ctlFound != null))) return ctlFound;
}
return null;
}
public T FindControl<T>(string id) where T : Control
{
return FindControl<T>(Page, id);
}
public static T FindControl<T>(Control startingControl, string id) where T : Control
{
T found = null;
foreach (Control activeControl in startingControl.Controls)
{
found = activeControl as T;
if (found == null)
{
found = FindControl<T>(activeControl, id);
}
else if (string.Compare(id, found.ID, true) != 0)
{
found = null;
}
if (found != null)
{
break;
}
}
return found;
}
}

Problem loading states of server controls residing in user control

I have user control which contains two text boxes and two dropdown list. I am loading this control first time on page_load event programatically. After that on each button click event of "Add New" button, controls are added dynamically but when this happens, previously loaded controls are showing all server controls(which are inside user control) empty. How can i retain the state of these controls?
My user control code is as shown below.
<%# Control Language="C#" AutoEventWireup="true" CodeFile="qualificationControl.ascx.cs" Inherits="qualificationControl" %>
<style type="text/css">
.RowHeight
{
height: 30px;
}
</style>
<table width="100%">
<tr>
<td class="RowHeight" width="20%">
Course Name</td>
<td width="20%">
<asp:DropDownList ID="courseList" runat="server" Width="100px">
</asp:DropDownList>
</td>
<td width="20%">
Year of Passing</td>
<td width="*">
<asp:DropDownList ID="yearList" runat="server" Width="100px">
<asp:ListItem Value="0">2005</asp:ListItem>
<asp:ListItem Value="1">2006</asp:ListItem>
<asp:ListItem Value="2">2007</asp:ListItem>
<asp:ListItem Value="3">2008</asp:ListItem>
<asp:ListItem Value="4">2009</asp:ListItem>
</asp:DropDownList>
</td>
</tr>
<tr>
<td class="RowHeight" width="20%">
Percentage</td>
<td colspan="3">
<asp:TextBox ID="percentageBox" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td class="RowHeight" width="20%">
Instutitute Name</td>
<td colspan="3">
<asp:TextBox ID="InstiNameBox" runat="server" Width="350px"></asp:TextBox>
</td>
</tr>
</table>
and that of aspx.cs page is as below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
public partial class AppplicationForm2 : System.Web.UI.Page
{
Control qualificationControl;
UserControl usrqualificationControl = new UserControl();
int CtrlID = 0;
protected void Page_Load(object sender, EventArgs e)
{
qualificationControl = usrqualificationControl.LoadControl("~/control/qualificationControl.ascx");
if (!IsPostBack)
{
ArrayList CtrlList = new ArrayList();
qualificationControl.ID = CtrlID.ToString();
UserCtrlHolder.Controls.Add(qualificationControl);
CtrlList.Add(qualificationControl);
Session.Add("qualiControl", CtrlList);
}
//else
}
protected void addQualificationBtn_Click(object sender, EventArgs e)
{
ArrayList CtrlList = null;
ArrayList CourseList = new ArrayList();
ArrayList YearList = new ArrayList();
ArrayList percentageList = new ArrayList();
ArrayList InstituteList = new ArrayList();
if (Session["qualiControl"] != null)
{
CtrlList = (ArrayList)Session["qualicontrol"];
}
qualificationControl.ID = CtrlList.Count.ToString();
CtrlList.Add(qualificationControl);
for (int i = 0; i < CtrlList.Count; i++)
{
UserCtrlHolder.Controls.Add((Control)CtrlList[i]);
}
}
private void RestoreUserControl(ArrayList CourseList,ArrayList YearList,ArrayList PercentageList,ArrayList InstiNameList,ArrayList CtrlList)
{
for (int CtrlCnt = 0; CtrlCnt < CtrlList.Count - 1; CtrlCnt++)
{
Control userControl = (Control)UserCtrlHolder.FindControl(CtrlID.ToString());
DropDownList dlCourseList = (DropDownList)userControl.FindControl("courseList");
DropDownList dlYearList = (DropDownList)userControl.FindControl("yearList");
TextBox percentageBox = (TextBox)userControl.FindControl("percentageBox");
TextBox InstiNameBox = (TextBox)userControl.FindControl("InstiNameBox");
dlCourseList.ClearSelection();
dlYearList.ClearSelection();
dlCourseList.Items.FindByText(CourseList[CtrlCnt].ToString()).Selected = true;
dlYearList.Items.FindByText(CourseList[CtrlCnt].ToString()).Selected = true;
percentageBox.Text = PercentageList[CtrlCnt].ToString();
InstiNameBox.Text = PercentageList[CtrlCnt].ToString();
}
}
}
Use Page_Init
Using Page_Load event for dynamic user control loading is too late because view state has already been loaded. Hence your controls are always rendered empty. Try adding your user control in Page_Init event instead. View state gets loaded just after this event which makes sure your dynamic controls should+++ be populated with previous state.
Note +++: If you add dynamic controls deterministically everything will be fine, but if you have non-deterministic processing your controls will have different IDs during page life hence view state will fail to load on each postback. You shouldn't have any problems with code you've provided.
http://www.google.com.tw/search?hl=en&safe=off&q=asp.net+add+control+dynamically&aq=1&aqi=g10&aql=&oq=asp.net+add+control
there are a ton of articles about adding controls dynamically, find one that suits you

Resources