加密ASP.NET MVC中的URL中的ID

问题描述:

我试图在URL中对加密的ID进行编码。像这样:http://www.calemadr.com/Membership/Welcome/9xCnCLIwzxzBuPEjqJFxC6XJdAZqQsIDqNrRUJoW6229IIeeL4eXl5n1cnYapg+N加密ASP.NET MVC中的URL中的ID

但是,它要么不正确编码和我在加密斜杠“/”或我接收和错误从IIS:请求筛选模块被配置为拒绝包含请求一个双转义序列。

我试过不同的编码,每一个失败:

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

更新

问题是当我加密一个Guid并将其转换为base64字符串时,它将包含不安全的url字符。当然,当我试图导航到一个包含不安全字符的URL时,IIS(7.5/windows 7)就会炸毁。 Url对base64加密字符串进行编码会引发IIS错误(请求筛选模块被配置为拒绝包含双转义序列的请求)。我不知道它是如何检测双重编码的字符串,但它确实如此。

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

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

+1

您的更新比回答更好。如果您希望Base64编码的URL安全,请阅读以下内容:http://*.com/a/10858198/237858 – kape123 2012-06-01 22:42:01

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

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

我发现了一个伟大一套基类来解决这一点,但在大多数 部分可以归结为一个班级。此类需要某种类型的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; } 
     } 
    } 
} 

要加密一些值,并将其传递到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())); 
} 

在我们重定向到,你就需要有这样相同的 键和查询字符串值本身进行解密的动作。请记住, 如果您没有正确的密钥,或者如果您在到期后尝试解密值 ,则该类将引发异常。

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(); 
} 

我没有花太多时间来解释深入的来源,因为它具有 这么久,因为我写的。另外请记住,这是很长的 我的测试第一天...(但它似乎工作)

一如既往,此示例的source code可供下载。

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

因为加密是很难得到正确,和令人难以置信的容易出错(同时还在寻找,就像“加密”为正确的解决方案),我建议你改用的GUID ID:

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

对于这种情况,SQL Server具有唯一标识符类型。

+0

借调。如果目的只是混淆,那么在ID上使用加密没有意义。 – womp 2009-05-21 22:43:11

+2

我的歉意,我在这个问题上不够详细。我正在尝试编码加密的字符串以确保URL安全。具有讽刺意味的是,我使用Guids,上面的加密是Guid。问题是编码加密的字符串,不会导致IIS发出安全警告或似乎是目录结构(包含斜线'/') @Womp - 由于系统的本质,我必须加密id 。 – 2009-05-21 23:02:12

+1

嗯。那你为什么要加密GUID呢?如果您担心某个未经授权重复使用URL的用户,他们同样可以重复使用您提供的URL作为示例。如果你担心某人*猜测*别人的GUID ...永远不会发生。 – 2009-05-30 09:39:53

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

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

嗯......这可能不会有什么区别,但你可以尝试AntiXSS库,它是URLEncode()方法。

http://www.codeplex.com/AntiXSS

HTHS, 查尔斯

不知道,如果它不再对你很重要,但我只是解决了我自己这个问题。我不得不加倍urlencode。

例如

Server.UrlEncode(Server.UrlEncode(串进行编码))

这个问题似乎是的Request.QueryString(编码的字符串)自动执行该拧了加密的译码。我希望我能更好地解释,但我仍然有点困惑

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

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

这篇文章可能比较老,但在这里你有另一种解决方案... 当你打算加密.ToBase64String时,url编码/解码会改变加密的字符串。

做解码之前,您encription库(或功能)试试这个:

Myencodedid.Replace(' ', '+') 

,然后去解密..

首先,创建一个类是这样的:!

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; 
    } 
} 

在控制器中,添加这样的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(); 
      } 

     } 

在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> 
} 

我希望这是有用的。