Am I missing something or asp.net core allows to post script tag in user text fields? In Previous versions of asp.net mvc I needed to allow it by [AllowHtml] attribute.
Is there a way how enable validation agains potentially dangerous values?
I'm free to submit value like
<script src='http://test.com/hack.js'></script>
during form post.
Model:
using System.ComponentModel.DataAnnotations;
namespace Test.Models
{
public class TestModel
{
[MaxLength(500)]
public string Content { get; set; }
}
}
Controller:
using Microsoft.AspNetCore.Mvc;
using Test.Models;
namespace Test.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
var model = new TestModel { Content = "Test" };
return View();
}
[HttpPost]
public IActionResult Index(TestModel model)
{
if(!ModelState.IsValid)
return View(model);
return Content("Success");
}
}
}
View:
#model TestModel
<form asp-action="Index" asp-controller="Home" method="post">
<div asp-validation-summary="All"></div>
<label asp-for="Content">Content<strong>*</strong></label>
<span asp-validation-for="Content"></span>
<input asp-for="Content" type="text" />
</div>
</form>
ASP.NET Core does not have a feature similar to Request validation, as Microsoft decided, that it’s not a good idea.
For more information see the discussion on the ASP.NET Core issue 'Default middleware for request validation, like IIS has'.
That means that validation has to take place on the inbound model. And that in the Razor (.cshtml)
you should output user provided input like #Model.Content, which encodes the given string.
Please bear in mind that those escaping techniques might not work when the text that was output is not inside a Html part.
So don't use #Html.Raw(..) unless you know that the data provided has been sanitized.
Supplement:
You might want to consider a Web Application Firewall (WAF)
for a generic protection against malicious requests (e.g. XSS or SQL Injection).
For protecting your users against an XSS attack you might also have a look at
providing a Content Security Policy (CSP).
Related
I want to allow a page to be viewed by anyone, but only authorized users to be able to submit forms i.e using the post method(s) of a razor page.
However authorize attribute is only applicable at PageModel level, I can either make get + post authorizable or both anonymously accessible.
What is the recommended approach in this scenario?
First, I would only render the form if the user is authenticated:
#if (User.Identity.IsAuthenticated)
{
<partial name="_CommentForm" />
}
Then I would perform the same check in the OnPost handler before processing the form submission to prevent automated or other nefarious submissions:
public async Task<IActionResult> OnPostAsync()
{
if(User.Identity.IsAuthenticated)
{
if(Modelstate.IsValid)
{
// blah blah
}
}
else
{
return BadRequest();
}
}
Or you could post to a different page which is only designed to process the submission and can have the Authorize attribute applied to it
I try to use Microsoft.AspNetCore.Identity with pages. Can I do it or I must choose Razor Pages authorization conventions like in https://learn.microsoft.com/en-us/aspnet/core/security/authorization/razor-pages-authorization? I `see
services.AddMvc()
.AddRazorPagesOptions(options =>
{
options.Conventions.AuthorizeFolder("/Account/Manage");
options.Conventions.AuthorizePage("/Account/Logout");
});`
I have .cshtml file with
#model Proj_s.Models.AccountViewModels.RegisterViewModel
#{
ViewData["Title"] = "Register";
}
<h2>#ViewData["Title"]</h2>
.......
#section Scripts {
#await Html.PartialAsync("_ValidationScriptsPartial")
}
I replace
#page #model Proj_s.Pages.Projects.DetailsModelwith
#model Proj_s.Models.AccountViewModels.RegisterViewModel
What the best way to add authentification or authorization to existing razor page that does not contain this?
You can use ASP.NET Core Identity and Razor Pages. Check this article
In general, just create a template and see how this is implemented.
dotnet new razor --auth individual
Be aware though, that Razor Pages are a little tricky when it comes to customization.
Most common and widely accepted practice is it use [Authorize] attribute.
[Authorize]
public class AccountController : Controller
{
public ActionResult Login()
{
}
public ActionResult Logout()
{
}
}
This is how you protect your view. [Authorize] checks if the user is logged in or not and sends them back to the configured page (login) if they aren't. You can also check if the logged in user is in role like this [Authorize("RoleName")]
More details
I am working on tracking system for my SignalR Hub purpose. For this I have class where I want to store URL which will represent current page where user is, then his last request since I use paged list for my data tables and I need to know exactly on which page user is and of course user id.
This is my class where I want to store information
public class UserTracking
{
public string URL { get; set; }
public string LastRequest { get; set; }
public string UserId { get; set; }
}
Since I have a single page application I have problem with tracking user position on website because of angular routing, but for displaying views I have dashboard controller with ActionResults methods to allow me to display .cshtml pages with angular routing, something like this below
public ActionResult ProjectTask()
{
return View();
}
public ActionResult Project()
{
return View();
}
My question is if I am able somehow to get URL of user position on my website. For example if user is on http://localhost:2969/Dashboard#/tasks/ I want to get this /Dashboard#/tasks. Maybe I can get some information from my ActionResults, but I have no idea how.
It is hard to know if this will work for you with the information you've provided, but the following could work.
If you know the specific routes that a user must navigate to to reach you MVC Controller then you could pass in that information as a model when you return the view. Say I have an MVC route that is meant to return a Razor page that displays all the items from my list named "Freddy's Birthday". The URL in this case would look something like:
localhost/list/Freddy's%20Birthday
matching a route:
[Route("~/list/{id}")]
To inform Angular of what you're dealing with, simply pass in the information as a model:
public ActionResult List(string id)
{
return View(model: id);
}
You can access that model in your cshtml with #Model. If the id passed in was "Freddy's Birthday" like before:
<div todo-list-item-directive>#Model</div>
Would return from ASP as:
<div todo-list-item-directive>Freddy's Birthday</div>
This way works, and you could build some view models to reference in your Razor pages if you need to pass in more complicated information. However, if at all possible, it'd likely be worth your while to set up ui-router and use Angular for your view routing and ASP.NET for your API.
Hi i am a beginner in MVC i have written code for validating but it is not working can anyone please help me out.
Here is the model code:
[Required]
public string Name { get; set; }
Here is the View code:
#Html.TextBoxFor(m => m.ContactDetailSubSections[i].Name)
#Html.ValidationMessageFor(m=>m.ContactDetailSubSections[i].Name)
Thanks in advance for your help
You can use Enable Client side validation feature of MVC for standard validation which doesn't require any server side code in controller.
Enable Client side Validation
Enable Client side Validation-2
However you also must check ModestState.IsValid() at controller level for better security.
First of all, you don't need any of JS libraries for ASP.NET MVC server validation.
Second, you should check in controller, that a model is valid.
if (ModelState.IsValid) {
//do something
}
return View(); //you can return view with optional parameters
Also, you should check which Method for sending data are you use (POST or GET) and check that this method is used in controller (for sending data always use a POST method).
[HttpPost]
public ActionResult Index(YourModel model) {
if (ModelState.IsValid) {
//do something
}
return View();
}
This is the project for you (Validation.zip): http://sdrv.ms/UP3DIE (I'm using VS 2012)
There is only one field with Required attribute and custom error message (model LocalValidationTestModel). And in the view there are two methods for displaying errors:
#Html.ValidationSummary() and #Html.ValidationMessageFor(x => x.TestField)
All JS scripts and CSS styles are cutted.
Also, why are you using arrays?
I think you should reference several files of jquery .
and then in the action ,you must do something ,like this:
if(ModelState.IsValid) { //TODO } return View();
and the action must add attribute is [HttpPost]
The controller is:
public class HomeController : Controller
{
public ActionResult LogOn()
{
return View();
}
[HttpPost]
public ActionResult LogOn(string captcha)
{
if (captcha == HttpContext.Session["captcha"].ToString())
return Content("ok");
else
return Content("failed");
}
public CaptchaImageResult ShowCaptchaImage()
{
return new CaptchaImageResult();
}
}
The view is:
<%using (Html.BeginForm())
{ %>
<p><img src="/Home/ShowCaptchaImage" /></p>
<p>Please enter the string as shown above:</p>
<p><%= Html.TextBox("captcha")%></p>
<p><input type="submit" value="Submit" /></p>
<% } %>
Everything goes well, the captcha image is rendered (CaptchaImageResult writes a jpg in the response stream). But if i use the razor view engine there is no captcha image rendered.
How to fix it?
And one more thing: is it a good way to display captcha?
Later edit: <img src=#Href("../../Home/ShowCaptchaImage") /> works fine.
The problem wasn't because razor it was because in the first example i was using Visual Studio Development server and in the second one i was using IIS
<img src="/Home/ShowCaptchaImage" />
This causes the browser to request /Home/ShowCaptchaImage from the root of the HTTP origin (scheme+domain+port) on which you host the application. You need to map the URL to reflect things like any virtual folders in which the app is hosted. If I'm not wrong and this is the problem you are facing, take a look at ResolveUrl/ResolveClientUrl equivalents for Asp.Net Razor? (I haven't tested it, but it looks good).
Also, you could diagnose the problem easily using Firebug or an equivalent tool in another browser - take a look at the requests which are made and you will see what the browser actually requests.