如何加密ASP.NET MVC中的URL?

时间:2010-12-16 19:42:55

标签: asp.net asp.net-mvc asp.net-mvc-2

我需要加密ASP.NET MVC应用程序中的URL。

我是否需要在Route Collection中的Global页面中编写代码以加密所有URL?

5 个答案:

答案 0 :(得分:7)

加密URL是个坏主意。周期。

你可能想知道我为什么这么说。

我为一家加密其网址的公司申请了一份申请。这是一个webforms应用程序。仅从URL中,几乎不可能分辨出我要引起该问题的代码部分。由于调用webform控件的动态特性,您只需知道软件将要发生的路径。这让人非常不安。

此外,应用程序中没有基于角色的授权。这一切都基于加密的URL。如果你可以解密URL(如果它可以被加密,它可以被解密),那么你可以想象输入另一个加密的URL并冒充另一个用户。我不是说这很简单,但可能会发生。

最后,您多久使用一次互联网并查看加密的网址?当你这样做的时候,你内心有点死吗?我做。网址旨在传达公共信息。如果您不希望它这样做,请不要将其放在您的URL中(或者需要对您站点的敏感区域进行授权)。

您在数据库中使用的ID应该是可供用户查看的ID。如果您使用SSN作为主键,则应更改Web应用程序的架构。

任何可以加密的东西都可以被解密,因此容易受到攻击。

如果您希望用户只有在获得授权的情况下才能访问某些URL,那么您应该使用ASP.NET MVC中提供的[Authorize]属性。

答案 1 :(得分:4)

加密整个网址,我同意,非常糟糕的主意。加密网址参数?不是那么多,实际上是一种有效且广泛使用的技术。

如果你真的想要加密/解密url参数(根本不是一个坏主意),那么请查看Mads Kristensen的文章“HttpModule for query string encryption”。

您需要修改context_BeginRequest以使其适用于MVC。只需删除if语句的第一部分,检查原始URL是否包含“aspx”。

话虽如此,我已经在几个项目中使用过这个模块(如果需要的话,还有一个转换后的VB版本),而且在大多数情况下,它就像魅力一样。

但是,在某些情况下,我遇到了一些jQuery / Ajax调用无法正常工作的问题。我确信可以修改模块以补偿这些情况。

答案 2 :(得分:1)

基于这里的答案,这对我来说不起作用BTW,我根据我的特定MVC实现发现了另一个解决方案,并且根据你是否依赖它也可以运行使用II7或II6。两种情况都需要稍作修改。

<强> II6

首先,您需要将以下内容添加到 web.config (root,而不是View文件夹中的那个)。

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

<强> II7

将其添加到 web.config (root,而不是View文件夹中的那个)。

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

或者你可以添加两者。它并不重要。

接下来使用这个课程。我打电话给你,因为你可能已经注意到了 - 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
    }

您不需要NameSpace

上述类可以执行加密和解密以'?'字符开头的任何URL参数所需的一切。它甚至可以很好地将您的参数变量重命名为&#39; enc&#39;这是一个奖励。

最后,将课程放在App_Start文件夹中,放在App_Code文件夹中,因为这会与“明确错误”相冲突。< / p>

完成。

现金:

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

答案 3 :(得分:0)

您可以创建自定义 html 帮助程序来加密查询字符串并使用自定义操作过滤器属性进行解密并取回原始值。您可以在全球范围内实施它,因此不会花费太多时间。您可以从这里参考Url Encryption In Asp.Net MVC。这将帮助您使用自定义助手和自定义操作过滤器属性。

答案 4 :(得分:-1)

全局加密所有url参数(查询字符串)可能毫无意义。大多数参数是HttpGet使用的显示项。如果所有内容都被加密,那么这将不会提供非常有用的页面。但是,如果有敏感参数只是客户端上的隐藏字段(键),这些参数最终会返回给服务器以标识记录,则可能值得加密。

考虑此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
}

viewModel被转换为查询字符串,类似于...。 appName.com/index?Id=2;FirstName="John";LastName="Doe“

如果此viewModel作为查询字符串传递,那么加密名字和姓氏有什么意义?

应注意,查询字符串是HttpGet。 HttpPost使用会话传递值而不是查询字符串。 HttpPost会话已加密。但是httpPost有开销。因此,如果您的页面确实包含需要显示的敏感数据(也许是用户当前的密码),则可以考虑使用HttpPost。

相关问题