Шифрование идентификатора в URL в ASP.NET MVC - PullRequest
11 голосов
/ 22 мая 2009

Я пытаюсь закодировать зашифрованный идентификатор в URL. Как это: http://www.calemadr.com/Membership/Welcome/9xCnCLIwzxzBuPEjqJFxC6XJdAZqQsIDqNrRUJoW6229IIeeL4eXl5n1cnYapg+N

Однако он либо неправильно кодируется, и я получаю косую черту '/' в шифровании, либо получаю сообщение об ошибке от IIS: Модуль фильтрации запросов настроен на отклонение запроса, который содержит двойную escape-последовательность.

Я пробовал разные кодировки, каждая из них дает сбой:

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

Обновление

Проблема была в том, что когда я зашифровал Guid и преобразовал его в строку base64, он содержал бы небезопасные символы URL. Конечно, когда я пытался перейти к URL, содержащему небезопасные символы, IIS (7.5 / windows 7) взорвался. Url Кодирование строки в зашифрованном виде base64 приведет к возникновению ошибки в IIS ( Модуль фильтрации запросов настроен на отклонение запроса, содержащего двойную escape-последовательность. ). Я не уверен, как он обнаруживает строки с двойным кодированием, но это произошло.

После попытки описанных выше способов закодировать зашифрованную строку base64. Я решил убрать кодировку base64. Однако это оставляет зашифрованный текст в виде байта []. Я попытался UrlEncoding byte [], это одна из перегрузок, свисающих с метода httpUtility.Encode. Опять же, несмотря на то, что он был закодирован в URL, IIS это не понравилось, и он открыл страницу "not found."

После копания в сети я наткнулся на класс HexEncoding / Decoding . Применение шестнадцатеричного кодирования к зашифрованным байтам сделало свое дело. Вывод URL безопасен. С другой стороны, у меня не было проблем с декодированием и дешифрованием шестнадцатеричных строк.

Ответы [ 8 ]

10 голосов
/ 06 апреля 2011

Используйте HttpServerUtility.UrlTokenEncode и HttpServerUtility.UrlTokenDecode для преобразования байтового массива в URL-безопасную строку.

См. C # байт [] для строки, дружественной к URL * .

7 голосов
/ 26 сентября 2009

Я написал короткий блог пост на эту тему, включая полный исходный код.

Позволяет шифровать и дешифровать данные, хранящиеся в форме строки запроса, с использованием 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();
}

Я не тратил много времени на подробное объяснение источника, потому что Прошло так много времени с тех пор, как я это написал. Также имейте в виду, это было задолго до мой тест в первые дни ... (но, похоже, он работает)

Как всегда, исходный код для этого образца доступен для скачивания.

2 голосов
/ 24 июля 2012

Это сообщение может быть старым, но здесь у вас есть другое решение ... Когда вы собираетесь зашифровать .ToBase64String, URL-адрес кодирует / декодирует изменение зашифрованной строки.

Попробуйте выполнить это в вашей библиотеке записи (или функции) перед выполнением декодирования:

Myencodedid.Replace(' ', '+')

А потом приступайте к расшифровке! ..

2 голосов
/ 22 мая 2009

Существует разница между шифрованием и кодированием; эти методы не были предназначены для шифрования.

Поскольку шифрование трудно понять правильно и невероятно легко ошибиться (хотя оно выглядит так же «зашифровано», как и правильное решение), я рекомендую вместо этого использовать идентификаторы GUID:

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

Сервер SQL имеет тип уникального идентификатора только для этого случая.

1 голос
/ 21 сентября 2017

Сначала создайте один класс, подобный этому:

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

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

        }

В представлении:

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

Надеюсь, это полезно.

1 голос
/ 25 сентября 2009

Не знаю, имеет ли это значение для вас, но я решил эту проблему самостоятельно. Мне пришлось удвоить urlencode.

Например

Server.UrlEncode (Server.UrlEncode (строка для кодирования))

Проблема, похоже, заключается в том, что Request.Querystring (закодированная строка) автоматически выполняет декодирование, приводящее к нарушению шифрования. Я хотел бы объяснить лучше, но я все еще немного сбит с толку

1 голос
/ 22 мая 2009

Хммм ... Это, вероятно, не будет иметь никакого значения, но вы можете попробовать библиотеку AntiXSS и ее метод URLEncode ().

http://www.codeplex.com/AntiXSS

HTHS, Charles

1 голос
/ 22 мая 2009

Я удивлен, что UrlEncode не работает. Как выглядит вывод вашего шифрования?

После того, как вы зашифровали Guid, попробуйте кодировать его в Base64 с помощью метода Convert.ToBase64String . Затем UrlEncode строки Base64, чтобы сделать ее приемлемой строкой для включения в ваш URL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...