在 ASP.NET MVC 中加密 URL 中的 id [英] Encrypting an id in an URL in ASP.NET MVC

查看:14
本文介绍了在 ASP.NET MVC 中加密 URL 中的 id的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对 Url 中的加密 ID 进行编码.像这样: http://www.calemadr.com/Membership/Welcome/9xCnCLIwzxzBuPEjqJFxC6XJdAZqQsIDqNrRUJoW6229IIeeL4eXl5n1cnYapg+N

但是,它要么编码不正确,我在加密中得到斜杠/",要么我收到来自 IIS 的错误:请求过滤模块被配置为拒绝包含双转义序列的请求.

我尝试了不同的编码,但都失败了:

  • HttpUtility.HtmlEncode
  • HttpUtility.UrlEncode
  • HttpUtility.UrlPathEncode
  • HttpUtility.UrlEncodeUnicode

更新

问题是当我加密 Guid 并将其转换为 base64 字符串时,它会包含不安全的 url 字符.当然,当我尝试导航到包含不安全字符的 url 时,IIS(7.5/windows 7) 会崩溃.对 base64 加密字符串进行 Url 编码会在 IIS 中引发和错误(请求过滤模块被配置为拒绝包含双转义序列的请求.).我不确定它是如何检测双编码字符串的,但确实如此.

尝试以上方法对base64加密后的字符串进行编码后.我决定删除 base64 编码.但是,这会将加密文本保留为字节 [].我尝试 UrlEncoding byte[],它是挂在 httpUtility.Encode 方法上的重载之一.同样,虽然它是 URL 编码的,但 IIS 不喜欢它并提供找不到页面".

在网上挖掘之后,我发现了一个 HexEncoding/解码类.将十六进制编码应用于加密字节就行了.输出是 url 安全的.另一方面,我在解码和解密十六进制字符串方面没有任何问题.

解决方案

我写了一个简短的博客 post 关于这个主题,包括完整的源代码.

它使您能够使用 16 个字符的密钥加密和解密以查询字符串形式存储的数据:

<块引用>

我找到了一组很好的基类来解决这个问题,但大多数情况下部分归结为一类.这个类需要一个 16 个字符的键某种进行加密和加密的值.你也可以如果需要,设置一个过期值.

using System.Collections.Specialized;使用 System.Security;使用 System.Text;使用 System.Web;使用 EncryptionMVC.Security.Encryption.Utility.Interfaces;使用 EncryptionMVC.Security.Encryption.Utility;命名空间 Security.Encryption.QueryString{//////提供一种在查询字符串中传输数据的安全方法.///公共类 SecureQueryString : NameValueCollection{私人字符串 timeStampKey = '__TS__';私人字符串日期格式 = 'G';私有 IEncryptionUtility mEncryptionUtil;私人日期时间 m_expireTime = DateTime.MaxValue;//////使用指定的键创建一个实例.//////用于加密函数的密钥,长度需要 16 个字符.公共 SecureQueryString(string key) : base(){mEncryptionUtil = 新的 EncryptionUtility(key);}//////使用指定的密钥和加密的查询字符串创建一个实例.//////用于加密函数的密钥,长度需要 16 个字符.///由实例生成的加密查询字符串.public SecureQueryString(string key, string queryString) : this(key){反序列化(DecryptAndVerify(queryString));检查过期();}//////返回一个加密的查询字符串.//////公共覆盖字符串 ToS​​tring(){返回 EncryptAndSign(Serialize());}私有无效反序列化(字符串查询字符串){string[] nameValuePairs = queryString.Split('&');for (int i = 0; i <= nameValuePairs.Length - 1; i++) {string[] nameValue = nameValuePairs(i).Split('=');if (nameValue.Length == 2) {base.Add(nameValue(0), nameValue(1));}}如果(base.GetValues(timeStampKey)!= null){string[] strExpireTime = base.GetValues(timeStampKey);m_expireTime = Convert.ToDateTime(strExpireTime(0));}}私有字符串 Serialize(){StringBuilder sb = new StringBuilder();foreach(base.AllKeys 中的字符串键){sb.Append(key);sb.Append('=');sb.Append(base.GetValues(key)(0).ToString());sb.Append('&');}sb.Append(timeStampKey);sb.Append('=');sb.Append(m_expireTime.ToString(dateFormat));返回 sb.ToString();}私有字符串 DecryptAndVerify(字符串输入){返回 mEncryptionUtil.Decrypt(input);}私有字符串 EncryptAndSign(字符串输入){返回 mEncryptionUtil.Encrypt(输入);}私有无效 CheckExpiration(){如果 (DateTime.Compare(m_expireTime, DateTime.Now) <0) {抛出新的 ExpiredQueryStringException();}}//////获取或设置此字符串应到期的时间戳///公共日期时间到期时间{得到 { 返回 m_expireTime;}设置 { m_expireTime = 值;}}}}

<块引用>

要加密某些值并将其传递给 MVC 中的另一个操作,您需要做类似下面的事情.

[AcceptVerbs(HttpVerbs.Post)]公共 ActionResult 索引(FormCollection 集合){SecureQueryString qs = new SecureQueryString(mKey);qs('YourName') = collection('name');qs.ExpireTime = DateTime.Now.AddMinutes(2);Response.Redirect('Home.aspx/About?data=' + HttpUtility.UrlEncode(qs.ToString()));}

<块引用>

在我们重定向到的操作中,您需要具有相同的密钥和查询字符串值本身来解密它.请记住如果您没有正确的密钥或者您尝试解密该值过期后,类会抛出异常.

public ActionResult About(){如果(请求('数据')!= null){尝试 {SecureQueryString qs = new SecureQueryString(mKey, Request('data'));ViewData('Message') = '你的名字是' + qs('你的名字');}捕获(异常前){}}返回视图();}

<块引用>

我没有花太多时间深入解释来源,因为它已经自从我写了这么久.还要记住这是很久以前我的测试第一天......(但它似乎有效)

一如既往,此示例的源代码是可供下载.

I'm attempting to encode the encrypted id in the Url. Like this: http://www.calemadr.com/Membership/Welcome/9xCnCLIwzxzBuPEjqJFxC6XJdAZqQsIDqNrRUJoW6229IIeeL4eXl5n1cnYapg+N

However, it either doesn't encode correctly and I get slashes '/' in the encryption or I receive and error from IIS: The request filtering module is configured to deny a request that contains a double escape sequence.

I've tried different encodings, each fails:

  • HttpUtility.HtmlEncode
  • HttpUtility.UrlEncode
  • HttpUtility.UrlPathEncode
  • HttpUtility.UrlEncodeUnicode

Update

The problem was I when I encrypted a Guid and converted it to a base64 string it would contain unsafe url characters . Of course when I tried to navigate to a url containing unsafe characters IIS(7.5/ windows 7) would blow up. Url Encoding the base64 encrypted string would raise and error in IIS (The request filtering module is configured to deny a request that contains a double escape sequence.). I'm not sure how it detects double encoded strings but it did.

After trying the above methods to encode the base64 encrypted string. I decided to remove the base64 encoding. However this leaves the encrypted text as a byte[]. I tried UrlEncoding the byte[], it's one of the overloads hanging off the httpUtility.Encode method. Again, while it was URL encoded, IIS did not like it and served up a "page not found."

After digging around the net I came across a HexEncoding/Decoding class. Applying the Hex Encoding to the encrypted bytes did the trick. The output is url safe. On the other side, I haven't had any problems with decoding and decrypting the hex strings.

解决方案

I wrote a short blog post about this very topic including full source code.

It enables you to encrypt and decrypt data stored in query string form using a 16 char key :

I found a great set of base classes to solve this but for the most part it comes down to one class. This class requires a 16 char key of some kind to do the encryption and a value to encrypt. You can also set an expiration value if needed.

using System.Collections.Specialized;
using System.Security;
using System.Text;
using System.Web;
using EncryptionMVC.Security.Encryption.Utility.Interfaces;
using EncryptionMVC.Security.Encryption.Utility;
namespace Security.Encryption.QueryString
{
    /// 
    /// Provides a secure means for transfering data within a query string.
    /// 
    public class SecureQueryString : NameValueCollection
    {

        private string timeStampKey = '__TS__';
        private string dateFormat = 'G';
        private IEncryptionUtility mEncryptionUtil;
        private DateTime m_expireTime = DateTime.MaxValue;

        /// 
        /// Creates an instance with a specified key.
        /// 
        /// The key used for cryptographic functions, required 16 chars in length.
        public SecureQueryString(string key) : base()
        {
            mEncryptionUtil = new EncryptionUtility(key);
        }

        /// 
        /// Creates an instance with a specified key and an encrypted query string.
        /// 
        /// The key used for cryptographic functions, required 16 chars in length.
        /// An encrypted query string generated by a  instance.
        public SecureQueryString(string key, string queryString) : this(key)
        {
            Deserialize(DecryptAndVerify(queryString));
            CheckExpiration();
        }

        /// 
        /// Returns a encrypted query string.
        /// 
        /// 
        public override string ToString()
        {
            return EncryptAndSign(Serialize());
        }

        private void Deserialize(string queryString)
        {
            string[] nameValuePairs = queryString.Split('&');
            for (int i = 0; i <= nameValuePairs.Length - 1; i++) {
                string[] nameValue = nameValuePairs(i).Split('=');
                if (nameValue.Length == 2) {
                    base.Add(nameValue(0), nameValue(1));
                }
            }

            if (base.GetValues(timeStampKey) != null) {
                string[] strExpireTime = base.GetValues(timeStampKey);
                m_expireTime = Convert.ToDateTime(strExpireTime(0));
            }
        }

        private string Serialize()
        {
            StringBuilder sb = new StringBuilder();
            foreach (string key in base.AllKeys) {
                sb.Append(key);
                sb.Append('=');
                sb.Append(base.GetValues(key)(0).ToString());
                sb.Append('&');
            }

            sb.Append(timeStampKey);
            sb.Append('=');
            sb.Append(m_expireTime.ToString(dateFormat));

            return sb.ToString();
        }

        private string DecryptAndVerify(string input)
        {
            return mEncryptionUtil.Decrypt(input);
        }

        private string EncryptAndSign(string input)
        {
            return mEncryptionUtil.Encrypt(input);
        }

        private void CheckExpiration()
        {
            if (DateTime.Compare(m_expireTime, DateTime.Now) < 0) {
                throw new ExpiredQueryStringException();
            }
        }

        /// 
        /// Gets or sets the timestamp in which this string should expire
        /// 
        public DateTime ExpireTime {
            get { return m_expireTime; }
            set { m_expireTime = value; }
        }
    }
}

To encrypt some value and pass it to another action in MVC you would do something like the below.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection collection)
{
    SecureQueryString qs = new SecureQueryString(mKey);

    qs('YourName') = collection('name');
    qs.ExpireTime = DateTime.Now.AddMinutes(2);

    Response.Redirect('Home.aspx/About?data=' + HttpUtility.UrlEncode(qs.ToString()));
}

In the action that we redirect to, you would need to have this same key and the query string value itself to decrypt it. Keep in mind that if you don't have the correct key or if you try to decrypt the value after the expiration, the class will throw an exception.

public ActionResult About()
{
    if (Request('data') != null) {
        try {
            SecureQueryString qs = new SecureQueryString(mKey, Request('data'));

            ViewData('Message') = 'Your name is ' + qs('YourName');
        }
        catch (Exception ex) {

        }
    }
    return View();
}

I didn't spend much time explaining the source in depth because it has been so long since I wrote it. Also keep in mind this was long before my test first days ... (but it does appear to work)

As always, the source code for this sample is available for download.

这篇关于在 ASP.NET MVC 中加密 URL 中的 id的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆