How do I encrypt URLs in ASP.NET MVC?

前端 未结 4 1261
执笔经年
执笔经年 2021-01-03 03:51

I need to Encrypt the URLs in my ASP.NET MVC application.

Do I need to write the code in Global page in Route Collection to Encrypt all the URLs?

相关标签:
4条回答
  • 2021-01-03 04:02

    It's likely pointless to globally encrypt all the url parameters (query string). Most parameters are display items used by HttpGet. If everything is encrypted then this won't make for a very informative page. However if there are sensitive parameters that are only hidden fields (keys) on the client that eventually are returned to the server to identify a record, this might be worth encrypting.

    Consider this viewModel:

    public viewModel
    {
        public int key {get;set;}           // Might want to encrypt
        public string FirstName {get;set;}  // Don't want this encrypted
        public string LastName {get;set;}   // Don't want this encrypted
    }
    

    The viewModel gets converted into a query string, something close to.... appName.com/index?Id=2;FirstName="John";LastName="Doe"

    If this viewModel is passed as a query string, what's the point in encrypting the first and last names?

    It should be noted that query strings are HttpGet. HttpPost use the session to pass values not query strings. HttpPost sessions are encrypted. But there is overhead to httpPost. So, if your page does actually contain sensitive data that needs to be displayed (perhaps the users current password) then consider going to HttpPost instead.

    0 讨论(0)
  • 2021-01-03 04:04

    Based on the answers here, which did not work for me BTW, I found another solution based on my particular MVC implementation, and the fact that it also works depending on whether you're using II7 or II6. Slight changes are needed in both cases.

    II6

    Firstly, you need to add the following into your web.config (root, not the one in View folder).

     <system.web>
        <httpModules>
          <add name="URIHandler" type="URIHandler" />
        </httpModules>
    

    II7

    add this instead into your web.config (root, not the one in View folder).

      <system.webServer>
        <validation validateIntegratedModeConfiguration="false" />
        <modules runAllManagedModulesForAllRequests="true">
          <remove name="URIHandler" />
          <add name="URIHandler" type="URIHandler" />
        </modules>
    

    Or you could add both. It doesn't matter really.

    Next use this class. I called it, as you've probably noticed - URIHandler.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.IO;
    using System.Text;
    using System.Security.Cryptography;
    using System.Diagnostics.CodeAnalysis;
    
    public class URIHandler : IHttpModule
        {
            #region IHttpModule members
            public void Dispose()
            {
            }
    
            public void Init(HttpApplication context)
            {
                context.BeginRequest += new EventHandler(context_BeginRequest);
            }
            #endregion
    
            private const string PARAMETER_NAME = "enc=";
            private const string ENCRYPTION_KEY = "key";
    
            private void context_BeginRequest(object sender, EventArgs e)
            {
                HttpContext context = HttpContext.Current;
                //if (context.Request.Url.OriginalString.Contains("aspx") && context.Request.RawUrl.Contains("?"))
                if (context.Request.RawUrl.Contains("?"))
                {
                    string query = ExtractQuery(context.Request.RawUrl);
                    string path = GetVirtualPath();
    
                    if (query.StartsWith(PARAMETER_NAME, StringComparison.OrdinalIgnoreCase))
                    {
                        // Decrypts the query string and rewrites the path.
                        string rawQuery = query.Replace(PARAMETER_NAME, string.Empty);
                        string decryptedQuery = Decrypt(rawQuery);
                        context.RewritePath(path, string.Empty, decryptedQuery);
                    }
                    else if (context.Request.HttpMethod == "GET")
                    {
                        // Encrypt the query string and redirects to the encrypted URL.
                        // Remove if you don't want all query strings to be encrypted automatically.
                        string encryptedQuery = Encrypt(query);
                        context.Response.Redirect(path + encryptedQuery);
                    }
                }
            }
    
            /// <summary>
            /// Parses the current URL and extracts the virtual path without query string.
            /// </summary>
            /// <returns>The virtual path of the current URL.</returns>
            private static string GetVirtualPath()
            {
                string path = HttpContext.Current.Request.RawUrl;
                path = path.Substring(0, path.IndexOf("?"));
                path = path.Substring(path.LastIndexOf("/") + 1);
                return path;
            }
    
            /// <summary>
            /// Parses a URL and returns the query string.
            /// </summary>
            /// <param name="url">The URL to parse.</param>
            /// <returns>The query string without the question mark.</returns>
            private static string ExtractQuery(string url)
            {
                int index = url.IndexOf("?") + 1;
                return url.Substring(index);
            }
    
            #region Encryption/decryption
    
            /// <summary>
            /// The salt value used to strengthen the encryption.
            /// </summary>
            private readonly static byte[] SALT = Encoding.ASCII.GetBytes(ENCRYPTION_KEY.Length.ToString());
    
            /// <summary>
            /// Encrypts any string using the Rijndael algorithm.
            /// </summary>
            /// <param name="inputText">The string to encrypt.</param>
            /// <returns>A Base64 encrypted string.</returns>
            [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
            public static string Encrypt(string inputText)
            {
                RijndaelManaged rijndaelCipher = new RijndaelManaged();
                byte[] plainText = Encoding.Unicode.GetBytes(inputText);
                PasswordDeriveBytes SecretKey = new PasswordDeriveBytes(ENCRYPTION_KEY, SALT);
    
                using (ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16)))
                {
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                        {
                            cryptoStream.Write(plainText, 0, plainText.Length);
                            cryptoStream.FlushFinalBlock();
                            return "?" + PARAMETER_NAME + Convert.ToBase64String(memoryStream.ToArray());
                        }
                    }
                }
            }
    
            /// <summary>
            /// Decrypts a previously encrypted string.
            /// </summary>
            /// <param name="inputText">The encrypted string to decrypt.</param>
            /// <returns>A decrypted string.</returns>
            [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
            public static string Decrypt(string inputText)
            {
                RijndaelManaged rijndaelCipher = new RijndaelManaged();
                byte[] encryptedData = Convert.FromBase64String(inputText);
                PasswordDeriveBytes secretKey = new PasswordDeriveBytes(ENCRYPTION_KEY, SALT);
    
                using (ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16)))
                {
                    using (MemoryStream memoryStream = new MemoryStream(encryptedData))
                    {
                        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                        {
                            byte[] plainText = new byte[encryptedData.Length];
                            int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);
                            return Encoding.Unicode.GetString(plainText, 0, decryptedCount);
                        }
                    }
                }
            }
            #endregion
        }
    

    You don't need a NameSpace.

    The above class does everything you need to Encrypt and Decrypt any URL parameters starting with '?' character. It even does a nice job of renaming your parameter variables to 'enc', which is a bonus.

    Lastly, place the class in your App_Start folder, and NOT the App_Code folder, as that will conflict with 'unambiguous errors'.

    Done.

    Credits:

    https://www.codeproject.com/questions/1036066/how-to-hide-url-parameter-asp-net-mvc

    https://msdn.microsoft.com/en-us/library/aa719858(v=vs.71).aspx

    HttpModule Init method were not called

    C# Please specify the assembly explicitly in the type name

    https://stackoverflow.com/questions/1391060/httpmodule-with-asp-net-mvc-not- being-called

    0 讨论(0)
  • 2021-01-03 04:06

    Encrypting an entire url, I agree, very bad idea. Encrypting url parameters? Not so much and is actually a valid and widely used technique.

    If you really want to encrypt/decrypt url parameters (which isn't a bad idea at all), then check out Mads Kristensen's article "HttpModule for query string encryption".

    You will need to modify context_BeginRequest in order to get it to work for MVC. Just remove the first part of the if statement that checks if the original url contains "aspx".

    With that said, I have used this module in a couple of projects (have a converted VB version if needed) and for the most part, it works like a charm.

    BUT, there are some instances where I have experienced some issues with jQuery/Ajax calls not working correctly. I am sure the module could be modified in order to compensate for those scenarios.

    0 讨论(0)
  • 2021-01-03 04:28

    It's a bad idea to encrypt a URL. Period.

    You may wonder why I say that.

    I worked on an application for a company that encrypted its URLs. This was a webforms application. From the URL alone, it was nearly impossible to tell what part of the code I was hitting to cause that issue. Because of the dynamic nature of calling the webform controls, you just had to know the path the software was going to go down. It was quite unnerving.

    Add to that that there was no role based authorization in the application. It was all based on the URL being encrypted. If you could decrypt the URL (which if it can be encrypted, it can be decrypted), then you could conceivably enter another encrypted URL and impersonate another user. I'm not saying it's simple, but it can happen.

    Finally, how often do you use the internet and see encrypted URLs? When you do, do you die a little inside? I do. URLs are meant to convey public information. If you don't want it to do that, don't put it in your URL (or require Authorization for sensitive areas of your site).

    The IDs you're using in the database should be IDs that are ok for the user to see. If you're using an SSN as a primary key, then you should change that schema for a web application.

    Anything that can be encrypted can be decrypted, and therefore is vulnerable to attack.

    If you want a user to only access certain URLs if they're authorized, then you should use the [Authorize] attributes available in ASP.NET MVC.

    0 讨论(0)
提交回复
热议问题