2009-05-21 6 views
10

Ich versuche, die verschlüsselte ID in der URL zu verschlüsseln. Wie folgt aus: http://www.calemadr.com/Membership/Welcome/9xCnCLIwzxzBuPEjqJFxC6XJdAZqQsIDqNrRUJoW6229IIeeL4eXl5n1cnYapg+NVerschlüsseln einer ID in einer URL in ASP.NET MVC

jedoch entweder kodieren nicht richtig und ich Schrägstriche ‚/‘ in der Verschlüsselung oder ich erhalten und Fehler von IIS: Das Anforderungsfilterungsmodul ist konfiguriert, um eine Anfrage zu verweigern, die enthält eine doppelte Escape-Sequenz.

ich verschiedene Kodierungen versucht haben, die jeweils nicht:

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

-Update

Das Problem war ich, als ich eine Guid verschlüsselt und konvertiert es in eine Base64-Zeichenfolge würde es unsichere URL-Zeichen enthalten. Natürlich, wenn ich versuchte, zu einer URL mit unsicheren Zeichen zu navigieren, würde IIS (7.5/Windows 7) explodieren. Url Die Codierung der verschlüsselten base64-Zeichenfolge würde in IIS zu Fehlern führen und Fehler verursachen. (Das Anforderungsfiltermodul ist so konfiguriert, dass eine Anforderung abgelehnt wird, die eine doppelte Escape-Sequenz enthält.). Ich bin mir nicht sicher, wie es doppelt codierte Strings erkennt, aber es hat es getan.

Nach dem Versuch, die oben genannten Methoden zum Verschlüsseln der Base64 verschlüsselten Zeichenfolge. Ich beschloss, die base64-Codierung zu entfernen. Dies lässt jedoch den verschlüsselten Text als ein Byte []. Ich versuchte UrlEncoding das Byte [], es ist eine der Überladungen hängen von der Methode httpUtility.Encode. Auch wenn es URL-codiert war, mochte IIS es nicht und lieferte eine "Seite nicht gefunden."

Nach dem Graben im Netz stieß ich auf eine HexEncoding/Decoding Klasse. Das Anwenden der Hexadezimalkodierung auf die verschlüsselten Bytes hat den Zweck erfüllt. Die Ausgabe ist url sicher. Auf der anderen Seite hatte ich keine Probleme mit der Entschlüsselung und Entschlüsselung der Hex-Strings.

+1

Ihr Update ist viel besser als die Antwort. Wenn Sie Base64-codierte URLs verwenden möchten, die sicher sind, lesen Sie Folgendes: http://stackoverflow.com/a/10858198/237858 – kape123

Antwort

7

Ich schrieb einen kurzen Blog post über dieses Thema einschließlich voller Quellcode.

Es ermöglicht Ihnen, Daten in Query-String-Form gespeichert zum Verschlüsseln und Entschlüsseln mit einem 16 Zeichen Schlüssel:

ich eine große Menge von Basisklassen gefunden, dies zu lösen, aber für die meisten Teil darauf ankommt eine Klasse. Diese Klasse benötigt einen 16-Zeichen-Schlüssel von eine Art, die Verschlüsselung und einen Wert zu verschlüsseln. Sie können auch einen Ablaufwert festlegen, falls erforderlich.

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

einen gewissen Wert verschlüsseln und es an eine andere Aktion in MVC übergeben Sie so etwas wie die unten tun würde.

[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 der Aktion, die wir umleiten zu, Sie die gleichen Schlüssel und den Query-String-Wert selbst es zu entschlüsseln, haben müßten. Denken Sie daran, dass , wenn Sie nicht den richtigen Schlüssel haben oder wenn Sie versuchen, den Wert nach dem Ablauf zu entschlüsseln, die Klasse eine Ausnahme auslösen wird.

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

Ich habe nicht viel Zeit, die Quelle in der Tiefe zu erklären, weil es so lange her, seit ich es geschrieben habe. Denken Sie auch daran, das war lange vor mein Test ersten Tagen ... (aber es scheint zu funktionieren)

Wie immer ist die source code für dieses Beispiel zum Download verfügbar.

2

Es gibt einen Unterschied zwischen Verschlüsselung und Codierung; Diese Methoden waren nicht zum Verschlüsseln gedacht.

Da Verschlüsselung schwer zu bekommen Recht ist, und unglaublich leicht etwas falsch zu laufen (während immer noch nur als „verschlüsselte“, wie die richtige Lösung suchen), empfehle ich, dass Sie stattdessen GUID-IDs verwenden:

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

Der SQL-Server hat nur für diesen Fall den Uniqueidentifier-Typ.

+0

Abgesichert. Es macht keinen Sinn, die IDs mit einer Verschlüsselung zu versehen, wenn der Zweck nur die Verschleierung ist. – womp

+2

Ich entschuldige mich, ich war nicht ausführlich genug in der Frage. Ich versuche, eine verschlüsselte Zeichenfolge als URL-sicher zu codieren. Ironischerweise verwende ich Guids, die obige Verschlüsselung ist ein Guid. Das Problem besteht darin, eine verschlüsselte Zeichenfolge zu codieren, die nicht dazu führt, dass IIS eine Sicherheitswarnung oder eine Verzeichnisstruktur (mit Schrägstrichen '/') ausgibt. @Womp - Wegen der Art des Systems muss ich die ID verschlüsseln . –

+1

Hmm. Warum verschlüsseln Sie dann die GUID? Wenn Sie sich Sorgen um jemanden machen, der nicht autorisiert ist, eine URL erneut zu verwenden, könnte er die von Ihnen angegebene URL genauso gut wiederverwenden. Wenn du dir Sorgen machst, dass jemand * GUID von jemand anderem erraten hat ... wird das nie passieren. –

1

Ich bin überrascht UrlEncode funktioniert nicht. Wie sieht die Ausgabe Ihrer Verschlüsselung aus?

Nachdem Sie Ihre Guid verschlüsselt haben, versuchen Sie es mit der Convert.ToBase64String Methode zu Base64 zu kodieren. Dann UrlEncode die Base64-Zeichenfolge, um es eine akzeptable Zeichenfolge in Ihre URL aufzunehmen.

+2

Es könnte besser sein, einfach das/und + durch - und _ für URLs zu ersetzen, statt sie zu codieren. –

+0

Aber du musst auch unencodieren, also wie würdest du wissen, was - ist ein Strich und was - ist ein Schrägstrich? – CoderDennis

1

Hmmm ... Dies wird wahrscheinlich keinen Unterschied machen, aber Sie könnten versuchen, die AntiXSS-Bibliothek und es ist URLEncode() -Methode.

http://www.codeplex.com/AntiXSS

HTHS, Charles

+0

Ich habe diese Bibliothek schon einmal benutzt. Ich versuche es mal. –

1

Sie wissen nicht, ob es mehr für Sie wichtig, aber ich dieses Problem auf meinem eigenen nur gelöst. Ich musste Urlencode verdoppeln.

Zum Beispiel

Server.UrlEncode (Server.UrlEncode (string zu kodieren))

Das Problem scheint zu sein, dass Request.Querystring (codierte Zeichenfolge) automatisch eine Dekodierungs tut, die die Verschlüsselung vermasseln wird . Ich wünschte, ich könnte besser erklären, aber ich bin immer noch ein wenig verwirrt

10

Verwenden Sie HttpServerUtility.UrlTokenEncode und HttpServerUtility.UrlTokenDecode, um Byte-Array in URL-sichere Zeichenfolge zu konvertieren.

Siehe C# Byte[] to Url Friendly String.

+0

+1 Danke für den Link. –

2

Dieser Beitrag kann alt sein, aber hier haben Sie eine andere Lösung ... Wenn Sie .ToBase64String zu verschlüsseln, ändern Sie die verschlüsselte Zeichenfolge der URL codieren/dekodieren.

Versuchen Sie dies auf Ihrer encription Bibliothek (oder Funktion), bevor der decode tun:

Myencodedid.Replace(' ', '+') 

Und dann gehen Sie für die Entschlüsselung ..

1

Erste eine Klasse wie folgt erstellen:

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 hinzufügen Referenz für diese Ecription Klasse wie folgt:

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 Aussicht:

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

hoffe, dass ich das nützlich.

+0

Das OP fragte nach der URI-Verschlüsselung, nicht nach der allgemeinen Formularfeldverschlüsselung – Fandango68