All posts by bryan

Vertical And Horizontal Privilege Escalation

What is Vertical And Horizontal Privilege Escalation?  Does your application support for this internally authorisation verification of work?  I expect not, it is really an over sight of the architecture and application planning that this is missed out and more importantly when it becomes an issue it is more often than not too late to implement any changes.

So what is Vertical And Horizontal Privilege Escalation?  

Privilege escalation is the act of exploiting a bug, design flaw or configuration oversight in an operating system or software application to gain elevated access to resources that are normally protected from an application or user. The result is that an application with more privileges than intended by the application developer or system administrator can perform unauthorized actions.

You may find that you have alternative methods to protect against privilege escalation:

  • Authorize attribute: This is used to authorize a user or role to access any resource in the application after authenticated. This helps to have User and Role level protections.
  • Http Referrer Check: This is to prevent an URL request which is not from the site, but from an external link or the link directly executed at the browser navigation
  • Anti Forgery Token: This is a powerful option to prevent any hidden field manipulation while form posting and prevents Cross-Site Request Forgery
  • HTML Encoding: It is advised to encode all user inputs to prevent Cross Site Scripting attack/ XSS attack etc.,
  • Encryption of Query string parameters. This is good way to prevent manipulation of query string parameters. 
  • URL Activity Tampering, we provide a key in the URL that can only be used for that URL

Even though you may not support Privilege Escalation directly you can place a front line of defence, Privilege escalation means a user receives privileges they are not entitled to. These privileges can be used to change information, view private information, or install unwanted programs such as viruses. It usually occurs when a system has a bug that allows security to be bypassed or, alternatively, has flawed design assumptions about how it will be used. Privilege escalation occurs in two forms:

  • Vertical privilege escalation, also known as privilege elevation, where a lower privilege user or application accesses functions or content reserved for higher privilege users or applications 
  • Horizontal privilege escalation, where a normal user accesses functions or content reserved for other normal users
I hope this help you understand, that planning and understanding issues from the outset is so important.

Make Fake MVC Objects for testing

If you need to create some Fake MVC objects for testing MVC objects then here you are:

FakeControllerContext

using System.Collections.Specialized;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;

using MvcContrib.TestHelper.Fakes;

public class FakeControllerContext : ControllerContext
{
    public FakeControllerContext(IController controller)
        : this(controller, null, null, null, null, null, null)
    {
    }

    public FakeControllerContext(IController controller, HttpCookieCollection cookies)
        : this(controller, null, null, null, null, cookies, null)
    {
    }

    public FakeControllerContext(IController controller, SessionStateItemCollection sessionItems)
        : this(controller, null, null, null, null, null, sessionItems)
    {
    }
        
    public FakeControllerContext(IController controller, NameValueCollection formParams)
        : this(controller, null, null, formParams, null, null, null)
    {
    }
        
    public FakeControllerContext(IController controller, NameValueCollection formParams, NameValueCollection queryStringParams)
        : this(controller, null, null, formParams, queryStringParams, null, null)
    {
    }
        
    public FakeControllerContext(IController controller, string userName)
        : this(controller, userName, null, null, null, null, null)
    {
    }
        
    public FakeControllerContext(IController controller, string userName, string[] roles)
        : this(controller, userName, roles, null, null, null, null)
    {
    }
        
    public FakeControllerContext
        (
            IController controller,
            string userName,
            string[] roles,
            NameValueCollection formParams,
            NameValueCollection queryStringParams,
            HttpCookieCollection cookies,
            SessionStateItemCollection sessionItems
        )
        : base(new FakeHttpContext(new FakePrincipal(new FakeIdentity(userName), roles), formParams, queryStringParams, cookies, sessionItems), new RouteData(), (Controller)controller)
    { }
}

FakeHttpContext

using System;
using System.Collections.Specialized;
using System.Security.Principal;
using System.Web;
using System.Web.SessionState;

public class FakeHttpContext : HttpContextBase
{
    private readonly FakePrincipal principal;
    private readonly NameValueCollection formParams;
    private readonly NameValueCollection queryStringParams;
    private readonly HttpCookieCollection cookies;
    private readonly SessionStateItemCollection sessionItems;

    public FakeHttpContext(FakePrincipal principal, NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies, SessionStateItemCollection sessionItems)
    {
        this.principal = principal;
        this.formParams = formParams;
        this.queryStringParams = queryStringParams;
        this.cookies = cookies;
        this.sessionItems = sessionItems;
    }

    public override HttpRequestBase Request
    {
        get
        {
            return new FakeHttpRequest(this.formParams, this.queryStringParams, this.cookies);
        }
    }

    public override IPrincipal User
    {
        get
        {
            return this.principal;
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public override HttpSessionStateBase Session
    {
        get
        {
            return this.sessionItems == null ? null : new FakeHttpSessionState(this.sessionItems);
        }
    }

}

FakeHttpRequest

using System.Collections.Specialized;
using System.Web;

public class FakeHttpRequest : HttpRequestBase
{
    private readonly NameValueCollection formParams;
    private readonly NameValueCollection queryStringParams;
    private readonly HttpCookieCollection cookies;

    public FakeHttpRequest(NameValueCollection formParams, NameValueCollection queryStringParams, HttpCookieCollection cookies)
    {
        this.formParams = formParams;
        this.queryStringParams = queryStringParams;
        this.cookies = cookies;
    }

    public override NameValueCollection Form
    {
        get
        {
            return this.formParams;
        }
    }

    public override NameValueCollection QueryString
    {
        get
        {
            return this.queryStringParams;
        }
    }

    public override HttpCookieCollection Cookies
    {
        get
        {
            return this.cookies;
        }
    }
}

FakeHttpSessionState

using System.Collections;
using System.Collections.Specialized;
using System.Web;
using System.Web.SessionState;

public class FakeHttpSessionState : HttpSessionStateBase
{
    private readonly SessionStateItemCollection sessionItems;

    public FakeHttpSessionState(SessionStateItemCollection sessionItems)
    {
        this.sessionItems = sessionItems;
    }

    public override void Add(string name, object value)
    {
        this.sessionItems[name] = value;
    }

    public override int Count
    {
        get
        {
            return this.sessionItems.Count;
        }
    }

    public override IEnumerator GetEnumerator()
    {
        return this.sessionItems.GetEnumerator();
    }

    public override NameObjectCollectionBase.KeysCollection Keys
    {
        get
        {
            return this.sessionItems.Keys;
        }
    }

    public override object this[string name]
    {
        get
        {
            return this.sessionItems[name];
        }
        set
        {
            this.sessionItems[name] = value;
        }
    }

    public override object this[int index]
    {
        get
        {
            return this.sessionItems[index];
        }
        set
        {
            this.sessionItems[index] = value;
        }
    }

    public override void Remove(string name)
    {
        this.sessionItems.Remove(name);
    }
}

FakePrincipal

using System.Linq;
using System.Security.Principal;

public class FakePrincipal : IPrincipal
{
    private readonly IIdentity identity;
    private readonly string[] roles;

    public FakePrincipal(IIdentity identity, string[] roles)
    {
        this.identity = identity;
        this.roles = roles;
    }

    public IIdentity Identity
    {
        get { return this.identity; }
    }

    public bool IsInRole(string role)
    {
        return this.roles != null && this.roles.Contains(role);
    }
}

The original article and source is from Stephen Walter Faking the Controller Context

Disclaimer Page using MVC

If you ever need a disclaimer page in MVC, there are a few things you need to consider, the first is you should not be able to get to a page without agreeing to the disclaimer and if you have to re-login then you need to be presented with the disclaimer page again.

I’ve opted to use an Attribute, which can be used on a Controller.

[AgreeToDisclaimer]
public class Page1Controller : Controller
{

This makes things very simple and as easy to use as the Authorise Attribute.

The implementation of the AgreeToDisclaimer inherits the Authorize Attribute, which over rides the AuthorizeCore and HandleUnauthorizedRequest methods

public class AgreeToDisclaimerAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
            throw new ArgumentNullException("httpContext");

        if (!this.HasAgreedToDisclaimer(httpContext))
            return false;

        return true;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        // Returns HTTP 401 by default 
        filterContext.Result = new RedirectToRouteResult(
            new RouteValueDictionary 
    {
        { "action", "index" },
        { "controller", "Disclaimer" }
    });
    }

    private bool HasAgreedToDisclaimer(HttpContextBase current)
    {
        return current != null && current.User != null ? (bool)current.User.Disclaimer() : false;
    }
}

You’ll have noticed that I have extended the User object to include Disclaimer, this way when the user session expires or the user logs out the current user is null

As for extending the User object this again is quite simple:

public static class IPrincipalExtension
{
    /// <summary>
    /// ObjectCache references the objects with WeakReferences for avoiding memory leaks.
    /// </summary>
    public static ConditionalWeakTable<object, Dictionary<string, object>> ObjectCache = new ConditionalWeakTable<object, Dictionary<string, object>>();

    public static void SetValue<T>(this T obj, string name, object value) where T : class
    {
        Dictionary<string, object> properties = ObjectCache.GetOrCreateValue(obj);

        if (properties.ContainsKey(name))
            properties[name] = value;
        else
            properties.Add(name, value);
    }

    public static T GetValue<T>(this object obj, object name)
    {
        Dictionary<string, object> properties;
        if (ObjectCache.TryGetValue(obj, out properties) && properties.ContainsKey(name.ToString()))
            return (T)properties[name.ToString()];
        else
            return default(T);
    }

    public static object GetValue(this object obj, bool name)
    {
        return obj.GetValue<object>(name);
    }

    public static bool Disclaimer(this IPrincipal principal)
    {
        return principal.GetValue<bool>("Disclaimer");
    }

    public static void SetDisclaimer(this IPrincipal principal, bool value)
    {
        principal.SetValue("Disclaimer", value);
    }
}

What is the difference between running in Debug and Release mode?

Is the only difference between Debug and Release configurations that Debug have the DEBUG constant defined, and Release produces the Optimize code?

  1. Are there performance differences between these two configurations. Are there any specific type of code that will cause big differences in performance here, or is it actually not that important?
  2. Are there any type of code that will run fine under the Debug configuration that might fail under Release configuration, or can you be certain that code that is tested and working fine under the Debug configuration will also work fine under Release configuration.

The C# compiler itself doesn’t alter the emitted IL a great deal in the Release build. Notable is that it no longer emits the NOP opcodes that allow you to set a breakpoint on a curly brace. The big one is the optimizer that’s built into the JIT compiler. It does make the following optimizations:

  • Method inlining. A method call is replaced by the injecting the code of the method. This is a big one, it makes property accessors essentially free.
  • CPU register allocation. Local variables and method arguments can stay stored in a CPU register without ever (or less frequently) being stored back to the stack frame. This is a big one, notable for making debugging optimized code so difficult. And giving the volatile keyword a meaning.
  • Array index checking elimination. An important optimization when working with arrays (all .NET collection classes use an array internally). When the JIT compiler can verify that a loop never indexes an array out of bounds then it will eliminate the index check. Big one.
  • Loop unrolling. Short loops (up to 4) with small bodies are eliminated by repeating the code in the loop body. Avoids the branch misprediction penalty.
  • Dead code elimination. A statement like if (false) { /…/ } gets completely eliminated. This can occur due to constant folding and inlining. Other cases is where the JIT compiler can determine that the code has no possible side-effect. This optimization is what makes profiling code so tricky.
  • Code hoisting. Code inside a loop that is not affected by the loop can be moved out of the loop.
  • Common sub-expression elimination. x = y + 4; z = y + 4; becomes z = x;
  • Constant folding. x = 1 + 2; becomes x = 3; This simple example is caught early by the compiler, but happens at JIT time when other optimizations make this possible.
  • Copy propagation. x = a; y = x; becomes y = a; This helps the register allocator make better decisions. It is a big deal in the x86 jitter because it has so few registers to work with. Having it select the right ones is critical to perf.

These are very important optimizations that can make a great deal of difference when, for example, you profile the Debug build of your app and compare it to the Release build. That only really matters though when the code is on your critical path, the 5 to 10% of the code you write that actually affects the perf of your program. The JIT optimizer isn’t smart enough to know up front what is critical, it can only apply the “turn it to eleven” dial for all the code.

The effective result of these optimizations on your program’s execution time is often affected by code that runs elsewhere. Reading a file, executing a dbase query, etc. Making the work the JIT optimizer does completely invisible. It doesn’t mind though 🙂

The JIT optimizer is pretty reliable code, mostly because it has been put to the test millions of times. It is extremely rare to have problems in the Release build version of your program. It does happen however. Both the x64 and the x86 jitters have had problems with structs. The x86 jitter has trouble with floating point consistency, producing subtly different results when the intermediates of a floating point calculation are kept in a FPU register at 80-bit precision instead of getting truncated when flushed to memory.

Reference

Unit Testing a Private Method

With Visual Studio keep changing the way you create unit tests I thought I’d document down how to test a private method the easy way.

Here is a simple HomeController and we want to test that the GetPageSize method return 20 in a unit test.

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var pageSize = GetPageSize();
        return View(pageSize);
    }

    private int GetPageSize()
    {
        return 20;
    }
}

As GetPageSize is a private method we’ll need to use the PrivateObject class to return the methods result, this is quite easy, from the Unit Test project make sure you have a reference to your MVC project and then reference the HomeController and invoke the method you need the result back from:

[TestMethod]
public void CheckPageSizeIs20()
{
    PrivateObject privateObject = new PrivateObject(typeof(HomeController));
    int pageSize;
    pageSize = (int)privateObject.Invoke("GetPageSize");

    Assert.AreEqual(20, pageSize);
}

If you need to pass in parameters to the private method then you can pass in an anonymous type

var actual = (IEnumerable<ActivityData>)privateObject.Invoke("GetAllUnassignedJobs", new object[] { filterData, uniqueJobs });

Reference: How to test a class member that is not public

Thanks to Karthik for googleing the answer

Concurrency

Hisenbugs

Hard to test concurrency, useally have test over a 5 week period and when you find the issues it is hard to reproduce

Lots of threads, and the behaviour of the program changes state and the interleaving changes and therefore it becomes hard to reproduce the concurrency issue, this is hope based testing, running on n number of machines and hope that we find a concurrency bug.  This is not only costly, in having the ability to run all the processes on multiple machines, the resource involved in managing the logistics for running all the tests and more importantly if you find a concurrency issue can you reproduce the bug.

So what we need is to be able to control the interleaving of the programme, we need to be able to run again and again in a loop, and record the interleaving and then if we find a bug having the ability to repeat that test and interleaving to reproduce that bug

 

CHESS is a tool for systematic and disciplined concurrency testing. Given a concurrent test, CHESS systematically enumerates the possible thread schedules to find hard-to-find concurrency errors, including assertion violations, deadlocks, data-races, and atomicity violations.

 

http://msdn.microsoft.com/en-us/library/ms182480%28v=vs.90%29/

Tools And Techniques To Identify Concurrency Issues

http://msdn.microsoft.com/en-us/magazine/cc546569/

hanselminutes_0136.pdf (94.14 kb)

Visual Studio 2013 requires Internet Explorer 10 – how to install without IE10

Not my fix, but it works

@ECHO OFF

:IE10HACK 
REG ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer" /v Version /t REG_SZ /d "9.10.9200.16384" /f 
REG ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer" /v svcVersion /t REG_SZ /d "10.0.9200.16384" /f 
REG ADD "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v Version /t REG_SZ /d "9.10.9200.16384" /f 
REG ADD "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v svcVersion /t REG_SZ /d "10.0.9200.16384" /f 
GOTO EXIT

:REVERTIE 
REG DELETE "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer" /v svcVersion 
REG DELETE "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v svcVersion 
REG ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer" /v Version /t REG_SZ /d "8.0.7601.17514" /f 
REG ADD "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v Version /t REG_SZ /d "8.0.7601.17514" /f 
GOTO EXIT

:EXIT

credit goses to Jimmy http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4153040-remove-the-requirment-for-internet-explorer-10-to-

URL Activity Tampering and how to prevent it in MVC

No web applications are developed without concerning the security issues. But it is not sure whether the security measures are implemented correctly and the applications are well protected. We could see a lot of web applications query string parameters in plain string which are easy to manipulate and way to escalate restricted resources. Even the URL parameters are encrypted there is still a chance of a bruteforce attack by manipulating the encrypted hash and it yields when the database is large where the chance of matching a random hash is high. So it is clear the importance to protect the URL in the web application is necessary for all programming platforms. Here, this is discussed with reference to ASP.NET MVC and the utility class is presented.

.NET Framework has a lot of improved methods for security and the MVC framework introduced new security methods like AntiForgeryToken that I discussed in a previous article Preventing Cross Site Request Forgery. Let us have a brief look at the security methods in general practice.

  • Authorize attribute: This is useful to authorize a user or role to access any resource in the application after authenticated. This helps to have User and Role level protections.
  • Http Referrer Check: This is a general method not confined to .NET. This is to prevent an URL request which is not from the site, but from an external link or the link directly executed at the browser navigation
  • Anti Forgery Token: This is a powerful option to prevent any hidden field manipulation while form posting and prevents Cross-Site Request Forgery
  • HTML Encoding: It is advised to encode all user inputs to prevent Cross Site Scripting attack/ XSS attack etc.,
  • Protection against SQL injections
  • Encryption of Query string parameters. This is good way to prevent manipulation of query string parameters. But this is not a complete protection, still vulnerable for a brute force attack.

Even though all the above methods are available, .NET framework doesn’t provide an inbuilt functionality for protecting the URL parameters. Its URL authorization technique protects the whole URL, but not parts of the URL which are still vulnerable for manipulation. This piece of coding here helps to easily implement all these security methods with special importance to protecting the URL parameters. Creating a URL hash is not new but yet it is not a common practice in the industry though it is an important concern. So it would be important to share a piece of code for the easy implementation of this method in ASP.NET MVC.

The basic idea is simple, encrypting the URL parameters along with controller, action names to a hash and later it will be passed to server as a URL parameter. The hash will be verified at the server side for its validity by recomputing the hash and compared with the submitted hash. This hash is dynamic and specific to a session. So even though your URL cached in the man-in-the middle attack, it will not work in other sessions. Basically a utility class extends the HTML helper ActionLink class. So we can use Html.ActionLink method as such in the MVC implementation, in addition you only need to pass a boolean argument as a last argument to get the protected URL. It is pretty easy to use this coding. Examples are shown below.

<%=Html.ActionLink("link Test 3", "HandleLink", new { id = 200 }, true)%>

You’ll notice the extra boolean parameter at the end to enable encryption.

The ExtendedHtmlActionLinkHelper looks like this:

namespace ExtendedHtmlActionLinkHelper
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    using System.Web.Routing;

    /// <summary>
    /// This class is an extension for the Html Helper
    /// </summary>
    public static class ActionLinkExtensions
    {
        // This password is included in the hash. If needed it can be changed.
        private static string tokenPassword = "@#123%#";

        public static string TokenPassword
        {
            get { return tokenPassword; }

            set { tokenPassword = value; }
        }

        /// <summary>
        /// This is the extended method of Html.ActionLink.This class has the extended methods for the 10 overloads of this method
        /// All the overloaded method applys the same logic excepts the parameters passed in
        /// </summary>
        /// <param name="helper">The helper.</param>
        /// <param name="linkText">The link text.</param>
        /// <param name="actionName">Name of the action.</param>
        /// <param name="generateToken">if set to <c>true</c> [generate token].</param>
        /// <returns></returns>
        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary();
            if (generateToken)
            {
                // Call the generateUrlToken method which create the hash
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd, TokenPassword);

                // The hash is added to the route value dictionary
                rvd.Add("urltoken", token);
            }

            // the link is formed by using the GenerateLink method.
            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, rvd, null);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, object routeValues, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary(routeValues);
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, rvd, null);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, RouteValueDictionary routeValues, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = routeValues;
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, rvd, null);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary();
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, rvd, null);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, object routeValues, object htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary(routeValues);
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var attrib = GetDictionaryFromObject(htmlAttributes);
            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, rvd, attrib);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, routeValues, TokenPassword);
                routeValues.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, null, routeValues, htmlAttributes);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary(routeValues);
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var attrib = GetDictionaryFromObject(htmlAttributes);
            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, rvd, attrib);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, routeValues, TokenPassword);
                routeValues.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, routeValues, htmlAttributes);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            var rvd = new RouteValueDictionary(routeValues);
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, rvd, TokenPassword);
                rvd.Add("urltoken", token);
            }

            var attrib = GetDictionaryFromObject(htmlAttributes);
            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, protocol, hostName, fragment, rvd, attrib);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool generateToken)
        {
            var rc = helper.ViewContext.RequestContext;
            var routeCollection = helper.RouteCollection;
            if (generateToken)
            {
                var token = TokenUtility.GenerateUrlToken(controllerName, actionName, routeValues, TokenPassword);
                routeValues.Add("urltoken", token);
            }

            var link = HtmlHelper.GenerateLink(rc, routeCollection, linkText, null, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes);
            var mvcHtmlString = MvcHtmlString.Create(link);
            return mvcHtmlString;
        }

        private static IDictionary<string, object> GetDictionaryFromObject(object sourceObject)
        {
            var objType = sourceObject.GetType();

            return objType.GetProperties().ToDictionary(prop => prop.Name, prop => prop.GetValue(sourceObject, null));
        }
    }
}

It is also worth generating the UrlHelper.Action too should this be required

using System.Web.Mvc;
using System.Web.Routing;

public static class ActionExtensions
{
    public static MvcHtmlString Action(this UrlHelper helper, string actionName, bool generateToken)
    {
        var rvd = new RouteValueDictionary();
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }

    public static MvcHtmlString Action(this UrlHelper helper, string actionName, object routeValues, bool generateToken)
    {
        if(routeValues== null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = (RouteValueDictionary)routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }

    public static MvcHtmlString Action(this UrlHelper helper, string actionName, RouteValueDictionary routeValues, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }

    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, bool generateToken)
    {
        var rvd = new RouteValueDictionary();
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }


    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, object routeValues, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = (RouteValueDictionary)routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }


    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, RouteValueDictionary routeValues, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }


    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, object routeValues, string protocol, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = (RouteValueDictionary)routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd, protocol);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }

    public static MvcHtmlString Action(this UrlHelper helper, string actionName, string controllerName, RouteValueDictionary routeValues, string protocol, string hostName, bool generateToken)
    {
        if (routeValues == null)
        {
            routeValues = new RouteValueDictionary();
        }

        var rvd = routeValues;
        if (generateToken)
        {
            // Call the generateUrlToken method which create the hash
            var token = TokenUtility.GenerateUrlToken(string.Empty, actionName, rvd);

            // The hash is added to the route value dictionary
            rvd.Add("urltoken", token);
        }

        // the link is formed by using the GenerateLink method.
        var link = new UrlHelper(helper.RequestContext).Action(actionName, controllerName, rvd, protocol, hostName);
        var mvcHtmlString = MvcHtmlString.Create(link);
        return mvcHtmlString;
    }
        
}Getting a protected URL in the view is easy as just passing a boolean parameter. Now let us see how to validate the URL when submitted to controller. It is even simpler. Just add this attribute to the controller method.
[IsValidURLRequest]

This attribute has taken care of the simple authorize check (user name, password verification), check for http referrer and protect the URL parameters.

Now for the TokenUtility that performs most of the work for creating the URL Hash.

using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Routing;

/// <summary>
/// This is a static helper class which creates the URL Hash
/// </summary>
public static class TokenUtility
{
    public static string GenerateUrlToken(string controllerName, string actionName, RouteValueDictionary argumentParams, string password)
    {
        //// The URL hash is dynamic by assign a dynamic key in each session. So
        //// eventhough your URL is stolen, it will not work in other session
        if (HttpContext.Current.Session["url_dynamickey"] == null)
        {
            HttpContext.Current.Session["url_dynamickey"] = RandomString();
        }

        // The salt include the dynamic session key and valid for an hour.
        var salt = HttpContext.Current.Session["url_dynamickey"] + DateTime.Now.ToShortDateString() + " " + DateTime.Now.Hour;

        // generating the partial url
        var stringToToken = controllerName + "/" + actionName + "/";
        stringToToken = argumentParams.Where(item => item.Key != "controller" && item.Key != "action" && item.Key != "urltoken").Aggregate(stringToToken, (current, item) => current + (item.Value));

        // Converting the salt in to a byte array
        var saltValueBytes = System.Text.Encoding.ASCII.GetBytes(salt);

        // Encrypt the salt bytes with the password
        var key = new Rfc2898DeriveBytes(password, saltValueBytes);

        // get the key bytes from the above process
        var secretKey = key.GetBytes(16);

        // generate the hash
        var tokenHash = new HMACSHA1(secretKey);
        tokenHash.ComputeHash(System.Text.Encoding.ASCII.GetBytes(stringToToken));

        // convert the hash to a base64string
        var token = Convert.ToBase64String(tokenHash.Hash).Replace("/", "_");

        return token;
    }

    /// <summary>
    /// This validates the token
    /// </summary>
    /// <param name="token">The token.</param>
    /// <param name="controllerName">Name of the controller.</param>
    /// <param name="actionName">Name of the action.</param>
    /// <param name="argumentParams">The argument params.</param>
    /// <param name="password">The password.</param>
    /// <returns></returns>
    public static bool ValidateToken(string token, string controllerName, string actionName, RouteValueDictionary argumentParams, string password)
    {
        // compute the token for the currrent parameter
        var computedToken = GenerateUrlToken(controllerName, actionName, argumentParams, password);

        // compare with the submitted token
        if (computedToken != token)
        {
            computedToken = GenerateUrlToken(string.Empty, actionName, argumentParams, password);
        }
        else { return true; }

        return computedToken == token;
    }

    /// <summary>
    /// It validates the token, where all the parameters passed as a RouteValueDictionary
    /// </summary>
    /// <param name="requestUrlParts">The request URL parts.</param>
    /// <param name="password">The password.</param>
    /// <param name="token">the Url encrypted token to be used to validate against</param>
    /// <returns></returns>
    public static bool ValidateToken(RouteValueDictionary requestUrlParts, string password, string token)
    {
        // get the parameters
        string controllerName;
        try
        {
            controllerName = Convert.ToString(requestUrlParts["controller"]);
        }
        catch (Exception)
        {
            controllerName = string.Empty;
        }

        var actionName = Convert.ToString(requestUrlParts["action"]);
        //var token = Convert.ToString(requestUrlParts["urltoken"]);

        // Compute a new hash
        var computedToken = GenerateUrlToken(controllerName, actionName, requestUrlParts, password);

        // compare with the submited hash
        if (computedToken != token)
        {
            computedToken = GenerateUrlToken(string.Empty, actionName, requestUrlParts, password);
        }
        else
        {
            return true;
        }

        return computedToken == token;
    }

    /// <summary>
    /// This method create the random dynamic key for the session
    /// </summary>
    /// <returns></returns>
    private static string RandomString()
    {
        var builder = new StringBuilder();
        var random = new Random();
        for (var i = 0; i < 8; i++)
        {
            var ch = Convert.ToChar(Convert.ToInt32(Math.Floor((26 * random.NextDouble()) + 65)));
            builder.Append(ch);
        }

        return builder.ToString();
    }
}

 

ExtendedHtmlActionLinkHelper (3).zip (277.13 kb)

Original Source