2

ASP.NET/Mono MVC4 shopping cart application users product codes as url names for awstats analytics like:

http://myshop.com/Store/Details/PRODUCT1

with default routing and controller

    public class StoreController : MyApp.ControllerBase
    {

        public ActionResult Details(string id)
        {
  ....

PRODUCT1 is product code. If product code contains / and other non-allowed characters in directory name, web server throws error.

Product code should be human readable since analytics shows urls. How to encode product code to passed as directory name and decode it back in controller ? Product code should remain unique after encoding.

Is there some built-in function in ASP.NET or some source code which implements this ?

jquery, jquery ui, razor view engine is used.

Update

I tried recommendatiod in comment by creating Razor helper

@helper Details(string toode)
{
    @Url.Action("Details", new { id = HttpUtility.UrlEncode(toode) });
}

and then using

<a href="@Details(someproduct)">

This causes error:

A potentially dangerous Request.Path value was detected from the client (%). GET /Store/Details/S%c3%9c%c3%9cTAJA HTTP/1.0

% chareter is not allowed in url paths. So UrlEncode cannot used. How to encode/decode?

Community
  • 1
  • 1
Andrus
  • 26,339
  • 60
  • 204
  • 378
  • You could possibly use url encoding/decoding (HttpUtility.UrlEncode) but encoded urls tend to look kind of ugly. I would rather have product codes that don't contain these problematic characters and thus are both human and server readable. – Wiktor Zychla Mar 01 '15 at 11:26
  • Users like product codes like `1/23:3/3+3/?A`. Currently in Razor view is used `@Url.Action("Details", new { product = "1/23:3/3+3/?A" }))` but awstats analytics treats all product pages as single page. Should I create url manually like `@("~/Store/Details/"+HttpUtility.UrlEncode("1/23:3/3+3/?A"))` or is there better way ? Or can awstats or other free server based analytics configured ? – Andrus Mar 01 '15 at 14:33
  • `1/23:3/3+3/?A` urlencoded is `1%2F23%3A3%2F3%2B3%2F%3FA`. I am not sure anyone will like it. But that's my subjective opinion and don't pay attention to it if you think it's otherwise. Anyway, urlencoding sounds like the only solution if you really insist on these awkward urls. – Wiktor Zychla Mar 01 '15 at 17:04
  • % character is not allowed in url paths. So UrlEncode cannot used. I updated question. How to encode/decode ? – Andrus Mar 01 '15 at 20:35
  • This is because your helper is probably wrong. I believe `Url.Action` already does some encoding. Try just `"/Store/Details?id="+HttpUtility.UrlEncode(toode)`. – Wiktor Zychla Mar 01 '15 at 20:43
  • I found this: http://stackoverflow.com/questions/591694/url-encoded-slash-in-url in answer with 14 upvotes: ´Request side: UrlEncode your path. Replace the '%' with '!'. Make the request. Response side: Replace the '!' with '%'. UrlDecode your path. Use the parameters as they were intended.´ Is this reasonable ? – Andrus Mar 01 '15 at 20:51
  • @WiktorZychla I asked about adding product id as last uri segment. Your recommendation adds id as query string parameter value. awstats analytics treats all details pages like same page then. – Andrus Mar 01 '15 at 21:04
  • I believe something else is going wrong as %(some number) is not blocked by IIS (a standalone % sign will be however). – Tommy Mar 01 '15 at 21:11
  • This is standard security error message from MVC4 parameter parser. It is not reasonable to turn it off, better is not to send % characters in uri segments, use % only in query string values – Andrus Mar 01 '15 at 21:15
  • @Andrus: I am sorry then, your requirements are not possible to be met all together. Either you forget about all these special characters in url segments (/ : + ?) and you introduce simple product codes or you pass url encoded values in the query string parameter rather than uri segment or you allow % as the uri segment by lowering MVC security. – Wiktor Zychla Mar 02 '15 at 08:44
  • I used urlencoding in id part (last fragment in url path) but replaced % with ! character. So id looks safe in url now . Is this OK ? – Andrus Mar 02 '15 at 14:25

1 Answers1

0

You can use encryption and decryption algorithm (cryptography) to achieve your goal like this...

 public class CryptoEngine
    {

        private static CryptoEngine _instance;
        private CryptoEngine() { }
        public static CryptoEngine Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new CryptoEngine();

                return _instance;
            }
        }

        static readonly string PasswordHash = "@dM!nCo$";
        static readonly string SaltKey = "AdMinCos";
        static readonly string VIKey = "Polar!s@dM!nCoN$";

        public string Encrypt(string plainText)
        {
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.Zeros };
            var encryptor = symmetricKey.CreateEncryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));

            byte[] cipherTextBytes;

            using (var memoryStream = new MemoryStream())
            {
                using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                    cryptoStream.FlushFinalBlock();
                    cipherTextBytes = memoryStream.ToArray();
                    cryptoStream.Close();
                }
                memoryStream.Close();
            }
            return Convert.ToBase64String(cipherTextBytes);
        }

        public string Decrypt(string encryptedText)
        {
            encryptedText = encryptedText.Trim();
            if (encryptedText.Contains(" "))
            {
                encryptedText = encryptedText.Replace(" ", "+");
            }

            byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
            byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash, Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding = PaddingMode.None };

            var decryptor = symmetricKey.CreateDecryptor(keyBytes, Encoding.ASCII.GetBytes(VIKey));
            var memoryStream = new MemoryStream(cipherTextBytes);
            var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];

            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray());
        }
    }

and use it like this...

"/Store/Details?id="+CryptoEngine.Instance.Encrypt(toode))

and in your action you can decrypt it as like this...

public ActionResult Details(string id)
{
   string _id = CryptoEngine.Instance.Decrypt(id);
   .......

You can set your PasswordHash, SaltKey and VIKey i think this is what you want.

You can check more about cryptography Reference

akd
  • 6,538
  • 16
  • 70
  • 112
Tejas Vaishnav
  • 466
  • 5
  • 20
  • This makes urls unreadable by humas. urls shoudl be readable so they and used in awstats analtyicts to track most viewed products. How to make urls readable ? – Andrus Mar 02 '15 at 14:20
  • code will encrypt only Id not entire url, so url will not be encrypted and readable to humans, but your id will encrypted at the end. – Tejas Vaishnav Mar 05 '15 at 05:44
  • I need that product id is also readable. Usually it contains regular characters and only few special ones. Id part should also be user-friendly also – Andrus Mar 05 '15 at 15:50