Solving XSS issues - security

I am trying to build an MVC application and have been told it is not a good way to retrieve data and is susceptible to cross-site scripting. I have never done security and have been trying to learn as well but I cannot wrap my head around it.
I am guessing there are several flaws here. Is there any particular encoding I can use?
I haven't pasted the entire code here but trying to figure out where I can stop the XSS attacks.
Model and View Model
namespace ThePeopleSearchApplication.Models
{
public class UserViewModel
{
public string UID{ get; set; }
public string FName{ get; set; }
public string LName{ get; set; }
public string Email { get; set; }
public string Status{ get; set; }
}
public class UserModel
{
public string UID{ get; set; }
public string FName{ get; set; }
public string LName{ get; set; }
public string Email { get; set; }
public string Status{ get; set; }
}
}
Controller
namespace ThePeopleSearchApplication.Controllers
{
public class MyController : Controller
{
// GET: My
public ActionResult Index()
{
return View();
}
[ValidateInput(false)] //has been added to understand XSS better
public ActionResult SearchUserAjax(string userId)
{
UserModel myUser = fetchUserFromLdap(userId);
return Content("{\"message\": \"search for userId: " +
userId + " result\", \"result\": " + convertToJson(myUser) + " }");
}
private string convertToJson(UserModel myUser)
{
return "{ \"userId\": \"" + myUser.UserId + "\", \"FirstName\": \"" +
myUser.FirstName + "\", \"LastName\": \"" + myUser.LastName + "\", \"Email\": \"" +
myUser.Email + "\", \"Status\": \"" + myUser.Status + "\"}";
}
[ValidateInput(false)] //has been added to understand XSS better
public ActionResult SearchUser(string userId)
{
UserModel myUser = fetchUserFromLdap(userId);
var viewModel = new UserViewModel
{
UID = userId,
FName = myUser.FirstName,
LName = myUser.LastName,
Email = myUser.Email,
Status = myUser.Status,
};
return this.View(viewModel);
}
private UserModel fetchUserFromLdap(string userId)
{
var retVal = new UserModel();
if (String.IsNullOrEmpty(userId))
{
retVal.UID = "N/A";
retVal.FName = "N/A";
retVal.LName = "N/A";
retVal.Email = "N/A";
retVal.Status = "N/A";
}
else
{
retVal.UID = userId;
retVal.FName = "FirstName";
retVal.LName = "LastName";
retVal.Email = "email#example.com";
retVal.Status = "<div style=background-color:#F00800>My Status</div>";
}
return retVal;
}
}
}
View
#model ThePeopleSearchApplication.Models.UserViewModel
#{
ViewBag.Title = "Search result for user: " + Model.UserId;
var ulId = "ul-id" + Model.UserId;
var formId = "form" + Model.UserId;
}
<html>
<head>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
</head>
<body>
<h1>Search result for user: #Model.UserId</h1>
<ul id="#Html.Raw(ulId)">
<li>#Model.FirstName</li>
<li>#Model.LastName</li>
<li>#Model.Email</li>
<li>#Html.Raw(Model.Status)</li>
</ul>
<form id=#formId name=#formId action=/My/SearchUser enctype="multipart/form-data">
<input type="text" name="userId" />
<input type="submit" />
</form>
<script type="text/javascript">
var theForm = document.#formId;
$(theForm).submit(function() {
alert('Valid form');
return true;
});
// just to demonstrate potential usage $(theForm).submit();
</script>
<div>
Ajax search:
<form id="ajax-search" name="ajax-search">
<input type="text" name="userId" />
<input type="submit" />
</form>
<script>
$("#ajax-search").submit(function() {
var url = "/My/SearchUserAjax"; // the script where you handle the form input.
$.ajax({
type: "POST",
url: url,
data: $("#ajax-search").serialize(), // serializes the form's elements.
success: function(data)
{
var obj = JSON.parse(data);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.message); // show response from the php script.
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.userId);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.FirstName);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.LastName);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.Status);
$('#ajax-search').append('<hr/>');
}
});
return false; // avoid to execute the actual submit of the form.
});
</script>
</div>
</body>
</html>

The principle problem is if the User controls some data that you render to the page in an unsafe way. Whether that be from their name (my name is <script>function() { nasty stuff is happening here... }</script>) or any other content.
I take the following approach, look at your output (or better think ahead about it) and see if it's a problem at each stage:
Let Razor do it, by default Razor handles encoding of all HTML
characters on the page, this doesn't apply if you use an
IHtmlString so avoid this Type (or methods that return it like
Html.Raw()) so #("<script>nastyThings()</script>") is a string so that will be encoded, and the script will not run
If it's broken, that means your string has some HTML/JS in it that
you actually want to render. So try and move that directly onto the
Razor template (HTML/JS) or obtain it via a link (JS)
Instead of the whole string being user controlled "<element onclick="javascript:alert('trouble')"></element>" with template #Html.Raw(Model.UserBadString)
Make the template <element onclick="mySafeJsFunction()">#Model.UserSafeString</element>", this takes control of the JS function away from the User, and leaves them with a Razor encoded parameter that they can't do XSS with
You want the User to have control over the HTML, then you will have to sanitise the string on output to the page, by using something like (https://github.com/mganss/HtmlSanitizer)
So the template could be #Html.Raw(sanitizer.Sanitize(Model.UserBadString)) but you'd probably want to do something nicer than that, good coding practice etc. The main point is that the string is sanitised
As an aside, make sure you keep a very close aye on usages of properties such as .innerHTML in JS (or the dreaded jQuery .html() which calls eval()), as if these take in user controlled content you'll have the exact same problem. But the same steps can be applied, (1) use .innerText instead, or (3) otherwise use a purification library on the string like DOMPurify before giving it to the JS (https://github.com/cure53/DOMPurify). Unfortunately in this case option (2) is not recommended, since whatever is left will have to be made safe by you or I, I'd rather trust DOMPurify to do it :)

Related

redirect on another page on button click

I am creating a web app and I have 2 textboxes and one button with an input field
<input id="Login" type="submit" onclick="location.href='#Url.Action("loggedin","logincontroller")'" style="" width="200" height="34" value="submit" />
and my controller looks like
public ActionResult loggedin(string role, string username, string password)
{
webservice.loginservice a= new webservice.loginservice();
a.getlogintype(role, username, password);
return View();
}
with my webservice
[WebMethod]
public string getlogintype(string role, string username, string password)
{
string strtru="";
string strfalse="";
sqlcon;
SqlCommand cmd = new SqlCommand("select * from [admin] where userid='" + username + "' and pass ='" + password + "'", con);
con.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
if (dt.Rows.Count > 0)
{
strtru = "true";
}
else
{
strfalse = "false";
}
con.Close();
}
My controller is calling the webservice and now I want to know how to redirect the page on successful validation. This is my first application using mvc I know there are many mistakes in this app(please let me know all the mistakes).
I am creating the application on mvc 5 and I am only using input fields not #Html syntax because I want to design it like(beta2.hti-india.com) this app is created by me on asp.net c#.
your web service code looks good.
changes in your code.
public ActionResult loggedin(string role, string username, string password)
{
webservice.loginservice a= new webservice.loginservice();
string result = a.getlogintype(role, username, password);
if(result == "true")
{
// redirect to your application home page or other page
return RedirectToAction("OtherAction", "Controller");
}
else
{
return View();
}
}
try to use this is better way for .cshtml or View
#using (Html.BeginForm("loggedin", "controller", new { ReturnUrl = "" }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<!-- your textbox here-->
<input id="Login" type="submit" value="submit">
}
in your action method loggedin(..) you should return a new view by using RedirectToAction()
return RedirectToAction("MyAction", "MyController");

Pass multiple pass values to RedirectToAction in MVC 5

I am developing the website in MVC. I want to display details record one by one. The next record to be displayed when user clicks the Submit Button.
Kindly advise for the same
Code in Controller
// GET: Member_Details
public ActionResult Member_Details(int sysmemberid , string type)
{
Member_Details obj = new Member_Details();
obj=obj.getMemberDetails(Convert.ToInt64(Session["Id"]), sysmemberid, type);// assign values to model
Session["sysmemberid"] = sysmemberid;
Session["type"] = type;
Session["Next"] = obj.next;
return View(obj);
}
[HttpPost]
public void Member_Details(Member_Details obj ,string command)
{
string sysmemberid = Session["sysmemberid"].ToString();
string type1 = Session["type"].ToString();
string sqlQuery = "";
int next = Convert.ToInt32(Session["Next"]);
RedirectToAction("Member_Details", new { sysmemberid = next, type = type1 });
}
View Code :
#using (Html.BeginForm("Member_Details", "Member_Details", FormMethod.Post, new { id = "submitForm" }))
{
// Code to bind model
<button type="submit" id="btnSave" name="command" value="invite" class="btn btn-lg btn-primary btn-block link dtlSubmit">Connect</button>
}
It look like you already have the logic to get the next item and are building the ReditectToAction, however it doesn't look like you are returning it.
Add the ActionResult return value to the Member_Details that handles the POST:
public ActionResult Member_Details(Member_Details obj ,string command)
And return your RedirectToAction:
return RedirectToAction("Member_Details", new { sysmemberid = next, type = type1 });

MVC5 Binding issue

I'm trying to set up some basic navigation on a web site I'm rewriting and I've run into a brick wall and don't see why this is not working. I'm doing something similar in a half dozen other places but it just ain't working.
What I want to do is if my article has a next and or previous ID I want to show a navigation bar with appropriate forward/reverse navigation arrows or whatever to allow user to navigate pages.
The ViewModel
public class NavViewModel
{
public int NextID { get; set; }
public int PreviousID { get; set; }
public string NextString { get; set; }
public string PreviousString { get; set; }
public bool SelectedMode { get; set; }
public NavViewModel() { }
}
The View
#Html.HiddenFor(model => model.NavigationViewModel.PreviousID)
#Html.HiddenFor(model => model.NavigationViewModel.NextID)
<div class="post-nav">
#if (#Model.NavigationViewModel.PreviousString != null)
{
using (Html.BeginForm("SinglePost", "Article", FormMethod.Post, new { #nvm = Model.NavigationViewModel }))
{
<input type="submit" class="btn btn-default" value="#Model.NavigationViewModel.PreviousString" />
}
}
#if (#Model.NavigationViewModel.NextString != null)
{
using (Html.BeginForm("SinglePost", "Article", FormMethod.Post, new { nvm = #Model.NavigationViewModel }))
{
<input type="submit" class="btn btn-default" value="#Model.NavigationViewModel.NextString" />
}
}
</div>
and the Controller
[HttpPost]
public ActionResult SinglePost(NavViewModel nvm)
{
return RedirectToAction("SinglePost", "Article", new { postID = nvm.PreviousID });
}
I've tried passing back the bool, the IDs, the ViewModel and they all come null or containing null values.
I had this code in a PartialView and because it wasn't working I moved it up a level into the calling view and it has the same result.
You have stated you want to navigate to the next and previous items so using forms and inputs and submitting to a POST method is not appropriate. Instead use a link to navigate to a GET method, passing the ID of the previous or next item.
#if (#Model.NavigationViewModel.PreviousString != null)
{
#Html.ActionLink(Model.NavigationViewModel.PreviousString, "SinglePost", "Article", new { postID = Model.NavigationViewModel.PreviousID }, null)
}
#if (#Model.NavigationViewModel.NextString != null)
{
#Html.ActionLink(Model.NavigationViewModel.NextString , "SinglePost", "Article", new { postID = Model.NavigationViewModel.NextID }, null)
}
The reason your code does not work will be obvious when you inspect the html generated for the <form> tag. Your generating an attribute nvm="YourAssembly.NavigationViewModel" (not a route value). If you used the correct overload to generate route values, which would be
using (Html.BeginForm("SinglePost", "Article", new { #nvm = Model.NavigationViewModel }))
it will still fail because it will generate something similar to (depending on you routes) action="/Article/SinglePost?nvm=YourAssembly.NavigationViewModel" so when you post back, the DefaultModelBinder will try to assign the string "YourAssembly.NavigationViewModel" to parameter nvm, but nvm is a complex object, not a string, so binding will fail.
You could make the POST method work by using
using (Html.BeginForm("SinglePost", "Article", Model.NavigationViewModel))
however this is just degrading performance by posting back unnecessary data and if your model contained properties that were complex objects or collections, it would fail anyway, so don't do it.
Finally, if you want to make the link look like a button, then style it using css.
Try to move hidden inputs into the form
<div class="post-nav">
#if (#Model.NavigationViewModel.PreviousString != null)
{
using (Html.BeginForm("SinglePost", "Article", FormMethod.Post, new { #nvm = Model.NavigationViewModel }))
{
#Html.HiddenFor(model => model.NavigationViewModel.PreviousID)
<input type="submit" class="btn btn-default" value="#Model.NavigationViewModel.PreviousString" />
}
}
#if (#Model.NavigationViewModel.NextString != null)
{
using (Html.BeginForm("SinglePost", "Article", FormMethod.Post, new { nvm = #Model.NavigationViewModel }))
{
#Html.HiddenFor(model => model.NavigationViewModel.NextID)
<input type="submit" class="btn btn-default" value="#Model.NavigationViewModel.NextString" />
}
}
</div>

using $.GetJSON() function to retrieve an array of class objects

I have implemented a WEB API 2 controller which returns an array of a class objects. Now, I want to consume this API in my MVC 5 application. For that I have found out that getJSON method can be used. But the problem is I don't know how to get an array of class objects from getJSON method. Also depending on the number of objects returned i have to create equal number of grids on UI. Any pointer, link or sample code is welcome.
Below example will help you to consume web api and use that data in your page.
Controller :-
public class TestController : ApiController
{
public IEnumerable<temp> Get()
{
var context = new Test();
return context.temps;
}
}
Model & DbContext Class For Database:-
[Table("temp")]
public class temp
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column(TypeName = "numeric")]
public decimal tempid { get; set; }
[Required]
[StringLength(50)]
public string name { get; set; }
[Required]
[StringLength(50)]
public string address { get; set; }
}
public class Test : DbContext
{
public Test()
: base("name=Test")
{
}
public virtual DbSet<temp> temps { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<temp>()
.Property(e => e.tempid)
.HasPrecision(18, 0);
}
}
View Side :-
<html>
<head>
<script src="~/Scripts/js/jquery-1.10.1.min.js"></script>
<script>
$(document).ready(function()
{
$.getJSON("http://localhost:51197/api/Test", function (data) {
$.each(data, function (key, val) {
$("<table border='1'><tr><td>" + val.name + "</td><td>" + val.address
+ "</td></tr></table>").appendTo("#tbPerson");
});
});
});
</script>
</head>
<body>
<div id="tbPerson">
</div>
</body>
</html>
I don't know if this is what you are looking for, but while parsing a json-string with several objects, you could simply use for each.
Inside the loop you could create your grid, so you are depeding on the number of objects.
$.each(jsonstring, function (i, object) {
/*create your grid and handle your object here*/
/*access attributes of your object with object.attributname*/
}
Is this what you are looking for?
Assuming you are trying to consume the API in JavaScript.
There are two ways way to consume the same
$.getJSON()
$.ajax()
For Details check this out : Difference Between $.getJSON() and $.ajax() in jQuery
JavaScript is very open,flexible and Object oriented at heart.
So the result which you'll get from the above will be JavaScript object and you can play with the same via loops to get your expected result.
function example() {
var data = [{ "Roll": "1", "Name": "A" }, { "Roll": "2", "Name": "B" }, { "Roll": "3", "Name": "C" }];
for (var index = 0; index < data.length; index++) {
var item = data[index];
// Play with your data item for eg
console.log(item.Roll);
console.log(item.Name);
}
// JSON being javascript object
// you can attach properties at run time too
data.Source = "AJAXCall Blah";
// Later in JS same can be used in appropriate scope.
console.log(data.Source);
};
$.each(dataReturnedFromAJAXCall,function(item){
// play with your data here
});
How do I iterate over a JSON structure?
http://www.w3schools.com/js/js_json.asp

MVC 5 ASP.NET Identity 2: Capture user's preference for "remember me" in ExternalLogin

I am using the Identity 2.0 Sample.
I get that by setting isPersistent to true in ExternalLoginCallback action method, the browser will automatically log the user in the next time (within limits) they visit using the same browser. I know that if the user's "remember me" preference was captured and passed to the ExternalLogin action method that it could be put into returnUrl and accessed in ExternalLoginCallback. But how do I get their preference to the ExternalLogin action method?
I don't get in this case how to put a checkbox on the LoginView page and wire things up so that I can process it in the ExternalLogin action method. How can I accomplish this?
Check out the AccountController.ExternalLoginConfirmation action and note the call to await SignInHelper.SignInAsync(user, isPersistent: false, rememberBrowser: false). You can set those values to true, or you can update the ExternalLoginConfirmationViewModel and corresponding ExternalLoginConfirmation view to let the user decide.
BTW: isPersistent will persist the users session across closing and reopening their browser. The rememberBrowser argument is particular to two factor authentication and it sounds like should be left false for your circumstance.
Tangentially related Supporting remember me with two factor authentication
Don't delete any code, just change as follows:
In AccountViewModels, edit to match:
public class ExternalLoginViewModel
{
public string Action { get; set; }
public string ReturnUrl { get; set; }
public string RemembermeExtnl { get; set; }
}
In Account Controller, edit to match:
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
ViewBag.RemembermeExtnl = "f";
return View();
}
public ActionResult ExternalLogin(string provider, string returnUrl, string remembermeExtnl)
{
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl, remembermeExtnl = remembermeExtnl }));
}
public async Task<ActionResult> ExternalLoginCallback(string returnUrl, string remembermeExtnl)
{
...
var result = await SignInHelper.ExternalSignIn(loginInfo, isPersistent: remembermeExtnl=="t");
...
}
In Login view, edit to match:
<section id="socialLoginForm">
#Html.Partial("_ExternalLoginsListPartial", new PG.Models.ExternalLoginViewModel() { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl, RemembermeExtnl = ViewBag.RemembermeExtnl })
<input type="checkbox" id="cbxRemExt" /> Remember me
</section>
In Login view, add this:
<script>
// ** change to eq(1) (2 places!) if your social login form is the second form on the page,
// keep as below if first form is your social login form **
$("#cbxRemExt").change(function () {
var isChecked = $(this).is(":checked");
var actionstring = $('form').eq(0).attr('action');
actionstring = actionstring.replace('RemembermeExtnl=' + (isChecked ? 'f' : 't'), 'RemembermeExtnl=' + (isChecked ? 't' : 'f'))
$('form').eq(0).attr('action', actionstring);
});
</script>
In _ExternalLoginListPartial:
string action = Model.Action;
string returnUrl = Model.ReturnUrl;
string remembermeExtnl = Model.RemembermeExtnl;
using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl, RemembermeExtnl = remembermeExtnl }))

Resources