Sanitising ASP.NET input (allowing angle brackets) - c#

I have read about customising input validation for ASP.NET requests to avoid the dreaded "a potentially dangerous value was detected". I'm using the following code to allow angled brackets to pass validation.
public class RequestValidator : System.Web.Util.RequestValidator {
protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex) {
validationFailureIndex = 0;
switch (requestValidationSource) {
case RequestValidationSource.Form:
if (control is CustomTextBox) { // How can I get the control?
// allow angle brackets to pass validation
value = value.Replace("<", "<").Replace(">", ">");
}
break;
}
return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
}
}
Now that I'm allowing these potentially dangerous values through the validation filter I'd like to be sure that they're being properly handled. This is a Web Forms environment so I thought I'd create a CustomTextBox control, override the Text property and HtmlEncode the string.
As you can see from the comment in the code above, I'd like to restrict my RequestValidator so that it only allows 'dangerous' values to pass validation if I can be sure they're going to be handled by my CustomTextBox. How can I get a reference to the Control when all we have to go on is the value and the collectionKey?

The validation of the Form Keys happen even before the Page PreInit event. There are no controls created at that time.
I think your best chance would be holding to a collection of UniqueIDs of all CustomTextBox instances that exists on the page currently. Having that collection, you could check if the form key being validated exists on the collection, meaning that it is in fact a CustomTextBox.
This collection could be managed inside the CustomTextBox control and saved on the Session or Application Cache.

I would suggest to explicitly set ValidateRequestMode property to ValidateRequestMode.Disabled in your custom control constructor and override Text property (or whatever property or you are using to store value) getter and there return sanitized value based on your specific scenario.

Related

Initializing class member in UserControl

Class is derived from Control in Asp.Net C#.
Public class member is defined as:
public bool isPresent = true;
Then in Render method check is performed :
if (isPresent)
doSomething;
On a form this field is set to false:
<c:CustomControl id="CustomControl1" isPresent="false">
When this code is executed locally from VS, everything is fine. Being deployed to the server, however, throws exception for the line with check for "if (isPresent)", saying that object reference is not set.
At the same time, if this line is changed to be "if (isPresent == true)", everything is fine both locally and on the server.
Is setting of value for class member of the Control different when run from VS and from IIS? Is it initialized in IIS before comparison operation, and not before implicit check?
UPDATE: as has been correctly pointed, this variable is a field, not a property. There is no other class member (and no property with same name).
UPDATE2: in addition, if check for value being not null is added, there is no exception anymore. Can it be the case that object initializer sets value of the field in case of explicit comparison operation?
if (isPresent == null)
return;
if (isPresent)
doSomething;
When creating user controls, the most advisable manner to store property values is in the View State, as follows:
public bool IsPresent
{
get
{
bool isPresent = false;
if (ViewState["IsPresent"] != null)
{
isPresent = (bool) ViewState["IsPresent"];
}
return isPresent;
}
set
{
ViewState["IsPresent"] = value;
}
}
Then, the control would be declared as follows (Note that the IsPresent starts with Upper I):
<c:CustomControl id="CustomControl1" IsPresent="false">
Whenever storing data on controls, keep in mind that they must be persisted on the page. If you simply declare a variable, there is no guarantee that the data will hold between requests. The only manner to make sure the data is persisted, is to save it in the View State. You can find support to these statements here and here.
The question of why the behavior changes in the IIS and Visual Studio may be not relevant here because simply declaring a variable, as stated above, provides no assurance at all that the data will be saved.
Regarding the Property being a getter/setter, note that it must be declared as shown above, in order to the property to be recognized by the ASPX page.

Custom handling of invalid character inputs

Here's the scenario. I have a textbox on the UI which is bound to a double property. If a character, say a '#' is typed in the textbox, the WPF validation is not enough for the application. I need to display a custom message and also disable some controls from the code. (These controls to be disabled are not part of the xaml.) As of now, the only way I could think of to do this is to bind the textbox to a string property and use the TryParse method. However, this will be a huge inconvenience. Is there a way to get the notification that an invalid character has been entered, without having to change the property to the string type?
well i use the "string" solution in my viewmodel. works best with IDataErrorInfo and binding.
but sometimes i also use a InputMaskbehavior for my Textboxe. so the user can just input characters wich is defined for the inputmask.
If you are using the MVVM pattern then you probably should have a string property in your ViewModel as this is what is entered on a Textbox. Even when you need the double for your model you have a string on your view. Then you can do whatever validation you need on the string property. Something like:
public string TextProperty
{
get
{
return _textProperty;
}
set
{
if (_textProperty != value)
{
_doubleProperty = this.TransformAndValidateString(value);
_textProperty = value;
}
}
}
Regarding disabling controls when an error is present look here:
IDataErrorInfo

Binding not refresing when I set the variable in the setter

I have a text bound to a property as follows
The user is expected to type in a File Name. Sometimes however users may type in invalid characters. So my backing property in the View Model looks as shown below
private string outputFileName;
public string OutputFileName
{
get
{
return outputFileName;
}
set
{
string temp = value;
if (true == IsValidFileName(temp))// this function uses Path.Getinvalidfilechars
{
outputFileName = value;
}
else
{
MessageBox.Show(string.Format("{0} contains one or more invalid characters
for a file Name",temp));
}
base.OnPropertyChanged("OutputFileName");
}
}
Here is the problem, the text box still shows the invalid char. why is the OnPropertyChanged not causing the text in the text box to go back to the old value without the invalid char.
How can I get that behaviour
In the else statement, the backing field for OutputFileName is not being assigned a different value. If you want to revert back to the previous value, then save that in another variable and update the backing field in the else statement and then the property changed event will change the UI with the old value. Although, I don't think this is very good user experience.
A better solution would to be use some validators and inform the user that the input needs to be corrected, rather than just reverting the value back to the previous value.
Google up "wpf validation" or start with this SO question: WPF Data Binding and Validation Rules Best Practices
What is the base class of your class that defines the OutputFileName? That class' OnPropertyChange method seems to check if the property value really changed before firing the PropertyChanged event. I tried your example with a class that directly implements INotifyPropertyChanged and does
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("OutputFileName"));
}
and that works as you expect. Although i agree with Marc, showing a MessageBox from a property setter is rather uncommon.

Asp Composite control child control (radiobutton) losing checked value

I am working on a quiz control in asp.net with dynamically created questions and options.
The main control is basically a container to hold all of the questions.
In design view users can add questions through a custom Collection Editor.
Everytime i add a question to the collection editor list it generates a question tag for me.
Inside each question object is a label and a n amount of Option objects that inherit the Radiobutton Control. Each of these Option objects in turn represent a option the user can select for each question.
This all works except i am now at the part where i want to be able to read the Checked value of each radiobutton. When i want to implement this quiz inside a page and check the questions i want to put a button in this page and call the following function that is inside the control:
$
public String checkQuestions()
{
if (questions != null)
{
foreach (Question question in questions)
{
options = question.readOptions();
int i = 0;
foreach (Option option in options)
{
testLabel.Text = option.Checked.ToString(); // test purposes only
}
}
}
return errors;
}
However once i select a radiobutton and click on the submit button the Checked value will always turn out false for all of the options.
Basically it is losing its checked value after a Postback and i am just stuck in trying to solve it.
Would appreciate it if anyone could point me in the right direction.
At a first glance, there are two things I'd check. Firstly, make sure you're implementing IPostBackDataHandler. this requires you to implement two methods, LoadPostData and RaisePostDataChangedEvent. At my first guess, the first one is probably the source of your problem.
Handling postback manually
LoadPostData takes a string postDataKey and a NameValueCollection postCollection and returns a bool indicating whether or not the value has changed as a result of the postback. You don't need to implement this the way .Net originally intends, for example I created a control that held several radio buttons (that for reasons that aren't important here couldn't simply be a RadioButtonList control) and so made sure they were all named by a property string GroupName and inspected the postCollection for that GroupName:
public bool LoadPostData(string postDataKey,
System.Collections.Specialized.NameValueCollection postCollection)
{
bool oldValue = _isChecked;
postCollection = HttpContext.Current.Request.Form; // See note below
_isChecked = (postCollection[this.GroupName] == this.Text);
return oldValue == _isChecked;
}
You'll notice that I'm redefining the postCollection here; this is because postCollection only contains a subset of the HttpRequest.Form corresponding to what ASP.Net thinks your control should care about. As you're also building a composite control here, you probably want to do the same.
Don't worry if this doesn't work first time round; it's worth stepping through what gets passed into this method in debug mode (or outputting things to the HttpContext.Trace, which I often find easier) to see why your code isn't quite what you need.
A quick caveat
One last thing: LoadPostData is only called if the posted form contains a field with a name which matches the UniqueID of your control. As your control is a composite control, you might want to cowboy this slightly, like so:
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
writer.WriteBeginTag("input");
writer.WriteAttribute("type", "hidden");
writer.WriteAttribute("name", this.UniqueID);
writer.WriteAttribute("value", "post");
writer.Write(" />");
}
It's a dirty hack, but it'll work ;o)
Handling viewstate manually
If handling the postback manually doesn't solve your problem, it might be that you need to mess with the viewstate of your control. Don't worry, this is nowhere near as scary as it seems, provided you follow a few simple rules.
To handle your viewstate manually, you just need to override two methods called, obviously enough, LoadViewState and SaveViewState. The first takes an object of viewstate to inflate and the other returns that same object structure. If you make your SaveViewState override return something containing the structure you need to save all the important properties that need persisting, then you just inflate it again in your LoadViewState method.
Here's where the first of the cunning tricks comes up. There are certain datatypes that you should use for saving viewstate and you should never use any other type (because other types are stored really inefficiently). The types that will probably be most useful to you are System.Web.UI.Pair, System.Web.UI.Triplet and our old friends System.Collections.ArrayList and System.Collections.Hashtable. Pairs and Triplets simply store two or three values of type object; ArrayLists are effectively a List<object>.
I'd guess that, in your circumstance, you probably want to store either (1) an ArrayList of boolean flags, storing the "checkedness" of your radiobuttons or (2) an ArrayList of strings or ints, storing the IDs or index of the checked radiobuttons.
In the control I mentioned earlier, I just needed to store the checkedness and the Text property, so my LoadViewState and SaveViewState methods looked like this:
protected override void LoadViewState(object savedState)
{
Pair state = savedState as Pair;
if (state != null)
{
_isChecked = state.First as Nullable<bool> ?? false;
this.Text = state.Second as string;
}
}
protected override object SaveViewState()
{
return new Pair(_isChecked, this.Text);
}
Again, if this doesn't work first time, you almost certainly want to step through the code or throw things into the Trace. Importantly, you probably want to avoid throwing Exceptions from these methods, in case your viewstate is corrupt or non-existent or something.
Further reading on viewstate
There are a couple of very useful articles I keep bookmarked for when I'm messing with viewstate. The first one explains about why you should only store certain types in the viewstate (like using ArrayList and Hashtable, rather than List<T> and Dictionary<TKey, TValue>) and the second is a good in-depth explanation of how all this viewstate stuff actually works.
Don't let the BinaryFormatter get at it!
Truly understanding ViewState
I hope all this helps resolve your problem.

Validation errors prevent the property setter being called

I am looking for a simple solution to the following problem:
I am using a simple TextBox control with the Text property bound to a property in the code behind. Additionally I am using a validation rule to notify the user of malformed input.
... error display style here ...
Now after entering valid data into the TextBox the user can hit a button to send the data. When clicking the button the data from the bound property UserName in the code behind is evaluated and sent.
The problem is that a user can enter valid data into the TextBox and this will be set in the property UserName. If the user then decides to change the text in the TextBox and the data becomes invalid, the setter of the property UserName is not called after the failed validation.
This means that the last valid data remains in the property UserName, while the TextBox display the invalid data with the error indicator. If the user then clicks on the button to send the data, the last valid data will be sent instead of the current TextBox content.
I know I could deactivate the button if the data is invalid and in fact I do, but the method is called in the setter of UserName. And if that is not called after a failed validation the button stays enabled.
So the question is: How do I enable calling of the property setter after a failed validation?
You could set the ValidationRule.ValidationStep property for your validation rules to ValidationStep.UpdatedValue. This first updates the source, and then performs validation. That means, your property setter should be called even though your validation fails. Note that this property is only available from .NET 3.5 SP1 upwards. For more details, see this blog post (paragraph "How do I use it? (Part 1)").
How I handle this in my view model classes:
public class MyViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private Dictionary<string, string> _Errors = new Dictionary<string, string>();
public object SomeProperty
{
get { return _SomeProperty; }
set
{
if (value != _SomeProperty && !ValidationError("SomeProperty", value))
_SomeProperty = value;
OnPropertyChanged("SomeProperty");
}
}
}
private bool ValidationError(string propertyName, object value)
{
// I usually have a Dictionary<string, Func<object, string>> that maps property
// names to validation functions; the functions return null if the property
// is valid and an error message if not. You can embed the validation logic
// in the property setters, of course, but breaking them out as separate methods
// eases testing.
_Errors[propertyName] = _ValidationMethods[propertyName](value);
OnPropertyChanged("IsValid");
}
public bool IsValid
{
get { return !(_Errors.Where(x => x.Value != null).Any()));
}
public string this[string propertyName]
{
get
{
return (_Errors.ContainsKey(propertyName))
? _Errors[propertyName]
: null;
}
}
}
It's a little awkward to get this all set up at first, but once you've done it, you have a simple and straightforward way to report validation errors to the UI (via the DataErrorValidationRule), a straightforward way to know whether any given property is valid or not (check _Errors), and an IsValid property that tells you whether or not the whole view model is valid. (Also, you can extend the IsValid property to handle the case where all the properties of the view model are valid but the view model itself is not, e.g. two mutually exclusive flags are both set.) And as long as you make them internal, the validation methods can be unit tested via NUnit or whatever.
I should add that the above code is off the top of my head and may or may not work as written - my actual working code is in a base class and has a lot of other things baked into it that would just be confusing.

Categories

Resources