Preventing crf attacks on ajax requests in asp.net web forms - asp.net

How can I prevent csrf attacks on ajax requests in a asp.net webforms application

You could create a token and keep it in Session["CSRF"] and render the same in HiddenField of everypage.
protected HiddenField CSRF { get; set; }
protected void page_load(object s, args[] e) {
if(Session["CSRF"]!=null) {
this.CSRF=Session["CSRF"];
}
else {
Session["CSRF"]=Guid.NewGuid().ToString();
this.CSRF=Session["CSRF"];
}
}
So whenever you send a request add it as a data parameter and check it in the server side code.
Pass this CSRF HiddenField id for every request.
For ASP.Net Ajax calls you could use ViewState["CSRF"], since by default update panel will send the Page's viewstate also :)
for jQuery ajax
var csrf_token = '<%= csrf_value %>';
The below code will add this token for all the ajax requests
$("body").bind("ajaxSend", function(elm, xhr, s){
if (s.type == "POST") {
xhr.setRequestHeader('X-CSRF-Token', csrf_token);
}
});

You should have a look at this link: Preventing Cross-Site Request Forgery (CSRF) Attacks
In short: anti-forgery tokens, which are provided as part of the ASP.NET MVC framework. Since however you are using webforms, it might be a little bit more complicated but it is possible to have an ASP.NET website running both webforms and MVC (or have a look at this answered question: AntiForgery implementation in Asp.net Forms).
EDIT: Also, to protect jQuery calls, you could use an anti forgery token and print it client side (as described here:
var csrf_token = '<%= token_value %>';
$("body").bind("ajaxSend", function(elm, xhr, s){
if (s.type == "POST") {
xhr.setRequestHeader('X-CSRF-Token', csrf_token);
}
});

Related

Check logged user with normal and ajax request

I use interceptor to check if a user is logged in every controller call like this :
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) {
if(request.getSession().getAttribute("user") == null) {
response.sendRedirect("redirect:/login?next="+
URLEncoder.encode(
request.getRequestURL().toString() + "" +
(request.getQueryString() != null ? "?" + request.getQueryString() : "")
,"utf-8");
return false;
}
return true;
}
It work fine for normal request but for ajax request i can't make a response.sendRedirect(..).
How to know if it's a ajax or normal request ?
How can i do it like if i got a ajax error ?
$.ajax({
.....
success : function(data) { ...... },
error : function(){
alert("login error"); // or
document.location = '/path/login' // or something else
}
});
There a other way to handle it rather than using interceptor ?
1. How to know if it's a ajax or normal request ?
You can check inside your interceptor for the existence of the X-Requested-With header. This header is always added to the ajax request by the jQuery library (to my knowing almost all major js libraries add it as well) with the purpose of preventing the Cross-Site request forgery. To figure out if the request is ajax, you can write your preHandle method like
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) {
String requestedWith = request.getHeader("X-Requested-With");
Boolean isAjax = requestedWith != null ? "XMLHttpRequest".equals(requestedWith) : false;
...
}
2. How can i do it like if i got a ajax error ?
As you've already noticed, ajax request don't recognize server side redirects, as the intention of the server side redirects is to be transparent to the client. In the case of an ajax request, don't do redirect rather set some status code to the response e.g. response.setStatus(respCode) or add a custom header e.g. response.setHeader("Location", "/path/login"), and read it through in the jQuery's complete method which is a callback that follows after either success or error, e.g.
$.ajax({
//...
complete: function(xhr, textStatus) {
console.log(xhr.status);
console.log(xhr.getResponseHeader('Location'));
// do something e.g. redirect
}
});
3. There a other way to handle it rather than using interceptor ?
Definitely. Checkout Spring Security. Its a framework, and adds a bit to the learning curve, but its well worth it. It will add much more than a custom solution, e.g. you'll get authorization mechanism on top of the authentication. When your application matures, you'll notice that the straigthforward implementation that you're on to now, has quite a few security flaws that are not hard to exploit e.g. session fixation, where spring security can easily protect you. There's plenty of examples online, and you'll get better support here on the SO in comparison to any custom solution. You can unit test it, an asset I personally value very much
You could simply:
Refuse ajax requests before the user is properly logged in
once the user logs in, set a security token in the session or somewhere
pass that token in the ajax request and use that token to validate on the server side prehandle
in your case you would check the existence of the token before running into the code
Also, the preHandle does not have to apply to every routes, you could also have different routes each with different authorisation, prehandle, code.

In ASP.NET I Need to update a control, run a task, then update control again

I am quite new to ASP.NET, but have a good understanding of WPF so I hoped this would help, but I guess not.
I want to, as the title says, update a span.innerHTML then run a asynchronous task, the update the span again.
I've tried this
Status.InnerText = "Connecting..."
Await Task.Run(Sub() Thread.Sleep(5000)) 'simulating a long running process
Status.InnerText = "Connected"
but it only updates when the task completes.
I have
<%# Page Language="vb" Async="true" AsyncTimeout="20"
in my aspx page. What am I missing?
Classic ASP really confuses things, IMO. ASP.NET MVC remains truer to the actual HTTP lifecycle. What actually happens with HTTP is that the client (browser) sends an HTTP request to the server, which then constructs a single HTTP response to send back. In the case of a web page request, that HTTP response includes all the HTML.
So, all the work your handler does on the server side "constructing" the HTML is all done before the response is sent. Nothing can be sent to the client until the handler is complete. Await will not help you in your situation. (As an aside: Await is certainly useful on the server side; it helps with scalability. Await will yield the request thread back to the thread pool; it just doesn't yield all the way to the client browser).
A more proper technology to use in your case would be SignalR, which supports persistent connections with two-way communication.
For more information, see my blog post on how async doesn't change the HTTP protocol, or my recent MSDN article on async ASP.NET.
Unsure if this is an option for you - depending on "where" you (really) want async, Javascript sounds ideal.
Trivial example:
Given an ASP.Net Form:
<form id="form1" runat="server">
<div>
<asp:Label runat="server" ID="Status" />
</div>
</form>
with Jquery:
$(function () {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: "foo.aspx/HelloWorld",
data: {}
}).done(function (d) {
$("#<%:Status.ClientID%>").append("..." + d.d);
}).fail(function (f) {
//....
}).always(function (a) {
//....
});
});
WebForm "code-behind" (for "foo.aspx" above), using WebMethod:
protected void Page_Load(object sender, EventArgs e)
{
Status.Text = "Initial hello at " + DateTime.Now;
}
[WebMethod]
public static string HelloWorld()
{
Thread.Sleep(5000);
return "And hello again from WebMethod " + DateTime.Now;
}
You should see the text "update" on the browser after 5 seconds, without a refresh/postback:
Initial hello at 11/22/2014 4:40:55 PM...And hello again from WebMethod 11/22/2014 4:41:00 PM
Hth...

Prevent FormsAuthenticationModule of intercepting ASP.NET Web API responses

In ASP.NET the FormsAuthenticationModule intercepts any HTTP 401, and returns an HTTP 302 redirection to the login page. This is a pain for AJAX, since you ask for json and get the login page in html, but the status code is HTTP 200.
What is the way of avoid this interception in ASP.NET Web API ?
In ASP.NET MVC4 it is very easy to prevent this interception by ending explicitly the connection:
public class MyMvcAuthFilter:AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest() && !filterContext.IsChildAction)
{
filterContext.Result = new HttpStatusCodeResult(401);
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.HttpContext.Response.SuppressContent = true;
filterContext.HttpContext.Response.End();
}
else
base.HandleUnauthorizedRequest(filterContext);
}
}
But in ASP.NET Web API I cannot end the connection explicitly, so even when I use this code the FormsAuthenticationModule intercepts the response and sends a redirection to the login page:
public class MyWebApiAuth: AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if(actionContext.Request.Headers.Any(h=>h.Key.Equals("X-Requested-With",StringComparison.OrdinalIgnoreCase)))
{
var xhr = actionContext.Request.Headers.Single(h => h.Key.Equals("X-Requested-With", StringComparison.OrdinalIgnoreCase)).Value.First();
if (xhr.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase))
{
// this does not work either
//throw new HttpResponseException(HttpStatusCode.Unauthorized);
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
return;
}
}
base.HandleUnauthorizedRequest(actionContext);
}
}
What is the way of avoiding this behaviour in ASP.NET Web API? I have been taking a look, and I could not find a way of do it.
Regards.
PS: I cannot believe that this is 2012 and this issue is still on.
In case someone's interested in dealing with the same issue in ASP.NET MVC app using the Authorize attribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class Authorize2Attribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
filterContext.Result = new HttpStatusCodeResult((int) HttpStatusCode.Forbidden);
}
else
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
}
base.HandleUnauthorizedRequest(filterContext);
}
}
}
This way browser properly distinguishes between Forbidden and Unauthorized requests..
The release notes for MVC 4 RC imply this has been resolved since the Beta - which are you using?
http://www.asp.net/whitepapers/mvc4-release-notes
Unauthorized requests handled by ASP.NET Web API return 401 Unauthroized: Unauthorized requests handled by ASP.NET Web API now return a standard 401 Unauthorized response instead of redirecting the user agent to a login form so that the response can be handled by an Ajax client.
Looking into the source code for MVC there appears to be an functionality added via SuppressFormsAuthRedirectModule.cs
http://aspnetwebstack.codeplex.com/SourceControl/network/forks/BradWilson/AspNetWebStack/changeset/changes/ae1164a2e339#src%2fSystem.Web.Http.WebHost%2fHttpControllerHandler.cs.
internal static bool GetEnabled(NameValueCollection appSettings)
{
// anything but "false" will return true, which is the default behavior
So it looks this this is enabled by default and RC should fix your issue without any heroics... as a side point it looks like you can disable this new module using AppSettings http://d.hatena.ne.jp/shiba-yan/20120430/1335787815:
<appSettings>
<Add Key = "webapi:EnableSuppressRedirect" value = "false" />
</appSettings>
Edit (example and clarification)
I have now created an example for this approach on GitHub. The new redirection suppression requires that you use the two correct "Authorise" attribute's; MVC Web [System.Web.Mvc.Authorize] and Web API [System.Web.Http.Authorize] in the controllers AND/OR in the global filters Link.
This example does however draw out a limitation of the approach. It appears that the "authorisation" nodes in the web.config will always take priority over MVC routes e.g. config like this will override your rules and still redirect to login:
<system.web>
<authentication mode="Forms">
</authentication>
<authorization>
<deny users="?"/> //will deny anonymous users to all routes including WebApi
</authorization>
</system.web>
Sadly opening this up for some url routes using the Location element doesn't appear to work and the WebApi calls will continue to be intercepted and redirected to login.
Solutions
For MVC applications I am simply suggest removing the config from Web.Config and sticking with Global filters and Attributes in the code.
If you must use the authorisation nodes in Web.Config for MVC or have a Hybrid ASP.NET and WebApi application then #PilotBob - in the comments below - has found that sub folders and multiple Web.Config's can be used to have your cake and eat it.
I was able to get around the deny anonymous setting in web.config by setting the following property:
Request.RequestContext.HttpContext.SkipAuthorization = true;
I do this after some checks against the Request object in the Application_BeginRequest method in Global.asax.cs, like the RawURL property and other header information to make sure the request is accessing an area that I want to allow anonymous access to. I still perform authentication/authorization once the API action is called.

ASP.NET 2.0 JQuery AJAX Login

I'm trying to figure out how to implement an AJAX login for a ASP.NET 2.0 site with Jquery. I already have a implemented other simple Jquery AJAX application on the site, but I'm unsure how to convert over the standard login control to POST via AJAX. Should I expose the login.aspx page methods? Any help would be great.
Here are some ideas on how this can be implemented. This is not full code, but it should be enough to get you started on the right track.
You need to create your own login form fields for username/password.
Create an ASMX or WCF WebService for authentication with a method similar to this:
[WebMethod]
public string AuthenticateUser(string username, string password)
{
string result = "Invalid Username or Password";
if(Membership.ValidateUser(userName, password))
{
FormsAuthentication.SetAuthCookie(u.UserName, false);
result = "successful";
}
return result;
}
Then from your login button's click event you can use jQuery ajax to post the username/password to the webservice:
$.ajax({
type: "POST",
url: "WebService.asmx/AuthenticateUser",
data: "{username:"+$('#txtUsername').val()+",password:"+$('#txtPassword').val()+"}",
success: function(result) {
alert(result);
//if(result=='successful')
// redirectUser to the home page
}
});
With this solution there is a big security problem that username and password will be send in plain-text format. so you should use SSL or hash these data in some way.
take a look here

Cross browser scripting proxy

I am developing some client side Javascript that is using some JSON web services on a different domain. I have read that some browsers do not allow cross-domain scripting and that I should create a proxy on my local server to serve the data.
Can someone please point me to a simple example of how to do this in ASP.Net?
Generally speaking, the proxy runs on your web server - most likely IIS in your case - and 'relays' the requests to another server on a different domain.
Here's an example of one implemented in C# .NET
Fast, Streaming AJAX proxy
You may be able to avoid a proxy by using a technique like JSONP. Assuming the web service you're talking to supports JSONP (for example, Flickr or Twitter both offer a JSONP API) or you have control over the data the web service sends back, you can send JSON data between domains using a library that features JSONP.
For example, in jQuery, you can make a remote JSON call:
jQuery.getJSON("http://www.someothersite.com/webservice?callback=?", function(result)
{
doStuffWithResult(result);
});
Because the call is to another domain, jQuery automatically uses some trickery to make a cross domain call. jQuery will automatically replace the ? in the url with a callback function name that the web service can use to format the JSON data being returned.
If you're the one controlling the web service, you can handle the JSONP request by getting the request parameter called "callback" which will be set to the callback function name you need to use. The callback function takes one parameter, which is the JSON data you want to send back. So, if the callback parameter is set to "jsonp2342342", you'll want the web service to respond like this:
jsonp2342342({key: value, key2: value});
If the web service you're using already supports JSONP, you won't have to worry about doing the formatting yourself.
You can write a simple .NET page to retrieve the remote page and display it on your site:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.IO;
namespace Proxy
{
public partial class _Proxy : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string proxyURL = string.Empty;
try
{
proxyURL = HttpUtility.UrlDecode(Request.QueryString["u"].ToString());
}
catch { }
if (proxyURL != string.Empty)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(proxyURL);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode.ToString().ToLower() == "ok")
{
string contentType = response.ContentType;
Stream content = response.GetResponseStream();
StreamReader contentReader = new StreamReader(content);
Response.ContentType = contentType;
Response.Write(contentReader.ReadToEnd());
}
}
}
}
}
See my post about it: http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/
No browsers allow cross-domain scripting, and although w3c has left space for this in its recommendation on the xmlHTTPRequest-object, we still have to wait for some time to see it implemented in a secure way ...
I'll give a pseudocode version for people seeking a general answer to the question.
SomeAjaxAbstraction.Request('proxyScript', {
parameters: {
address: 'http://somewhere.com/someapi?some=query'
}
});
Then in proxyScript:
var address = GET['address'];
if(ValidUrl(address) && ConnectionAllowed(address)) {
// Validating address and whitelisting services is an exercise to the reader
var response = SomeHttpGetFunction(address);
echo XssAndBadStuffFilter(response);
} else {
// Handle errors
}

Resources