asp.net-mvc 在 ASP.NET MVC 中加密 URL 中的 id

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/895586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 23:36:12  来源:igfitidea点击:

Encrypting an id in an URL in ASP.NET MVC

asp.net-mvcencryption

提问by Chuck Conway

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

我正在尝试在 Url 中对加密的 id 进行编码。像这样: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.

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

I've tried different encodings, each fails:

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

  • HttpUtility.HtmlEncode
  • HttpUtility.UrlEncode
  • HttpUtility.UrlPathEncode
  • HttpUtility.UrlEncodeUnicode
  • 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.

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

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."

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

After digging around the net I came across a HexEncoding/Decodingclass. 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.

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

采纳答案by Toran Billups

I wrote a short blog postabout 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 :

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

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.

我找到了一组很好的基类来解决这个问题,但在大多数情况下,它归结为一个类。此类需要某种 16 个字符的密钥来进行加密,并需要一个值进行加密。如果需要,您还可以设置到期值。

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.

要加密某些值并将其传递给 MVC 中的另一个操作,您可以执行以下操作。

[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 codefor this sample is available for download.

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

与往常一样,此示例的源代码可供下载。

回答by Pavel Chuchuva

Use HttpServerUtility.UrlTokenEncodeand HttpServerUtility.UrlTokenDecodeto convert byte array to URL-safe string.

使用HttpServerUtility.UrlTokenEncodeHttpServerUtility.UrlTokenDecode将字节数组转换为 URL 安全字符串。

See C# Byte[] to Url Friendly String.

请参阅C# Byte[] 到 Url Friendly String

回答by PnP

This post may be old but here you have another solution... When you are going to encrypt .ToBase64String, the url encode / decode change the encrypted string.

这篇文章可能很旧,但在这里你有另一个解决方案......当你要加密 .ToBase64String 时,url 编码/解码会改变加密的字符串。

Try this on your encription library (or function) before doing the decode:

在进行解码之前,在您的加密库(或函数)上试试这个:

Myencodedid.Replace(' ', '+')

And then, go for the decryption!..

然后,去解密!..

回答by Marcel Popescu

There's a difference between encrypting and encoding; those methods weren't meant for encrypting.

加密和编码是有区别的;这些方法不是用于加密的。

Because encryption is hard to get right, and incredibly easy to get wrong (while still looking just as "encrypted" as the right solution), I recommend that you instead use GUID IDs:

因为加密很难正确,而且非常容易出错(虽然看起来仍然像正确的解决方案一样“加密”),我建议您改用 GUID ID:

http://www.calemadr.com/.../{6F0184E4-809F-4e30-8A5B-4DC144135A54}

http://www.calemadr.com/.../{6F0184E4-809F-4e30-8A5B-4DC144135A54}

SQL server has the uniqueidentifier type just for this case.

SQL Server 具有仅用于这种情况的 uniqueidentifier 类型。

回答by CoderDennis

I'm surprised UrlEncode doesn't work. What does the output of your encryption look like?

我很惊讶 UrlEncode 不起作用。你的加密输出是什么样的?

After you encrypt your Guid, try encoding it to Base64 with the Convert.ToBase64Stringmethod. Then UrlEncode the Base64 string to make it an acceptable string to be included in your URL.

加密 Guid 后,尝试使用Convert.ToBase64String方法将其编码为 Base64 。然后对 Base64 字符串进行 UrlEncode,使其成为可以包含在您的 URL 中的可接受字符串。

回答by Charlino

Hmmm... This probably won't make any difference but you could try the AntiXSS library and it's URLEncode() method.

嗯...这可能不会有任何区别,但您可以尝试 AntiXSS 库和它的 URLEncode() 方法。

http://www.codeplex.com/AntiXSS

http://www.codeplex.com/AntiXSS

HTHs, Charles

HTH,查尔斯

回答by Charlino

Don't know if it matters anymore to you but I just solved this problem on my own. I had to double urlencode.

不知道这对你是否更重要,但我只是自己解决了这个问题。我不得不将 urlencode 加倍。

For example

例如

Server.UrlEncode(Server.UrlEncode(string to encode))

Server.UrlEncode(Server.UrlEncode(string to encode))

The problem seems to be that Request.Querystring(encoded string) automatically does a decode which is screwing up the encryption. I wish I could explain better but I'm still a little confused

问题似乎是 Request.Querystring(encoded string) 自动进行解码,这会破坏加密。我希望我能解释得更好,但我还是有点困惑

回答by star test

First create one class like this:

首先创建一个这样的类:

public class Encryption
{ 
    public static string Encrypt(string clearText)
    {
        string EncryptionKey = "MAKV2SPBNI99212";
        byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(clearBytes, 0, clearBytes.Length);
                    cs.Close();
                }
                clearText = Convert.ToBase64String(ms.ToArray());
            }
        }
        return clearText;
    }

    public static string Decrypt(string cipherText)
    {
        string EncryptionKey = "MAKV2SPBNI99212";
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();
                }
                cipherText = Encoding.Unicode.GetString(ms.ToArray());
            }
        }
        return cipherText;
    }
}

In Controller, add reference for this Ecription class like this:

在 Controller 中,为这个 Ecription 类添加引用,如下所示:

using testdemo.Models

public ActionResult Index() {
            return View();
        }
        [HttpPost]
        public ActionResult Index(string text)
        {
            if (Request["txtEncrypt"] != null)
            {
                string getEncryptionCode = Request["txtEncrypt"];
                string DecryptCode = Encryption.Decrypt(HttpUtility.UrlDecode(getEncryptionCode));
                ViewBag.GetDecryptCode = DecryptCode;
                return View();
            }
            else {
                string getDecryptCode = Request["txtDecrypt"];
                string EncryptionCode = HttpUtility.UrlEncode(Encryption.Encrypt(getDecryptCode));
                ViewBag.GetEncryptionCode = EncryptionCode;
                return View();
            }

        }

In View:

在视图中:

<h2>Decryption Code</h2>
@using (Html.BeginForm())
{
    <table class="table-bordered table">
        <tr>
            <th>Encryption Code</th>
            <td><input type="text" id="txtEncrypt" name="txtEncrypt" placeholder="Enter Encryption Code" /></td>
        </tr>
        <tr>
            <td colspan="2">
                <span style="color:red">@ViewBag.GetDecryptCode</span>
            </td>
        </tr>
        <tr>
                <td colspan="2">
                    <input type="submit" id="btnEncrypt" name="btnEncrypt"value="Decrypt to Encrypt code" />
                </td>
            </tr>
    </table>
}
    <br />
    <br />
    <br />
    <h2>Encryption Code</h2>
@using (Html.BeginForm())
{
    <table class="table-bordered table">
        <tr>
            <th>Decryption Code</th>
            <td><input type="text" id="txtDecrypt" name="txtDecrypt" placeholder="Enter Decryption Code" /></td>
        </tr>

        <tr>
            <td colspan="2">
                <span style="color:red">@ViewBag.GetEncryptionCode</span>
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" id="btnDecryt" name="btnDecryt" value="Encrypt to Decrypt code" />
            </td>
        </tr>
    </table>
}

I hope this useful.

我希望这有用。