Handling Potentially Dangerous Query String - c#

My project implements search (from default HTML page) and will redirect to the search page (ASPX page) and I'm using query string to pass the search value. I'm getting potentially dangerous Request.QueryString value server error when language is set to non-english (e.g. thai, cyrillic).
Is there any way to handle this from client side? Currently I can't find a way to handle this from the page itself (Page_Load, Page_PreInit isn't triggering).
Here's the code I used for redirecting:
function Search() {
var searchString = document.getElementById('txtSearch').value;
location.href = "/Search.aspx?search=" + searchString;
}

Adding validateRequest="false" to you .Net Page or Web.config file
OR
you can encode your url vars, adding encodeURIComponent:
function Search() {
var searchString = document.getElementById('txtSearch').value;
location.href = "/Search.aspx?search=" + encodeURIComponent(searchString);
}

If your data is going to look roughly like code you may well have to disable this validation; but then you need to be really sure about your code handling, in particular avoiding XSS and SQL injection attacks. You should be able to set in the aspx validateRequest=false to disable on a per-page basis:
<%# Page validateRequest="false" ...
or globally in the web.config if you need this everywhere.

Related

Updating the displayed URL in the browser using .NET Core

So, I have a certain webpage (view) that I have created. I have a requirement where I need to update the displayed URL in the browser's to show a different path to this page and update the querystring.
Update: I don't want to actually redirect the page, this is merely a cosmetic update. To make the URL appear differently that what it was. It's a requirement our customer support team wanted. :p
Ex.
https://www.myserver.com/error/
I need to update the path in the URL depending on the type of error, like so:
https://www.myserver.com/#/order-completed?var=someguid
My error page handles various situations you see.
I know this is easily done in JS, but I want to be able to do this from my error page Controller.
Could someone lend a hand? I'd super appreciate it!
I think "update the path" means you simply have to redirect the browser to that url. If you are using ASP.NET MVC, you can use the Redirect controller method like this:
return Redirect("https://www.myserver.com/#/order-completed?var=someguid");
So, I went the way of JS afterall. I call it from window.onload in the View.
var fromController = '#ViewData["NewURL"]';
histoy.pushState(null, '', fromController);
In the Controller, in the Index() action
ViewData["NewURL"] = #"/myURL/myview?user=2342434";
return View();

Internet Explorer redirect on all .Net Core project pages

I'm a .Net Core beginner and look for a solution to protect the application from IE.
I got the following code working in Controller:
string userAgent = Request.Headers["User-Agent"].ToString();
var flagsIE = new [] {"MSIE", "Trident"};
if(flagsIE.Any(userAgent.Contains)){
return RedirectToAction("BadBrowser");
}
Now if someone is trying to visit the page using IE, they get redirected to an info-page asking them to use a modern browser. Instead of adding this code to every single Controller.cs I would like to add it on project level, so that it get's executed independent from the location within of the project.
And, I know that this can be achieved with _Layout.cshtml, my question is:
Where and how would I implement a function to get it executed for all requested views withing the project without adding it every single request within Controller.
Thank you in advance.
As Icepickle suggested, in the comments of my question, I used middleware in Startup.cs and got the desired result:
app.Use(async (context,next) =>
{
string userAgent = context.Request.Headers["User-Agent"].ToString();
var IEkeywords = new [] {"MSIE", "Trident"};
if (IEkeywords.Any(userAgent.Contains)){
context.Response.Redirect("/IE/redirect/badbrowser.html");
return;
}
await next();
});
You can try to add js in _Layout.cshtml to detect the browser is IE:
<script>
var isIE = false || !!document.documentMode;
if (isIE) {
window.location.href = "/Home/ForbidInfo";
}
</script>
Then create a view named ForbidInfo under Home controller which to show the message to user that he cannot use the IE to show views.
(Notes: this view's Layout must be null ,or it will enter an endless loop)
#{
ViewData["Title"] = "ForbidInfo";
Layout = null;
}
<h1>Please use a modern browser!</h1>
After these settings, when you running a view in IE, it will be redirected to the FordidInfo page.
If your page does not use _layout, then you need to add the js on the corresponding view separately to ensure that it will not be displayed in IE.
Never do that. Excluding browsers with redirects, is what lead to massive user agent spoofing. Effectively making that AgentId useless. And the way you wrote it, you may get a lot of false-positives.
It is also a bad idea from the early days of the internet, we are hoping to get rid off:
https://en.wikipedia.org/wiki/User_agent#User_agent_spoofing

Is sending Session from javascript safe?

Well, this is a bit weird i think to ask this question, because i am not sure if that's the place to ask that.
OK, into the question..
I have this code
<script>
var session = "<%= Session["User"]%>";
</script>
So, i was thinking, is that safe? let me tell you what i mean..
I have a web api which you can get the name, last name, age and everything about the user with his Session, can i send this web api this session and use it?
Is that a safe thing to do ? in matter of securiy? if not, is there any better way?
EDIT 1:
What am i trying to aaccomplish? simple, i will store the UserId in the session, the UserId will Guid, when the user is loogin in the javascript can send post to an API server to get info, the API will send the UserId from the session.
Is That ok?
Workflow that you describe looks fine. For me it seems safe to use some ID to get more information about some user, especially if this is supposed to be an API, at least, Facebook API uses such principle not being afraid of some hackers :)
My main concern here is the coding style when you try to mix code and view which is not good. If you really need to share some information between client and server sides then I would go with one of these options.
Option # 1 - Cookies
What is the difference between a Session and a Cookie?
You can keep some simple information in a cookie and get it this way :
Client : $.cookie('ID')
Server : Response.Cookies["ID"]
In this case there is no need to put in a mess your client side JS with C# code and cookies will be saved on users PC which means that nobody will see them except him.
Option # 2 - Templates
Server : put all needed information into hidden form or ViewState
Client : take information from hidden form using HTML selectors
Straight answer :
In general, if you worry only about safety then it is fine to use this code, it should not break security of your site.
Although, personally I do not like this approach because :
you will mix code and view, MVC was created to split them
it is not clear where exactly in your view you will put this code and thus it is not clear how you are going to check that this variable was initialized
it may happen that you will put there some value that will break JS syntax and will cause JS error
In my personal opinion, I would replace it with one of the mentioned options.
Option 1 - MVC + JQuery + Cookie Example
public ActionResult Index()
{
string demo = Request.QueryString["MyNameSpace.ID"]; // get value from client
Response.Cookies["MyNameSpace.ID"].Value = "server"; // change value in response
return View();
}
Then in your JS file :
$(document).ready(function() { // make sure server rendered page
var ID = $.cookie('MyNameSpace.ID'); // get cookie value from server
$.cookie('MyNameSpace.ID', 'client'); // update, on the next request server will get it
});
Option 2 - MVC + JQuery + Templates Example
public class OptionsModel // View Model
{
public string ID { get; set; }
public string User { get; set; }
}
public ActionResult Index() // Controller
{
OptionsModel options = new OptionsModel();
options.ID = "server";
return View(options);
}
Your view :
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<OptionsModel>" %>
<%=Html.HiddenFor(m => Model.ID, new { #class = "MyNameSpace:ID" })%>
<%=Html.HiddenFor(m => Model.User, new { #class = "MyNameSpace:User" })%>
Then in your JS file :
$(document).ready(function() { // make sure server rendered page
var options = $('[class^=MyNameSpace]') // get values from hidden fields
options[0] = 'client'; // update data
$.ajax({ data : options }); // create handler to send data back to server
});
Examples for Web Forms do not differ significantly.
The code you have posted will be rendered on the page as so when it hits the client (assuming you are using ASP.NET
<script>
var session = "John Smith";
</script>
This is due to the use of the server side scripting tags <%= %> (https://technet.microsoft.com/en-us/library/cc961121.aspx)
As a note its probably not the best thing in the world to fully expose the session to javascript if that is your intention. At the end of the day it depends what you are storing in there and using it for (but ASP.NET will also use it for certain things) but exposing it just opens another area for someone to attack.
http://www.owasp.org is a great place to learn more about securing your website.

JavaScript in C# ASP MVC issue

We have a web project that takes data from an MS SQL database and uses the Google Visualisation API to display these charts on the web view.
Recently we have added castle windsor so we can configure the application to different users with an XML file. Before we added this, the view worked fine, using the baked in parameters that were needed for this query. For some reason, when we send in the parameters from the XML files (Running with breakpoints shows that the parameters are being passed to the main controller action for the page) the data isn't being returned. here is some of the code for you.
JavaScript
<script type="text/javascript">
var csvDataUrl = '#Url.Action("TradeValuesDataCsv", "Dashboard")';
var jsonDataUrl = '#Url.Action("TradeValuesDataJson", "Dashboard")';
google.load("visualization", "1", { packages: ['table', 'corechart', 'gauge'] });
google.setOnLoadCallback(drawCharts);
drawCharts();
$("body").on({
ajaxStart: function () {
$(this).addClass("loading");
},
ajaxStop: function () {
$(this).removeClass("loading");
}
});
function drawCharts() {
var queryString = 'platform=' + $('#PlatformDropDownList').val();
queryString += '&startDate=' + $('#startDatePicker').val();
queryString += '&endDate=' + $('#endDatePicker').val();
queryString += '&model=' + $('#ModelDropDownList').val();
queryString += '&eventType=' + '#Model.EventType';
queryString += '&parameterName=' + '#Model.ParameterName';
$.ajax({
type: "POST",
url: jsonDataUrl,
data: queryString,
statusCode: {
200: function (r) {
drawToolbar(queryString);
drawTable(r);
drawChart(r);
},
400: function (r) {
},
500: function (r) {
}
}
});
}
Main controller Method for this page:
public ActionResult ActionResultName(EventTypeParameterNameEditModel model)
{
var viewModel = new EventTypeParameterNameViewModel(_queryMenuSpecific);
viewModel.EventType = model.EventType;
viewModel.ParameterName = model.ParameterName;
PopulateFilters(viewModel);
return this.View(viewModel);
}
Retrieve the JSON Data Controller Method:
public ActionResult ActionResultNameJson(EventTypeParameterNameEditModel filters)
{
List<CustomDataType> results = this.GetTradeValues(filters);
return this.Json(results, JsonRequestBehavior.AllowGet);
}
EDIT I have managed to find a solution, even if it is a rather messy one. I have some filters built into the page that allow the user to filter by device and by OS, and these were being populated on the page load with 'undefined'. I didn't spot this first time round with NHProf Running, but this wasn't happening when the page loaded before we configured the input to be from XML. I will add this as an answer and accept it and close the question. Thanks everyone for your attempts to help. Starting to really like this community. Perfect place to find help as a Graduate Developer.
Yep. I'm not a Razor syntax expert but I think these property references are probably your problem. I suspect razor is going to tend to avoid asserting itself inside strings being used in statements with properties in JS contexts. Or you could try implementing as getter functions which would probably work. Otherwise an # and a . in a string could easily lead to confusing mixups with email addresses when it's not an obvious method call:
queryString += '&eventType=' + '#Model.EventType';
queryString += '&parameterName=' + '#Model.ParameterName';
As a general rule in any server to client-side scenario, my advice is to confine JavaScript direct from the back end to JSON objects only. That way you have more granular control over what's going on on both sides of the http request wall and your client-side devs don't have to figure where stuff is getting built if there's a short-term need to quickly modify. In general, don't build behavioral code with other code if you can avoid it.
I couldn't convince my .net MVC boss at first but he slowly came around to the idea on his own months later.
We also store a URL base path along with some other context-shifting params in a standard JSON object that loads on every page so the JS devs can add these things linked JS files rather than have to work with JS in the HTML (I don't recall why but document.location wasn't always going to work).
Lastly, try to keep the JS out of the HTML. Link it. It seems like a pain from a procedural POV but trust me. It makes life much easier when you are juggling 3 major concerns as one ball each rather than all in the same jumbled HTML/template mess.
It turned out that the problem was not in my Javascript. I have some filters in there that allow the user to filter the results my model and operating system and date and what not. These were being automatically populated on page load with 'undefined' which is not an option in the database. I added something to catch that in the call to the query and it seemed to solve the problem.

How to retrieve site root url?

I need to get the url of the site so that I render a user control on only the main page. I need to check for http://foo.com, http://www.foo.com, and foo.com. I am a bit stumped as to how check for all 3. I tried the following which does not work.
string domainName = Request.Url.Host.ToString();
if (domainName == "http://nomorecocktails.com" | Request.Url.Host.Contains("default.aspx"))
{ //code to push user control to page
Also tried
var url = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + "/";
Any thoughts?
You need to check if the Request.Path property is equal to / or /Default.aspx or whatever your "main page" is. The domain name is completely irrelevant. What if I accessed your site via http://192.56.17.205/, and similarly, what if your server switched IP addresses? Your domain check would fail.
If you utilize the QueryString to display different content, you'll also need to check Request.QueryString.
Documentation for Request.Path:
http://msdn.microsoft.com/en-us/library/system.web.httprequest.path.aspx
Documentation for Request.QueryString:
http://msdn.microsoft.com/en-us/library/system.web.httprequest.querystring.aspx
If you need the user control to only appear on the main page (I'm assuming you mean home page), then add the code to call the user control to the code behind of that file.
If this code is stored in the master page, then you can reference it like:
Master.FindControl("UserControlID");
If you are only using the one web form (ie. just Default.aspx), then you can check that no relevant query strings are included in the URL, and display only if this is the case:
if (Request.QueryString["q"] == null){
//user control code
}
However if you are using this technique then I would recommend using multiple web forms using master pages in the future to structure your application better.
The ASP.NET website has some good tutorials on how to do this:
http://www.asp.net/web-forms/tutorials/master-pages

Categories