MVC Ajax.BeginForm and Content Security Policy - c#

To prevent cross side scripting i implement CSP to one of my applications. At moment i´m reconfigure all html classes, so that javascript always comes from my server.
Now i found a page with an Ajax.BeginForm and always get the error "Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'"." if i want to submit the form and update the view.
Can anybody help me, where the problem is?
Here is my html classes (shorted):
UserInformation.cshtml:
<div id="OpenAccountInformation">#Html.Action("OpenAccountInformation")</div>
</div>
AccountInformation.cshtml:
#Scripts.Render("~/Scripts/bundles/ManageUsers/AccountInformation")
#model Tumormodelle.Models.ViewModels.AzaraUserModel
<input type="hidden" value="#ViewBag.Editable" id="EditableUserInformation">
<div id="Editable">
#using (Ajax.BeginForm("EditUser", "ManageUsers", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "OpenAccountInformation", HttpMethod = "post", }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.UserID)
<div>
<div>
#Html.LabelFor(m => m.Username, new { #class = "entryFieldLabel" })
</div>
</div>
<div>
<div>
<button name="button" value="save" class="formbutton" id="saveButton">save</button>
<button name="button" value="cancel" class="formbutton" id="cancelButton">cancel</button>
</div>
}
</div>
<div id="NonEditable">
<div>
<div>
#Html.LabelFor(m => m.Username, new { #class = "entryFieldLabel" })
</div>
</div>
<div>
<div>
<button name="button" value="edit" class="formbutton" id="editButton" type="button">edit</button>
</div>
</div>
</div>
and the c# methods:
public ActionResult EditUser(AzaraUserModel AzaraUserModel, string button)
{
if (button == Tumormodelle.Properties.Resources.Save)
{
if (ModelState.IsValid)
{
azaraUserManagement.Update(AzaraUserModel.Username, AzaraUserModel.Title, AzaraUserModel.FirstName, AzaraUserModel.LastName, AzaraUserModel.EMailAddress, null, AzaraUserModel.Phone, AzaraUserModel.UserID, (byte)AzaraUserModel.ShowMail.ID);
ViewBag.Message = Tumormodelle.Properties.Resources.Personal_Data_Changed;
ViewBag.Editable = true;
}
else ViewBag.Editable = false;
BindShowMailList();
return PartialView("AccountInformation", AzaraUserModel);
}
else
{
return RedirectToAction("OpenAccountInformation", "ManageUsers");
}
}
public ActionResult UserInformation()
{
return View("UserInformation");
}
public PartialViewResult OpenAccountInformation()
{
AzaraUserModel AzaraUserModel = new AzaraUserModel(azaraUserManagement.GetSingle(AzaraSession.Current.UserComparison.GetUser().Id));
BindShowMailList();
ViewBag.Editable = true;
return PartialView("AccountInformation", AzaraUserModel);
}
Edit: With help of Chrome debugger i find out, that the error is thrown in the moment form becomes submited.

Ajax.BeginForm will be generating inline script in the generated HTML of your page, which you have disallowed by use of script-src 'self' in your Content Security Policy.
If you want to use the CSP to prevent any inline injected scripts you must use Html.BeginForm instead and add the JavaScript to submit this via Ajax in an external .js file.

try to add this attribute to your controller post action
[ValidateInput(false)]

Related

Pass value of dropdownlist when click button

I have a dropdownlist in my View:
#Html.DropDownListFor(m => m.APtTitleData.apt, (IEnumerable<SelectListItem>)ViewBag.apt, "-Select Apt-", new { id = "SelectedAPt", name= "SelectedAPt" })
and I have a button in the same View
GO
How do I pass the value of the dropdown to my controller (Edit)? I'm trying to get the value to the button, but I'm not sure this is the right way. Any other idea?
I would suggest that you use a form where you submit the value from the dropdown to the controller.
Please check out the following code:
#using (Html.BeginForm("APtTitle", "Edit", FormMethod.Post))
{
<div class="form-group">
<label>AptTitles</label>
<div>
#Html.DropDownListFor(m => m.APtTitleData.apt, (IEnumerable<SelectListItem>)ViewBag.apt, "-Select Apt-", new { id = "SelectedAPt", name= "SelectedAPt" })
</div>
</div>
<div class="form-group">
<div>
<input type="submit" value="Submit" />
</div>
</div>
</div>
}
And in the controller your code should look similar to the following:
[HttpPost]
public ActionResult Edit(string SelectedAPt)
{
var aPtValue = SelectedAPt;
// Do what intended with the value
}
You should now be able to see the value in the controller now.
Try it out and let me know if you run into issues.

Blank form appears after submitting in ASP.NET Core?

I have an application that has multiple tabs to submit a form. However, users are getting a blank form after hitting submit, and are not redirected to the confirmation page. This is odd because some applications are submitting fine, while others are not storing the data from fields to the database. My first guess was that it was a firewall issue. I am using a post method for submit. Another note, this is something that is occurring on our production server but not on our local development environment.
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Applicant")]
public IActionResult Application(ApplicationViewModel model)
{
var saved = false;
model = _applicantManager.RebuildApplicationViewModel(model);
if (ModelState.IsValid)
{
saved = _applicantManager.SubmitApplication(model, CurrentUser.UserName);
return RedirectToAction("Index");
}
return View(model);
}
Form (Rather large so shortened for simplicity):
#Html.ValidationSummary(excludePropertyErrors: false, message: "", htmlAttributes: new { #style = "color:red" })
<ul class="wdn_tabs">
<li>Personal</li>
<li>Academic</li>
<li>Questions</li>
<li>Availability & Reference</li>
</ul>
#using (Html.BeginForm(actionName: "Application", controllerName: "Applicant", method: FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="wdn_tabs_content">
<div id="personalTab">
<h4>Personal Information</h4>
<div style="color:red"><strong>All fields are required.</strong></div>
<div class="tabBody">
<div class="inputGroup spacer">
<strong>#Html.DisplayNameFor(x => x.PersonalInfo.FirstName)</strong>
#Html.ValidationMessageFor(x => x.PersonalInfo.FirstName)
#Html.TextBoxFor(x => x.PersonalInfo.FirstName)
</div>
<div class="inputGroup spacer">
<strong>#Html.DisplayNameFor(x => x.PersonalInfo.LastName)</strong>
#Html.ValidationMessageFor(x => x.PersonalInfo.LastName)
<input type="text" asp-for="PersonalInfo.LastName" />
</div>
..........................other fields..........................
</div>
<div class="tabFooter">
Back
<button type="submit" class="wdn-button wdn-button-complement">Submit</button>
</div>
</div>
</div>
}

Summernote and form submission in MVC c#

I am using the summernote plugin for text box:
http://summernote.org/#/getting-started#basic-api
This is the form I have using summmernote:
<div class="modal-body" style="max-height: 600px">
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset class="form-horizontal">
<div id="textForLabelLanguage"></div>
<button type="submit" class="btn btn-primary">Save changes</button>
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn " })
</fieldset>
}
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#textForLabelLanguage').summernote();
});
</script>
Now, In my controller, this is the code I have:
public ActionResult Create(UserInfo newInfo , [Bind(Prefix = "textForLabelLanguage")] string textForLabelLanguage)
{
//logic here
}
Now the problem is that textForLabelLanguage param is always null.
This happens because I have to pass $('#textForLabelLanguage').code(); into MVC when submiting the form but I have no idea how to do that!
How do I solve my problem?
I found my solution to the problem. This is how I am making the controller get the correct information:
<div class="modal-body" style="max-height: 600px">
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset class="form-horizontal">
<textarea name="textForLabelLanguage" id="textForLabelLanguage" />
<button type="submit" class="btn btn-primary">Save changes</button>
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn " })
</fieldset>
}
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#textForLabelLanguage').summernote();
});
</script>
Basically, if I use a textarea with a name instead of an input or anything else, it works!
However, and be warned, even though this solution works, I then get a error in the controller saying:
A potentially dangerous Request.Form value was detected from the client
This happens because I am allowing HTML. But this is a problem for another question!
Please, use [AllowHTML]
There's a good article on MSDN
Request Validation in ASP.NET
"To disable request validation for a specific property, mark the property definition with the AllowHtml attribute:"
[AllowHtml]
public string Prop1 { get; set; }
similar to what was posted earlier you can use the HTML helper
#HTML.TextAreaFor( m=> m.text, new {#id = "textFor*Model*"})
instead of <textarea>

How to stop page change on Ajax Form Posting in MVC Mobile

I am creating an application on MVC Mobile and having a problem. Here i have a Partial view load on a page run-time by ajax. In which i have a simple form which will submit with ajax request like bellow:
#model Test.Models.TestModel
#using (this.Ajax.BeginForm("Create", "Test", Model, new AjaxOptions { UpdateTargetId = "divResult", LoadingElementId = "loading", LoadingElementDuration = 2000, HttpMethod = "Post" }, new { id = "frmCreate" }))
{
#Html.AntiForgeryToken()
<div class="messageBox">#Html.Raw(TempData["Message"])</div>
<div class="atmForm">
<div class="control-group">
#Html.LabelFor(x => x.Name)
#Html.TextBoxFor(x => x.Name, new { #placeholder = "Name", #class = "inputStyle" }) #Html.ValidationMessageFor(x => x.Name)
</div>
<div class="control-group">
#Html.LabelFor(x => x.Notes)
#Html.TextAreaFor(x => x.Notes, new { #placeholder = "Notes", #class = "inputStyle" }) #Html.ValidationMessageFor(x => x.Notes)
</div>
</div>
<div class="form-actions2 clearfix">
<input type="submit" class="btn btn-block" value="Create" data-ajax="false" id="btnFormSubmit" />
</div>
}
<script type="text/javascript">
$.validator.unobtrusive.parse("#frmCreate");
</script>
The problem is when user submit the form the controller called twice. First time it return the partial view and then again it calls and then jQuery Mobile change the page. I am Using MVC4 with jQuery Mobile 1.1.0
(please note that create.cshtml (desktop ver) works fine but create.Mobile.cshtml (mobility ver) havng this problem)
Do not submit the form, use $("#myForm").serialize() as ajax data.

Mvc ViewBag - Cannot convert null to 'bool' because it is a non-nullable value type

I want to set a bool to true in the controller when producing a certain view and then alter the header of the view accordingly. This should be dead simple but instead Im getting:
Cannot perform runtime binding on a null reference Exception Details:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform
runtime binding on a null reference
All I'm doing is in controller:
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.IsRegistration = true;
return View();
}
and then in view:
#if (ViewBag.IsRegistration)
{
<legend>Register using another service.</legend>
}
else
{
<legend>Use another service to log in.</legend>
}
but it fails on:
#if (ViewBag.IsRegistration)
UPDATE
Relevant Controller Code:
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.IsRegistration = "true";
return View();
}
The register view:
#model Mvc.Models.RegisterViewModel
#{
Layout = "~/Views/Shared/_AccountLayout.cshtml";
ViewBag.Title = "Register";
}
<hgroup class="title">
<h1>#ViewBag.Title.</h1>
</hgroup>
<div class="row">
<div class="col-lg-6">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset class="form-horizontal">
<legend>Create a new account.</legend>
<div class="control-group">
#Html.LabelFor(m => m.UserName, new { #class = "control-label" })
<div class="controls">
#Html.TextBoxFor(m => m.UserName)
</div>
</div>
<div class="control-group">
#Html.LabelFor(m => m.Password, new { #class = "control-label" })
<div class="controls">
#Html.PasswordFor(m => m.Password)
</div>
</div>
<div class="control-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "control-label" })
<div class="controls">
#Html.PasswordFor(m => m.ConfirmPassword)
</div>
</div>
<div class="form-actions no-color">
<input type="submit" value="Register" class="btn" />
</div>
</fieldset>
}
</div>
<div class="col-lg-6"></div>
<section id="socialLoginForm">
#Html.Action("ExternalLoginsList", new { ReturnUrl = ViewBag.ReturnUrl })
</section>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The ExternalLoginsList partial:
#using Glimpse.Core.Extensions
#using Microsoft.Owin.Security
#model ICollection<AuthenticationDescription>
#if (Model.Count == 0)
{
<div class="message-info">
<p>There are no external authentication services configured</p>
</div>
}
else
{
using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
<fieldset id="socialLoginList">
#if (!string.IsNullOrEmpty(ViewBag.IsRegistration))
{
<legend>Register using another service.</legend>
}
else
{
<legend>Use another service to log in.</legend>
}
<p>
#foreach (AuthenticationDescription p in Model) {
<button type="submit" class="btn" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType" title="Log in using your #p.Caption account">#p.AuthenticationType</button>
}
</p>
</fieldset>
}
}
Try:
#if (ViewBag.IsRegistration == true)
I know this is an old question, but I think I have an elegant answer, so in case anyone reads this after searching, here is mine:
#if (ViewBag.IsRegistration ?? false)
Try this:
Replace the line in your controller:
ViewBag.IsRegistration = true;
with
ViewBag.IsRegistration = new bool?(true);
and replace the line in your view:
#if (ViewBag.IsRegistration)
with
#if ((ViewBag.IsRegistration as bool?).Value)
Effectively you are putting a nullable bool in the ViewBag and then unwrapping it.
Simply check for null before checking for true:
if (ViewBag.IsRegistration != null && ViewBag.IsRegistration)
Try TempData instead of ViewBag.
Change your code from
Controller
ViewBag.IsRegistration=true;
to
TempData["IsReg"]=true;
and in View
#if((bool)TempData["IsReg"])
It seems that you are using the value in child partial view and you are adding the data in parent action.The values in viewbag cannot pass out data from one action to anothers action's view. While TempData use session it can be used to pass data to one action to another actions view.
Ok so as per Floods suggestion in comments, I need to pass the arguments around. The ViewBag from the parent View does not flow through to partial views.
So in the code for the Register View I needed to change from
<section id="socialLoginForm">
#Html.Action("ExternalLoginsList", new {ReturnUrl = ViewBag.ReturnUrl})
</section>
to
<section id="socialLoginForm">
#Html.Action("ExternalLoginsList",
new {ReturnUrl = ViewBag.ReturnUrl,
IsRegistering = #ViewBag.IsRegistering })
</section>
Then go into my account controller and change from:
[AllowAnonymous]
[ChildActionOnly]
public ActionResult ExternalLoginsList(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return (ActionResult)PartialView("_ExternalLoginsListPartial", new List<AuthenticationDescription>(AuthenticationManager.GetExternalAuthenticationTypes()));
}
to
[AllowAnonymous]
[ChildActionOnly]
public ActionResult ExternalLoginsList(string returnUrl, string isRegistering) {
ViewBag.IsRegistering = (isRegistering.ToLower() == "true");
ViewBag.ReturnUrl = returnUrl;
return (ActionResult)PartialView("_ExternalLoginsListPartial", new List<AuthenticationDescription>(AuthenticationManager.GetExternalAuthenticationTypes()));
}
Then in the ExternalLogins I can just:
#if (ViewBag.IsRegistering)
as necessary.
So Im effectively passing the IsRegistering bool from controller to main view then back up to action method on controller then into ViewBag which allow me to access the bool in the child partial view.
Many thanks.
Booleans in Viewbag are always tricky. Try this instead
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.Registration = "x";//x or whatever
return View();
}
#if (!String.IsNullorEmpty(ViewBag.Registration))
{
<legend>Register using another service.</legend>
}
else
{
<legend>Use another service to log in.</legend>
}
Maybe so:
#if ((ViewBag.IsRegistration != null) && (ViewBag.IsRegistration is bool) && (bool)ViewBag.IsRegistration)
{
}

Categories