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

Clean Content to help searching

One of the issue we all faced with is when a user searches for content, we are allowing the end user to be able to search for anything and this could result in unnecessary searching or cause the backend to perform searches which could result in DOS attacks via SQL.

I have covered DOS attacks via SQL before

https://bryanavery.co.uk/post/2013/10/01/Denial-Of-Service-attacks-via-SQL-Wildcards-should-be-prevented/

SQL Wildcard attacks force the underlying database to carry out CPU-intensive queries by using several wildcards. This vulnerability generally exists in search functionalities of web applications. Successful exploitation of this attack will cause Denial of Service.

Depending on the connection pooling settings of the application and the time taken for attack query to execute, an attacker might be able to consume all connections in the connection pool, which will cause database queries to fail for legitimate users.

By default in ASP.NET, the maximum allowed connections in the pool is 100 and timeout is 30 seconds. Thus if an attacker can run 100 multiple queries with 30+ seconds execution time within 30 seconds no one else would be able to use the database related parts of the application.

Recommendation:

If the application does not require this sort of advanced search, all wildcards should be escaped or filtered.
References:

OWASP Testing for SQL Wildcard Attacks
https://www.owasp.org/index.php/Testing_for_SQL_Wildcard_Attacks_(OWASP-DS-001)

DoS Attacks using SQL Wildcards
http://www.zdnet.com/blog/security/dos-attacks-using-sql-wildcards-revealed/1134

So I’ve went to work to produce a Sequence Diagram on what we need to do to Clean the Content

I’ve generated this method for cleaning content which helps with removing unwanted characters

using System;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

public class Search
{
    /// <summary>
    /// The regex strip html.
    /// </summary>
    private readonly Regex RegexStripHtml = new Regex("<[^>]*>", RegexOptions.Compiled);

    private StringCollection StopWords
    {
        get
        {
            var stopWords = new StringCollection();
            return stopWords;
        }
    }

    /// <summary>
    /// Removes stop words and HTML from the specified string.
    /// </summary>
    /// <param name="content">
    /// The content.
    /// </param>
    /// <param name="removeHtml">
    /// The remove Html.
    /// </param>
    /// <returns>
    /// The clean content.
    /// </returns>
    public string CleanContent(string content, bool removeHtml)
    {
        if (removeHtml)
        {
            content = this.StripHtml(content);
        }

        content = content.Replace("\\", string.Empty).Replace("|", string.Empty).Replace("(", string.Empty).Replace(")", string.Empty).Replace("[", string.Empty).Replace("]", string.Empty).Replace("*", string.Empty).Replace("?", string.Empty).Replace("}", string.Empty).Replace("{", string.Empty).Replace("^", string.Empty).Replace("+", string.Empty).Replace("%", string.Empty).Replace("_", string.Empty);

        var words = content.Split(new[] { ' ', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
        var sb = new StringBuilder();
        foreach (var word in
            words.Select(t => t.ToLowerInvariant().Trim()).Where(word => RemoveSingleCharacters(word) && RemoveStopWords(word)))
        {
            sb.AppendFormat("{0} ", word);
        }

        return sb.ToString().Trim();
    }

    /// <summary>
    /// Strips all HTML tags from the specified string.
    /// </summary>
    /// <param name="html">
    /// The string containing HTML
    /// </param>
    /// <returns>
    /// A string without HTML tags
    /// </returns>
    public string StripHtml(string html)
    {
        return this.StringIsNullOrWhitespace(html) ? string.Empty : this.RegexStripHtml.Replace(html, string.Empty).Trim();
    }

    /// <summary>
    /// Returns whether a string is null, empty, or whitespace. Same implementation as in String.IsNullOrWhitespace in .Net 4.0
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public bool StringIsNullOrWhitespace(string value)
    {
        return value == null || value.Trim().Length == 0;
    }

    /// <summary>
    /// Removes the single characters.
    /// </summary>
    /// <param name="word">The word.</param>
    /// <returns></returns>
    private bool RemoveSingleCharacters(string word)
    {
        return word.Length > 1;
    }

    /// <summary>
    /// Removes the stop words.
    /// </summary>
    /// <param name="word">The word.</param>
    /// <returns></returns>
    private bool RemoveStopWords(string word)
    {
        return !this.StopWords.Contains(word);
    }
}

URL Validator

I needed to check to see if a URL that the user was entering was a valid Url, does it contain HTTP:// or HTTPS:// I ended up writing a small ValidationAttribute to add to the collection I am now building up, here is the code:

using System;
using System.ComponentModel.DataAnnotations;
using System.Net;

public class IsUriAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var myString = value.ToString();
        Uri myUri;
        if (Uri.TryCreate(myString, UriKind.Absolute, out myUri) && (myUri.Scheme == Uri.UriSchemeHttp || myUri.Scheme == Uri.UriSchemeHttps))
        {
            return ValidateUri(myUri);
        }
        return new ValidationResult("URL is invalid.\nStart with http:// or https:// and end with\na proper image extension");
    }

    private ValidationResult ValidateUri(Uri myUri)
    {
        var webRequest = WebRequest.Create(myUri);
        try
        {
            webRequest.GetResponse();
        }
        catch //If exception thrown then couldn't get response from address
        {
            return new ValidationResult("URL is invalid and does not exist");
        }
        return ValidationResult.Success;
    }
}
 

Using the WebGrid in MVC correctly

I know the WebGrid is a basic Grid control, but sometimes you are constrained with what you can use with a customer and WebGrid is by default from Microsoft so it is safe to use and does not require any unknown third party tools to be installed.

By default the WebGrid requires all the data to be loaded in order for paging to work.  The problem is when you page through the data, all the data is returned. If you try to limit the data being returned, the problem you’ll encounter because you’re only returning a subset of the data is the WebGrid thinks there’s only that amount of data to display, so the paging links will disappear! Not good!  This is the reason why I’m writing this blog post to over come this issue.

Throughout this example I’ve tried to keep to using interfaces where ever possible as I always think these are easier to understand and keep the application more flexible.

The WebGrid supports dynamic typing, while dynamic typing is probably a good fit for WebMatrix, there are benefits to strongly typed views. One way to achieve this is to create a derived type WebGrid<T>, here it is:

using System;
using System.Collections.Generic;
using System.Web.Helpers;

public class WebGrid<T> : WebGrid
{
    public WebGrid(IEnumerable<T> source = null, IEnumerable<string> columnNames = null, string defaultSort = null, int rowsPerPage = 10, bool canPage = true, bool canSort = true, string ajaxUpdateContainerId = null, string ajaxUpdateCallback = null, string fieldNamePrefix = null, string pageFieldName = null,
    string selectionFieldName = null, string sortFieldName = null, string sortDirectionFieldName = null)
        : base(source.SafeCast<object>(), columnNames, defaultSort, rowsPerPage, canPage, canSort, ajaxUpdateContainerId, ajaxUpdateCallback, fieldNamePrefix, pageFieldName,
            selectionFieldName, sortFieldName, sortDirectionFieldName)
    {
    }
    public WebGridColumn _Column(string columnName = null, string header = null, Func<T, object> format = null, string style = null, bool canSort = true)
    {
        Func<object, object> wrappedFormat = null;
        if (format != null)
        {
            wrappedFormat = o => format((T)o);
        }
        var _scolumn = base.Column(columnName, header, wrappedFormat, style, canSort);
        return _scolumn;
    }
    public WebGrid<T> _Bind(IEnumerable<T> source, IEnumerable<string> columnNames = null, bool autoSortAndPage = true, int rowCount = -1)
    {
        base.Bind(source.SafeCast<object>(), columnNames, autoSortAndPage, rowCount);
        return this;
    }
}

And to extend the exisiting WebGrid we require a static extension:

using System.Web.Mvc;
using System.Collections.Generic;

public static class WebGridExtensions
{
    public static WebGrid<T> Grid<T>(this HtmlHelper htmlHelper, IEnumerable<T> source, IEnumerable<string> columnNames = null, string defaultSort = null, int rowsPerPage = 10, bool canPage = true, bool canSort = true, string ajaxUpdateContainerId = null, string ajaxUpdateCallback = null, string fieldNamePrefix = null,
    string pageFieldName = null, string selectionFieldName = null, string sortFieldName = null, string sortDirectionFieldName = null)
    {
        return new WebGrid<T>(source, columnNames, defaultSort, rowsPerPage, canPage, canSort, ajaxUpdateContainerId, ajaxUpdateCallback, fieldNamePrefix, pageFieldName,
        selectionFieldName, sortFieldName, sortDirectionFieldName);
    }

    public static WebGrid<T> ServerPagedGrid<T>(this HtmlHelper htmlHelper, IEnumerable<T> source, int totalRows, IEnumerable<string> columnNames = null, string defaultSort = null, int rowsPerPage = 10, bool canPage = true, bool canSort = true, string ajaxUpdateContainerId = null, string ajaxUpdateCallback = null,
    string fieldNamePrefix = null, string pageFieldName = null, string selectionFieldName = null, string sortFieldName = null, string sortDirectionFieldName = null)
    {
        dynamic webGrid = new WebGrid<T>(null, columnNames, defaultSort, rowsPerPage, canPage, canSort, ajaxUpdateContainerId, ajaxUpdateCallback, fieldNamePrefix, pageFieldName,
        selectionFieldName, sortFieldName, sortDirectionFieldName);
        return webGrid.Bind(source, rowCount: totalRows, autoSortAndPage: false);
    }
}

One further method we will need is a SafeCast to extend the Enumerable

using System.Collections;
using System.Collections.Generic;
using System.Linq;

public static class EnumerableExtensions
{
    public static IEnumerable<TTarget> SafeCast<TTarget>(this IEnumerable source)
    {
        return source == null ? null : source.Cast<TTarget>();
    }
}

Okay so this is it for the infrastructure, now lets get down to using the new WebGrid, so first the domain objects or interfaces we want to display

using System;
    
public interface IDocument
{
    global::System.Guid Id { get; set; }
    DateTime? Timestamp { get; set; }
    global::System.Boolean Inactive { get; set; }
}

Now for the important worker, the Service interface:

using System.Collections.Generic;

public interface IDocumentService
{
    IEnumerable<IDocument> GetDocuments(out int totalRecords, int pageSize = -1, int pageIndex = -1, string sort = "Id", SortDirection sortOrder = SortDirection.Ascending);
}

and the impmentation looks something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

public class EfDocumentService : IDocumentService
{
    private readonly IDictionary<string, Func<IQueryable<IDocument>, bool, IOrderedQueryable<IDocument>>>
        _documentOrderings
            = new Dictionary<string, Func<IQueryable<IDocument>, bool, IOrderedQueryable<IDocument>>>
                    {
                        {
                            "Id",
                            CreateOrderingFunc<IDocument, Guid>(p => p.Id)
                            },
                        {
                            "Inactive",
                            CreateOrderingFunc<IDocument, bool?>(p => p.Inactive )
                            },
                        {
                            "Timestamp",
                            CreateOrderingFunc<IDocument, DateTime?>(p => p.Timestamp )
                            }
                    };


    private static Func<IQueryable<T>, bool, IOrderedQueryable<T>> CreateOrderingFunc<T, TKey>(Expression<Func<T, TKey>> keySelector)
    {
        return (source, @ascending) => @ascending ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector);
    }

    public IEnumerable<IDocument> GetDocuments(out int totalRecords, int pageSize, int pageIndex, string sort, SortDirection sortOrder)
    {
        using (var context = new EDM())
        {
            IQueryable<IDocument> documents = context.Documents;

            totalRecords = documents.Count();

            Func<IQueryable<IDocument>, bool, IOrderedQueryable<IDocument>> applyOrdering;
            _documentOrderings.TryGetValue(sort, out applyOrdering);

            documents = applyOrdering(documents, sortOrder == SortDirection.Ascending);

            if (pageSize > 0 && pageIndex >= 0)
            {
                documents = documents.Skip(pageIndex * pageSize).Take(pageSize);
            }

            return documents.ToList();
        }
    }
}

Now for the Controller to process the data:

using System;
    using System.Web.Mvc;
    using Domain;
    using Models;

    public class HomeController : Controller
    {
        private readonly IDocumentService _documentService;

        public HomeController()
        {
            _documentService = new EfDocumentService();
        }

        public ActionResult index(int page = 1, string sort = "Id", string sortDir = "Ascending")
        {
            const int pageSize = 5;
            int totalRecords;

            var documents = _documentService.GetDocuments(out totalRecords, pageSize: pageSize, pageIndex: page - 1, sort: sort, sortOrder: GetSortDirection(sortDir));
            
            var model = new PagedDocumentsModel
            {
                PageSize = pageSize,
                PageNumber = page,
                Documents = documents,
                TotalRows = totalRecords
            };

            return View(model);
        }

        private SortDirection GetSortDirection(string sortDirection)
        {
            if (sortDirection != null)
            {
                if (sortDirection.Equals("DESC", StringComparison.OrdinalIgnoreCase) || sortDirection.Equals("DESCENDING", StringComparison.OrdinalIgnoreCase))
                {
                    return SortDirection.Ascending;
                }
            }
            return SortDirection.Descending;
        }
    }

The model to display all the information to the screen:

using System.Collections.Generic;
using Domain;

public class PagedDocumentsModel
{
    public int PageSize { get; set; }
    public int PageNumber { get; set; }
    public IEnumerable<IDocument> Documents { get; set; }
    public int TotalRows { get; set; }
}

And finally the view to display the information:

@model WebGridPaging.Models.PagedDocumentsModel
@using WebGridPaging.Infrastructure
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <script src="../../Scripts/jquery-2.0.3.min.js" type="text/javascript"></script>
    <title>List</title>
</head> 
<body>
    <div id="grid">
        @{
            var grid = new WebGrid<WebGridPaging.Domain.IDocument>(null, rowsPerPage: Model.PageSize, defaultSort: "Id", ajaxUpdateContainerId:"grid");
            grid.Bind(Model.Documents, rowCount: Model.TotalRows, autoSortAndPage: false);
        }
        @grid.GetHtml()
    </div>
    <p>
	Model.Documents.Count() = @Model.Documents.Count()
</p>
<p>
	Model.TotalRows = @Model.TotalRows
</p>
<p>
	Time = @System.DateTime.Now
</p>
</body>
</html>

I’ve included a project with code samples, but please note this is talking to an external database with a table called Documents, so either generate a sample database with this table or point it to one you already have.

WebGridPaging.zip (3.37 mb)

Reference links

Get the Most out of WebGrid in ASP.NET MVC

Catching Exceptions with Elmah within WCF

We all use the excellent ELMAH to deal with unhandled exceptions in an ASP.NET 3.5 web or MVC application. This works extremely well for all of the site, now what about WCF how can we get Elmah to work for us?

You can use the HttpHandler, and Decorate your Service(s) with an Error Handling attribute.

The ServiceErrorBehaviourAttribute:

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

/// <summary>
/// So we can decorate Services with the [ServiceErrorBehaviour(typeof(HttpErrorHandler))]
/// ...and errors reported to ELMAH
/// </summary>
public class ServiceErrorBehaviourAttribute : Attribute, IServiceBehavior
{
    readonly Type _errorHandlerType;

    public ServiceErrorBehaviourAttribute(Type errorHandlerType)
    {
        this._errorHandlerType = errorHandlerType;
    }

    public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
    {
    }

    public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
    {
        var errorHandler = (IErrorHandler)Activator.CreateInstance(_errorHandlerType);
        foreach (var channelDispatcher in serviceHostBase.ChannelDispatchers.OfType<ChannelDispatcher>())
        {
            channelDispatcher.ErrorHandlers.Add(errorHandler);
        }
    }
}

Now the HttpErrorHandler:

using Elmah;
using System;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

/// <summary>
/// Your handler to actually tell ELMAH about the problem.
/// </summary>
public class HttpErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return false;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        if (error == null) return;

        ErrorLog.GetDefault(null).Log(new Error(error));
    }
}

Now it is just a simple case of adding an attribute to the WCF Service:

[ServiceErrorBehaviour(typeof(HttpErrorHandler))]
public class Game : IGame
{

Here is a small sample application showing it in action

WcfService1.zip (8.26 kb)

Removing and Cleaning search content to prevent DoS attacks

There are many ways to search a system, what we have to be careful of is making sure that the search does not cause a DoS (Denial of Service) attack.

So following on from my article Denial Of Service (DoS) attacks via SQL Wildcards should be prevented here is a method to remove and clean up the search to prevent such an attack.

using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Specialized;

public class Search
{
private readonly Regex RegexStripHtml = new Regex("<[^>]*>", RegexOptions.Compiled);

private StringCollection StopWords
{
    get
    {
        var stopWords = new StringCollection();
        // Add your stopword here, or get them from a data source
        return stopWords;
    }
}

public string CleanContent(string content, bool removeHtml)
{
    if (removeHtml)
    {
        content = StripHtml(content);
    }

    content =
        content.Replace("\\", string.Empty).Replace("|", string.Empty).Replace("(", string.Empty).Replace(
            ")", string.Empty).Replace("[", string.Empty).Replace("]", string.Empty).Replace("*", string.Empty).
            Replace("?", string.Empty).Replace("}", string.Empty).Replace("{", string.Empty).Replace(
                "^", string.Empty).Replace("+", string.Empty).Replace("%", string.Empty).Replace("_", string.Empty);

    var words = content.Split(new[] { ' ', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
    var sb = new StringBuilder();
    foreach (var word in
        words.Select(t => t.ToLowerInvariant().Trim()).Where(word => word.Length > 1 && !StopWords.Contains(word)))
    {
        sb.AppendFormat("{0} ", word);
    }

    return sb.ToString().Trim();
}

private string StripHtml(string html)
{
    return StringIsNullOrWhitespace(html) ? string.Empty : RegexStripHtml.Replace(html, string.Empty).Trim();
}

private bool StringIsNullOrWhitespace(string value)
{
    return ((value == null) || (value.Trim().Length == 0));
}

Some of this code was cribbed from the BlogEngine

Here are some Unit Tests to test the CleanCode method, yes Unit Tests, this is the perfect method to perform and under how the methodworks.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Capita.Dolphin.Web.Helpers;

/// <summary>
/// Summary description for HelperSearchTests
/// </summary>
[TestClass]
public class HelperSearchTests
{
    [TestMethod]
    public void CleanContentValidCharacters()
    {
        // Assign
        var search = new Search();
        const string expected = "hello moon";
            
        // Act
        var actual = search.CleanContent("Hello moon", false);

        // Assert
        Assert.AreEqual(expected, actual);
    }

    [TestMethod]
    public void CleanContentInValidCharacters()
    {
        // Assign
        var search = new Search();
        const string expected = "hello moon";

        // Act
        var actual = search.CleanContent("Hello moo%*([|+^}{)n", false);

        // Assert
        Assert.AreEqual(expected, actual);
    }

    [TestMethod]
    public void CleanContentRemoveHTMLCharacters()
    {
        // Assign
        var search = new Search();
        const string expected = "hello moon";

        // Act
        var actual = search.CleanContent("<p>Hello moon</p>", true);

        // Assert
        Assert.AreEqual(expected, actual);
    }

    [TestMethod]
    public void CleanContentRemoveExtraWildCardsCharacters()
    {
        // Assign
        var search = new Search();
        const string expected = "hello moon";

        // Act
        var actual = search.CleanContent("[][^]_%Hello moon</p>", true);

        // Assert
        Assert.AreEqual(expected, actual);
    }
}

MVC way to check the File Extension

Following on from my article about checking for the file signature to ensure that the file is who it says it is

I decide to take it further and produce a Data Validation attribute, I found that the Microsoft.Web.Mvc.dll library already has one ,but it only checks for the file names, which is generally okay.

So I thought I’d enhance the Microsoft FileExtension attribute, but it was sealed……!  Grrrrrrrr  But Microsoft now have most of its code as open source, yaaaaa  🙂

So I downloaded the source and created my own variation of the FileExtensionsAttribute

First we need to generate DataTypeAttribute, and IClientValidatable to inherit.

IClientValidatable

using System.Collections.Generic;
using System.Web.Mvc;

public interface IClientValidatable
{
    IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context);
}

ModelClientValidationRule

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

[TypeForwardedFrom("System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
public class ModelClientValidationRule
{
    private readonly Dictionary<string, object> _validationParameters = new Dictionary<string, object>();
    private string _validationType;

    public string ErrorMessage { get; set; }

    public IDictionary<string, object> ValidationParameters
    {
        get { return _validationParameters; }
    }

    public string ValidationType
    {
        get { return _validationType jQuery15201478678032162548_1380881227039 String.Empty; }
        set { _validationType = value; }
    }
}

Now the actual code for FileExtensionsAttribute

FileExtensionsAttribute

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DataValidation.Properties;

/// <summary>
/// The file extensions, default is png,jpg,jpeg,gif.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class FileExtensionsAttribute : DataTypeAttribute, IClientValidatable
{
    private string _extensions;
    private string _extensionsSignatures;

    public FileExtensionsAttribute()
        : base("upload")
    {
        ErrorMessage = DataValidationResource.FileExtensionsAttribute_Invalid;
    }

    /// <summary>
    /// The file extensions, default is png,jpg,jpeg,gif.
    /// </summary>
    /// <value>
    /// The extensions.
    /// </value>
    public string Extensions
    {
        get { return String.IsNullOrWhiteSpace(_extensions) ? "png,jpg,jpeg,gif" : _extensions; }
        set { _extensions = value; }
    }

    /// <summary>
    /// The extensions signatures, this is the fileclass signature within the actual file.
    /// </summary>
    /// <value>
    /// The extensions signatures.
    /// </value>
    public string ExtensionsSignatures
    {
        get { return String.IsNullOrWhiteSpace(_extensionsSignatures) ? "" : _extensionsSignatures; }
        set { _extensionsSignatures = value; }
    }

    private string ExtensionsFormatted
    {
        get { return ExtensionsParsed.Aggregate((left, right) => left + ", " + right); }
    }

    [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "These strings are normalized to lowercase because they are presented to the user in lowercase format")]
    private string ExtensionsNormalized
    {
        get { return Extensions.Replace(" ", String.Empty).Replace(".", String.Empty).ToLowerInvariant(); }
    }

    [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "These strings are normalized to lowercase because they are presented to the user in lowercase format")]
    private string ExtensionsSignaturesNormalized
    {
        get { return ExtensionsSignatures.Replace(" ", String.Empty).Replace(".", String.Empty).ToLowerInvariant(); }
    }

    private IEnumerable<string> ExtensionsParsed
    {
        get { return ExtensionsNormalized.Split(',').Select(e => "." + e); }
    }

    private IEnumerable<string> ExtensionsSignaturesParsed
    {
        get { return ExtensionsSignaturesNormalized.Split(','); }
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, ExtensionsFormatted);
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ValidationType = "extension",
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
        };
        rule.ValidationParameters["extension"] = ExtensionsNormalized;
        yield return rule;
    }

    public override bool IsValid(object value)
    {
        if (value == null)
        {
            return true;
        }

        var valueAsFileBase = value as HttpPostedFileBase;
        if (valueAsFileBase != null)
        {
            return ValidateExtension(valueAsFileBase.FileName) && ValidateFileContent(valueAsFileBase);
        }

        var valueAsString = value as string;
        return valueAsString != null && ValidateExtension(valueAsString);
    }

    [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "These strings are normalized to lowercase because they are presented to the user in lowercase format")]
    private bool ValidateExtension(string fileName)
    {
        try
        {
            return ExtensionsParsed.Contains(Path.GetExtension(fileName).ToLowerInvariant());
        }
        catch (ArgumentException)
        {
            return false;
        }
    }

    private bool ValidateFileContent(HttpPostedFileBase file)
    {
        var validExtensions = GetValidExtenstions();
            
        var br = new BinaryReader(file.InputStream);
        string fileclass;
        byte buffer;

        try
        {
            buffer = br.ReadByte();
            fileclass = buffer.ToString();
            buffer = br.ReadByte();
            fileclass += buffer.ToString();
        }
        catch
        {
            return false;
        }

        return string.IsNullOrWhiteSpace(ExtensionsSignatures)
            ? ExtensionsParsed.Where(validExtensions.ContainsKey).Any(extension => validExtensions[extension].ToString() == fileclass) 
            : ExtensionsSignaturesParsed.Any(extensionsSignatures => extensionsSignatures == fileclass);
    }

    private Dictionary<string, int> GetValidExtenstions()
    {
        var validExtenstions = new Dictionary<string, int>
                                    {
                                        {".gif", 7173},
                                        {".jpg", 255216},
                                        {".png", 13780},
                                        {".bmp", 6677},
                                        {".txt", 239187},
                                        {"/", 239187},
                                        {".asp", 239187},
                                        {".sql", 239187},
                                        {".xls", 208207},
                                        {".doc", 208207},
                                        {".docx", 208207},
                                        {".dot", 208207},
                                        {".dotx", 208207},
                                        {".ppt", 208207},
                                        {".xml", 6063},
                                        {".html", 6033},
                                        {".js", 4742},
                                        {".xlsx", 8075},
                                        {".zip", 8075},
                                        {".ptx", 8075},
                                        {".mmap", 8075},
                                        {".rar", 8297},
                                        {".accdb", 01},
                                        {".mdb", 01},
                                        {".exe", 7790},
                                        {".dll", 7790},
                                        {".bat", 64101},
                                        {".tiff", 7373},
                                        {".tif", 7373}
                                    };
        return validExtenstions;
    }
}

You’ll notice the ValidateFileContent method which is the additional feature I’ve added to check for the file signature.

That’s it job done

A sample project can be found here

FileUploader.zip (9.24 mb)

File Upload does not check content

Is it possible to upload files of any type to the server through web application’s functionality?

Only file extension restrictions were could be enforced and the server may not perform any content checking (apart from possible anti-virus checks).

At the very least, a rudimentary check of the file content/headers must be made to ensure that the file extension does relate to the file content and that both are acceptable for uploading into the system.

Ideally the file content must be checked to ensure no malicious scripts or macros in word documents are present.

Recommendation:

All uploaded files should be thoroughly scanned and validated before being made available to other users.

If in doubt, the file should be discarded. Ideally, only files of certain types should be allowed and checking for file types should be done by the server for their content and file extensions, Content-Encoding or Content-Type headers should not be relied upon.

I’ve produced a simple application that checks for file signature when upload that can be used

https://bryanavery.co.uk/post/2013/06/25/Determine-which-file-type-has-been-uploaded/

Anothe rsource of reference can he found here:

http://stackoverflow.com/questions/58510/using-net-how-can-you-find-the-mime-type-of-a-file-based-on-the-file-signature

SSL Vulnerable to BEAST attack

A vulnerability exists in SSL 3.0 and TLS 1.0 that could allow information disclosure if an attacker intercepts encrypted traffic served from an affected system. The weakness is down to insufficiently randomised data being used for the Initialisation Vectors (IV) within the CBC-mode encryption algorithms. The exploit can be performed through multiple injection points, both native to the browser’s functionality.

This issue is reduced in risk by the fact that the attacker is required to have a Man-in-the-Middle position for this exploit whereby traffic interception can be performed, and with this position obtained it is generally easier to attack the victim through other methods (SSL-stripping, mixed-scripting [requesting HTTP resources from an HTTPS connection], etc…) which do not require complex cryptanalysis such as BEAST to execute.

TestSSLServer.exe (43.00 kb)

http://www.bolet.org/TestSSLServer/

 

Supported versions:
 SSLv2 SSLv3 TLSv1.0
Deflate compression: no
Supported cipher suites (ORDER IS NOT SIGNIFICANT):
  SSLv2
     RC4_128_WITH_MD5
     DES_192_EDE3_CBC_WITH_MD5
  SSLv3
     RSA_WITH_RC4_128_MD5
     RSA_WITH_RC4_128_SHA
     RSA_WITH_3DES_EDE_CBC_SHA
  TLSv1.0
     RSA_WITH_RC4_128_MD5
     RSA_WITH_RC4_128_SHA
     RSA_WITH_3DES_EDE_CBC_SHA
     RSA_WITH_AES_128_CBC_SHA
     RSA_WITH_AES_256_CBC_SHA
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
----------------------
Server certificate(s):
  0edc8b5e2d1e4c803319c3e4e80dd9945d953db2: CN=application.local.someone.zone
----------------------
Minimal encryption strength:     strong encryption (96-bit or more)
Achievable encryption strength:  strong encryption (96-bit or more)
BEAST status: vulnerable
CRIME status: protected

Recommendation:

Client-side:

Various browsers are introducing or have introduced mitigations for the issue which make exploitation less likely. There are also steps which can be taken on the server side to make exploitation impossible.

Server-side:

Enabling and prioritising TLS 1.1/1.2 would be advised where possible although removing support for TLS1.0 is impractical at this time.

In the short-term due to the lack of wide-scale support by browsers and servers alike, prioritising the use of a stream cipher (such as RC4-SHA) instead of a CBC-mode cipher is recommended in order to maintain compatibility with browsers (see note).

Migration away from TLS 1.0 and below to TLS 1.1/1.2 should considered as a medium-term option for secure applications.

SSL Best Practice Guide:

https://www.ssllabs.com/projects/best-practices/index.html

BEAST attack

On September 23, 2011 researchers Thai Duong and Juliano Rizzo demonstrated a “proof of concept” called BEAST (“Browser Exploit Against SSL/TLS”) using a Java applet to violate same origin policy constraints, for a long-known Cipher block chaining (CBC) vulnerability in TLS 1.0.[44][45] Practical exploits had not been previously demonstrated for this vulnerability, which was originally discovered by Phillip Rogaway[46] in 2002. The vulnerability of the attack had been fixed with TLS 1.1 in 2006, but TLS 1.1 had not seen wide adoption prior to this attack demonstration.

Mozilla updated the development versions of their NSS libraries to mitigate BEAST-like attacks. NSS is used by Mozilla Firefox and Google Chrome to implement SSL. Some web servers that have a broken implementation of the SSL specification may stop working as a result.

Microsoft released Security Bulletin MS12-006 on January 10, 2012, which fixed the BEAST vulnerability by changing the way that the Windows Secure Channel (SChannel) component transmits encrypted network packets.

Users of Windows 7 and Windows Server 2008 R2 can enable use of TLS 1.1 and 1.2, but this work-around will fail if it is not supported by the other end of the connection and will result in a fall-back to TLS 1.0.