Fixings Cross Site Scripting (Reflected) in ASP.Net MVC - asp.net-mvc

I have been using the Zed Attack Proxy (ZAP) to test a new application being developed. The App is ASP.NET MVC4 based using the standard HTML helpers where ever possible.
ZAP has identified the following alert:
Cross Site Scripting (Reflected)
GET: localhost:65227/CashReceipt?SearchText=javascript%3Aalert%281%29%3B
On this page we have a list of receipts and a search box whereby a user can search by receipt number.
When this page is called using the link above, the following Razor builds the relevant part of the page:
#using (Html.BeginForm("Index", "CashReceipt", FormMethod.Get, new { #class = "form-inline", #role = "form" }))
{
<div class="form-group">
<label class="hidden-label" for="SearchText">Search For</label>
#Html.TextBoxFor(m => m.SearchText, new { #class = "form-control input-lg", #placeholder = "Receipt Number" })
</div>
<input type="submit" value="Search" class="btn btn-primary btn-lg" />
}
the HTML generated is:
<input class="form-control input-lg" id="SearchText" name="SearchText" placeholder="Receipt Number" type="text" value="javascript:alert(1);" />
The page rendered appears as:
This does not result in an actual alert box being displayed within the browser, just the text is reflected back.
Is this an XSS issue that needs to be resolved? If so, how?

No it is not an XSS issue since the javascript alert is not executed. Razor Html helpers properly encode and decode text to stop this from happening by default.

Related

Duplicated ID in ManageLogin.cshtml built-in template

I am using the built-in template which comes with ASP.NET MVC 4. The View which is causing problem is: ManageLogins.cshtml
This is how the output looks like:
So, this particular user has connected both Google and Facebook external IDs to his account:
And this is the Built in MS Template which produces the above code (I have changed the appearance a bit, but the code is the same)
#foreach (var account in Model.CurrentLogins)
{
<div class="form-row">
#using (Html.BeginForm("RemoveLogin", "Manage"))
{
#Html.AntiForgeryToken()
<div>
#Html.Hidden("loginProvider", account.LoginProvider)
#Html.Hidden("providerKey", account.ProviderKey)
<input type="submit" class="btn btn-default" value="Remove" title="Remove this #account.LoginProvider login from your account" />
</div>
}
</div>
}
The problem is that this code generates 2 inputs with id=loginProvider, and this gives me the browser error:
How can solve this problem?
Since model binding occurs on name and not id, I decided to remove the id from the hidden field and just use the name attribute:
#using (Html.BeginForm("RemoveLogin", "Manage", FormMethod.Post, new { #class = "inline-form float-right" }))
{
#Html.AntiForgeryToken()
<div>
<input type="hidden" name="LoginProvider" value="#Model.LoginProvider" class="d-none login-provider" />
<input type="hidden" name="ProviderKey" value="#Model" class="d-none provider-key" />
<input type="submit" class="btn btn-default" value="Remove" title="Remove this #account.LoginProvider login from your account" />
</div>
}
You can use an overload of the helper that allows you to provide htmlAttributes.
e.g.
for (int i = 0; i < 3; i++)
{
#Html.Hidden("foo", $"value{i}", new { id = $"foo{i}"})
...
}
Caveat: while the sample above shows how you can do whatever you want for name, value, id, etc., it may affect validation (and force you to customize that too). In your specific use case however, since it's just id, it should be fine.

MVC/ASP.NET: Client side validation not working

EDIT: Consider this whole question replaced by this one:
ASP.NET/MVC: Knockout-binding preventing client-side validation from being performed?
Working in ASP.NET/MVC, I’m having great trouble getting the (unobtrusive or even non-unobtrusive) client side validation to work. (Yes again, but this time for different reasons as it appears.)
NB: The EDITS towards the bottom of the post are important, esp. EDITS 2 and 3.
Problem is, client side validation does absolutely nothing (see below), even though all ingredients seem to be in place. I’ve read through quite a few questions and answers here on Stack Overflow, and it seems everything is done correctly in my project, but still it doesn’t work. What am I missing?
In my Web.config file (the one in the root folder, not the one in the View folder), I’ve explicitly enabled the client side validation:
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
And all the relevant Javascript files are there, in the right order and loading correctly (and I’ve made no changes to them obviously). I’ve included them in bundles, in BundleConfig:
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate.js", "~/Scripts/jquery.validate.unobtrusive.js"));
I add these bundles in my View (well actually in the shared _Layout.cshtml parent view):
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/bootstrap")
#Scripts.Render("~/bundles/knockout")
And in the generated source code for the View these scripts (and a few others) appear as follows:
Which, as far as I can tell, is correct. (I also use the jQuery as well as knockout extensively in other places in the same View.) Also, no loading errors in the browser console.
Then in my ViewModel, I have this annotated property Email (among others):
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
// some other properties…
}
And this is the corresponding code in my View:
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
Which generates the following source code (click to enlarge):
Which also seems correct, as far as I can tell.
But then when I type something that’s evidently not a valid email-address in the input field, and make the field lose focus (by jumping to the next field), NO ERROR MESSAGE appears. Neither in the summary, nor the specific error message for the email field itself. As seen here:
(The little red square is the .field-validation-valid element that should contain the error message, but doesn't. For testing purposes I had decorated this element with a red border.)
Also, when I press the submit button, the input fields are simply submitted to the server action method (which then correctly determines that the inputs are not valid). But in fact, with client side validation enabled, the submit shouldn’t happen unless client side validation succeeds. But well, that’s basically the whole issue: client side validation simply doesn’t happen, despite the correct HTML being generated (presumably!).
EDIT 1:
And here is the HTML/Razor for the whole form:
#model Treinen2.Models.RegisterViewModel
#{
ViewBag.Title = "Register";
}
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
This is in a shared View called Register.cshtml, which -- depending on certain conditions -- gets displayed by calling #Html.Partial("Register") from the home view Index.cshtml. [I'm kind of trying to build a single page API application, as an exercise, so everything is included in the homepage (Index), and all navigation happens client side (with the obvious exception of the submit of the "Register" button itself, which gets sent to the server Action method, at least for now). And with obviously only one part ('page') of Index.cshtml being displayed at any one time, for which I use knockout binding.]
EDIT 2:
OK, I've noticed the following: If I put the same form in Index.cshtml, and also add the same model to that Index view, then client-side validation works perfectly. It's only on the partial view that it fails to work. Which suggests that I could simply stop using the partial view, and instead simply include its content on Index.cshtml, as tested. On the other hand, I still don't understand WHY using the partial view for the register form wouldn't work too. (With this new information, I may have to ask the question anew in a different form, but don't have the time right now...) [/EDIT 2]
EDIT 3:
Seems I'm edging closer to understanding the root cause of the problem. Because now I have the validation working with the form on the Index view... BUT it stops working as soon as I put the whole form inside a DIV-element that is bound by a Knockout attribute data-bind="If: ....." So that seems to be the essence of the problem: the interaction between client-side validation and Knockout binding. The Knockout binding, which in and of itself works fine, seems to prevent the validation from being performed. Although I still don't understand why that should be the case. [/EDIT 3]
So, what am I missing? Any constructive suggestions appreciated, will check back in a few hours.

Email form in footer to disappear after submit

Im new to .Net MVC, and im for learning purposes making a simple e-mail newsletter signup form in my footer.
#using (Html.BeginForm("details", "Home", FormMethod.Post))
{
<div class="form-group form-inline">
<label class="margin20">Sign up for newsletter</label>
#Html.TextBoxFor(Model => Model.Email, new { id = "input1", Class = "form-control", Style = "display:inline-block; max-width:200px", Placeholder = "Example#Example.com", type = "email" })
<button type="submit" disabled class="btn btn-default" style="display:inline-block" id="emailSignup">Signup</button>
</div>
}
Currently the form works just fine (I can type in my email, and i receive a confirmation mail after submitting).
When the user submits the email, the user is redirected to another page. However, i want this form to work on the same page, so that after the submit button is pressed, it says something like "thank you for subscribing" instead of moving to new view.
Im thinking, that the easy way to come around this would be to make a jQuery script that hides the email form and unhides a div that says "Thank you for signing up"
However, i want to do this in MVC manners, so what would be "most" correct to do? #RenderSection could be an option i guess?
Typically, it's done with simple flags, based on the model state - i.e. whether the e-mail has been sent or not. For example (very rough code);
#if (emailHasBeenSent)
{
<div class="polite-message"> Thanks for signing up! </div>
}
else
{
<div class="form-group form-inline"> your sign up code </div>
}
I'm fairly new to MVC too, but this is what I've seen from other people's code at work!

Html.ValidationMessageFor not displaying at all

I have the following form:
<form action="~/buy-online" method="get" class="buy-online-form clearfix" autocomplete="off" id="buy-online-search">
<div class="infield-holder clearfix">
#Html.LabelFor(m => m.CustomerPostcode, new { #class = "infield" })
#Html.TextBoxFor(m => m.CustomerPostcode, new { #class = "textbox" })
<input type="submit" value="Buy Online" id="find-retailer-button" class="button" />
</div>
</form>
#Html.ValidationMessageFor(m => m.CustomerPostcode)
Which works fine and will display an error message when submitted without jQuery, but when I add the jQuery validate scripts (v 1.11.1):
<script src="/scripts/jquery.validate.js"></script>
<script src="/scripts/jquery.validate.unobtrusive.js"></script>
It stops the form submitting but doesn't display the error message
My property is marked like so:
[DisplayName("Enter your full postcode")]
[Required(ErrorMessage = "Please enter your full postcode")]
public string CustomerPostcode { get; set; }
And the html renders like this:
<input class="textbox" data-val="true" data-val-required="Please enter your full postcode" id="CustomerPostcode" name="CustomerPostcode" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="CustomerPostcode" data-valmsg-replace="true"></span>
If I inspect the input when I hit submit it is adding the class input-validation-error to the textbox but just not updating the validation message.
All the posts that I have checked on this problem just say to include the scripts so I'm at a loss as to why the message is not showing.
I've even tried adding the jquery.unobtrusive-ajax.js script but that didn't seem to do anything either. Any help would be appreciated, thanks.
You need to include the #Html.ValidationMessageFor(m => m.CustomerPostcode) within the form tags for jquery.validate.unobtrusive to work.

MVC5 Validation Errors in Razor View

I am using MVC5 and having problem displaying the validation errors of an object both in the Validation Summary section and the individual validation messages for each control.
Lets put aside client validation for the moment although we have ENABLED IT in the web config and included the js files.
If a model that is invalid is passed to a view that has in place a Validation Summary (setting excludePropertyErrors to false) and for each control there is a #Html.ValidationMessageFor(model => model.Summary, "", new { #class = "text-danger" }), shoudn't all these display the Validation errors in the object when the page loads.
We checked the object and the framwork knows it is invlaid (ModelState.IsValid is definitely false) and the errors collection contains several validation errors
(System.Data.Entity.Validation.DbValidationError) but none of them show up neither in the ValidationSummary or the ValidationMessage for the individual controls when the page loads.
Currently I am getting he validation errors manually by context.Entry(prop).GetValidationResult().ValidationErrors.ToList(); and passing it to the Viewbag and iterate over them in the view to display them. Seems crazy!
P.S. The main View is composed of several partial views in which the controls are and the Vaidationsummary is in the Main containing view.
public async Task<ActionResult> GetProduct(id)
{
var product= await context.Products.FindAsync(id);
return View(product);
}
As I mentioned , there are NO VALIDATION MESSAGES ANYWHERE. If we turn off client side validation the input control html is
<input class="form-control text-box single-line valid" id="Price" name="Price" style="font-weight:bold" type="text" value="" aria-invalid="false">
As you can see the value is empty BUT it says it is valid even though the field is a required field marked so via DataAnnotations and the Model is INVALID and includes validation error that Price field is required!
Here is the code:
<div class="form-group">
#Html.LabelFor(m => m.Price, new { #class = "col-sm-3 control-label" })
<div class="col-sm-5">
#Html.EditorFor(model => model.Price, new { htmlAttributes = new { #class = "form-control", style = "font-weight:bold" } })
#Html.ValidationMessageFor(model => model.Price, "", new { #class = "text-danger" })
</div>
</div>
And this is the generated html with client side validation enabled :
<input class="form-control text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" style="font-weight:bold" type="text" value="">
Would greatly appreciate any assistance.

Resources