query string parameter obfuscation
Asked Answered
I

6

7

I want to obfuscate one query string parameter in ASP.NET. The site will have a high volume of request, so the algorithm shouldn't be too slow.

My problem is that all the algorithms I found result in unwanted characters (like +/=)

Here is an example of what i want to achieve:

www.domain.com/?id=1844

to

www.domain.com/?id=3GQ5DTL3oVd91WsGj74gcQ

The obfuscated param should only include a-z and A-Z and 0-9 characters.

I know I can encrypt using base64, but this will generate unwanted characters such as / or = or +.

Any idea what algorithm can be used?

Update: I'm aware of UrlEncoding , i want to avoid encoding the string. because that will generate charaters like %F2 or %B2 in the url.

Ide answered 25/8, 2010 at 20:3 Comment(10)
Why do you want to encrypt this value? Avoiding guessing or obscuring?Frizzly
Base64 is encoding, and encoding is not encryptionAstonishing
@sharru: I think you probably mean "obfuscation" rather than "encryption". I suggest that you edit your tags, title and question accordingly. If you really do want to encrypt then base64 is not the way to do it.Monetta
What sort of abuse, specifically, are you trying to avoid?Obloquy
@Aillyn: I think sharru means additional encoding of the encrypted parameters to remove unwanted charactersBrisco
Why the restriction on the characters in the obfuscated value? "Smells" hack-ish.Rheingold
i'm just trying to avoid user typing in id=999 , and then id=1000. and i want the urls to be "clean" (just letters and numbers). is that not possible?Ide
Added another answer that may address what you're looking forScour
Seems like your over-thinking a small detail. Can you provide a better example of why you need these seemingly arbitrary constraints?Rheingold
If you're relying on obfuscation to prevent abuse, you've already lost. Instead, design your app better - for example, by applying access controls, so people can't access what they shouldn't be able to, or by assigning a GUID to each record so you have a long, difficult to guess identifier.Cuirassier
S
5

You can use triple DES to encode the value using a narow block cipher.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace ConsoleApplication1 {
    class Program {
        static string ToHex(byte[] value) {
            StringBuilder sb = new StringBuilder();
            foreach (byte b in value)
                sb.AppendFormat("{0:x2}", b);
            return sb.ToString();
        }
        static string Encode(long value, byte[] key) {
            byte[] InputBuffer = new byte[8];
            byte[] OutputBuffer;
            unsafe {
                fixed (byte* pInputBuffer = InputBuffer) {
                    ((long*)pInputBuffer)[0] = value;
                }
            }
            TripleDESCryptoServiceProvider TDes = new TripleDESCryptoServiceProvider();
            TDes.Mode = CipherMode.ECB;
            TDes.Padding = PaddingMode.None;
            TDes.Key = key;

            using (ICryptoTransform Encryptor = TDes.CreateEncryptor()) {
                OutputBuffer = Encryptor.TransformFinalBlock(InputBuffer, 0, 8);
            }
            TDes.Clear();

            return ToHex(OutputBuffer);
        }
        static long Decode(string value, byte[] key) {
            byte[] InputBuffer = new byte[8];
            byte[] OutputBuffer;

            for (int i = 0; i < 8; i++) {
                InputBuffer[i] = Convert.ToByte(value.Substring(i * 2, 2), 16);
            }

            TripleDESCryptoServiceProvider TDes = new TripleDESCryptoServiceProvider();
            TDes.Mode = CipherMode.ECB;
            TDes.Padding = PaddingMode.None;
            TDes.Key = key;

            using (ICryptoTransform Decryptor = TDes.CreateDecryptor()) {
                OutputBuffer = Decryptor.TransformFinalBlock(InputBuffer, 0, 8);
            }
            TDes.Clear();

            unsafe {
                fixed (byte* pOutputBuffer = OutputBuffer) {
                    return ((long*)pOutputBuffer)[0];
                }
            }
        }
        static void Main(string[] args) {
            long NumberToEncode = (new Random()).Next();
            Console.WriteLine("Number to encode = {0}.", NumberToEncode);
            byte[] Key = new byte[24];
            (new RNGCryptoServiceProvider()).GetBytes(Key);
            Console.WriteLine("Key to encode with is {0}.", ToHex(Key));
            string EncodedValue = Encode(NumberToEncode, Key);
            Console.WriteLine("The encoded value is {0}.", EncodedValue);
            long DecodedValue = Decode(EncodedValue, Key);
            Console.WriteLine("The decoded result is {0}.", DecodedValue);
        }
    }
}

The output should be something like this:

Number to encode = 873435734.
Key to encode with is 38137b6a7aa49cc6040c4297064fdb4461c79a895f40b4d1.
The encoded value is 43ba3fb809a47b2f.
The decoded result is 873435734.

Note that the encoded value is only 16 characters wide.

If you're really conserned about abuse, then AES can be used in a similar manner. In the next example I switch in AES and write the 64 bit id number into both sides of the block. If it doesn't decode with the same value on both sides then it is rejected. This can prevent people from writing in random numbers.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace ConsoleApplication1 {
    class Program {
        static string ToHex(byte[] value) {
            StringBuilder sb = new StringBuilder();
            foreach (byte b in value)
                sb.AppendFormat("{0:x2}", b);
            return sb.ToString();
        }
        static string Encode(long value, byte[] key) {
            byte[] InputBuffer = new byte[16];
            byte[] OutputBuffer;
            unsafe {
                fixed (byte* pInputBuffer = InputBuffer) {
                    ((long*)pInputBuffer)[0] = value;
                    ((long*)pInputBuffer)[1] = value;
                }
            }
            AesCryptoServiceProvider Aes = new AesCryptoServiceProvider();
            Aes.Mode = CipherMode.ECB;
            Aes.Padding = PaddingMode.None;
            Aes.Key = key;

            using (ICryptoTransform Encryptor = Aes.CreateEncryptor()) {
                OutputBuffer = Encryptor.TransformFinalBlock(InputBuffer, 0, 16);
            }
            Aes.Clear();

            return ToHex(OutputBuffer);
        }
        static bool TryDecode(string value, byte[] key, out long result) {
            byte[] InputBuffer = new byte[16];
            byte[] OutputBuffer;

            for (int i = 0; i < 16; i++) {
                InputBuffer[i] = Convert.ToByte(value.Substring(i * 2, 2), 16);
            }

            AesCryptoServiceProvider Aes = new AesCryptoServiceProvider();
            Aes.Mode = CipherMode.ECB;
            Aes.Padding = PaddingMode.None;
            Aes.Key = key;

            using (ICryptoTransform Decryptor = Aes.CreateDecryptor()) {
                OutputBuffer = Decryptor.TransformFinalBlock(InputBuffer, 0, 16);
            }
            Aes.Clear();

            unsafe {
                fixed (byte* pOutputBuffer = OutputBuffer) {
                    //return ((long*)pOutputBuffer)[0];
                    if (((long*)pOutputBuffer)[0] == ((long*)pOutputBuffer)[1]) {
                        result = ((long*)pOutputBuffer)[0];
                        return true;
                    }
                    else {
                        result = 0;
                        return false;
                    }
                }
            }
        }
        static void Main(string[] args) {
            long NumberToEncode = (new Random()).Next();
            Console.WriteLine("Number to encode = {0}.", NumberToEncode);
            byte[] Key = new byte[24];
            (new RNGCryptoServiceProvider()).GetBytes(Key);
            Console.WriteLine("Key to encode with is {0}.", ToHex(Key));
            string EncodedValue = Encode(NumberToEncode, Key);
            Console.WriteLine("The encoded value is {0}.", EncodedValue);
            long DecodedValue;
            bool Success = TryDecode(EncodedValue, Key, out DecodedValue);
            if (Success) {
                Console.WriteLine("Successfully decoded the encoded value.");
                Console.WriteLine("The decoded result is {0}.", DecodedValue);
            }
            else
                Console.WriteLine("Failed to decode encoded value. Invalid result.");
        }
    }
}

The result should now look something like this:

Number to encode = 1795789891.
Key to encode with is 6c90323644c841a00d40d4407e23dbb2ab56530e1a4bae43.
The encoded value is 731fceec2af2fcc2790883f2b79e9a01.
Successfully decoded the encoded value.
The decoded result is 1795789891.

Also note that since we have now used a wider block cipher the encoded value is now 32 characters wide.

Scorper answered 26/8, 2010 at 0:4 Comment(6)
thanks for answer , looks great , ill give it a try. any idea about performance? is this a big overload?Ide
This shouldn't result in very significant overhead. If you are using HTTPS then this exact operation is performed a few hundred times just for that for a single HTML page so this should be trivial.Scorper
is it a must to use unsafe and pointers? those aren't really on my daily menu :)Ide
No, you can remove the pointers, but then you have to write a for loop to copy the integer into/from the byte array.Scorper
@Lunatic, @sharru: Neither a loop nor unsafe block is necessary, System.BitConverter will do the trick very nicely.Standpoint
Cool. Didn't see that before! Thanks!Scorper
S
5

You can use HttpServerUtility.UrlTokenEncode and HttpServerUtility.UrlTokenDecode

Encode uses base64 encoding, but replaces URL unfriendly characters.

There's a similar answer in a previous SO question. See the accepted answer.

Scour answered 25/8, 2010 at 20:13 Comment(0)
S
5

You can use triple DES to encode the value using a narow block cipher.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace ConsoleApplication1 {
    class Program {
        static string ToHex(byte[] value) {
            StringBuilder sb = new StringBuilder();
            foreach (byte b in value)
                sb.AppendFormat("{0:x2}", b);
            return sb.ToString();
        }
        static string Encode(long value, byte[] key) {
            byte[] InputBuffer = new byte[8];
            byte[] OutputBuffer;
            unsafe {
                fixed (byte* pInputBuffer = InputBuffer) {
                    ((long*)pInputBuffer)[0] = value;
                }
            }
            TripleDESCryptoServiceProvider TDes = new TripleDESCryptoServiceProvider();
            TDes.Mode = CipherMode.ECB;
            TDes.Padding = PaddingMode.None;
            TDes.Key = key;

            using (ICryptoTransform Encryptor = TDes.CreateEncryptor()) {
                OutputBuffer = Encryptor.TransformFinalBlock(InputBuffer, 0, 8);
            }
            TDes.Clear();

            return ToHex(OutputBuffer);
        }
        static long Decode(string value, byte[] key) {
            byte[] InputBuffer = new byte[8];
            byte[] OutputBuffer;

            for (int i = 0; i < 8; i++) {
                InputBuffer[i] = Convert.ToByte(value.Substring(i * 2, 2), 16);
            }

            TripleDESCryptoServiceProvider TDes = new TripleDESCryptoServiceProvider();
            TDes.Mode = CipherMode.ECB;
            TDes.Padding = PaddingMode.None;
            TDes.Key = key;

            using (ICryptoTransform Decryptor = TDes.CreateDecryptor()) {
                OutputBuffer = Decryptor.TransformFinalBlock(InputBuffer, 0, 8);
            }
            TDes.Clear();

            unsafe {
                fixed (byte* pOutputBuffer = OutputBuffer) {
                    return ((long*)pOutputBuffer)[0];
                }
            }
        }
        static void Main(string[] args) {
            long NumberToEncode = (new Random()).Next();
            Console.WriteLine("Number to encode = {0}.", NumberToEncode);
            byte[] Key = new byte[24];
            (new RNGCryptoServiceProvider()).GetBytes(Key);
            Console.WriteLine("Key to encode with is {0}.", ToHex(Key));
            string EncodedValue = Encode(NumberToEncode, Key);
            Console.WriteLine("The encoded value is {0}.", EncodedValue);
            long DecodedValue = Decode(EncodedValue, Key);
            Console.WriteLine("The decoded result is {0}.", DecodedValue);
        }
    }
}

The output should be something like this:

Number to encode = 873435734.
Key to encode with is 38137b6a7aa49cc6040c4297064fdb4461c79a895f40b4d1.
The encoded value is 43ba3fb809a47b2f.
The decoded result is 873435734.

Note that the encoded value is only 16 characters wide.

If you're really conserned about abuse, then AES can be used in a similar manner. In the next example I switch in AES and write the 64 bit id number into both sides of the block. If it doesn't decode with the same value on both sides then it is rejected. This can prevent people from writing in random numbers.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace ConsoleApplication1 {
    class Program {
        static string ToHex(byte[] value) {
            StringBuilder sb = new StringBuilder();
            foreach (byte b in value)
                sb.AppendFormat("{0:x2}", b);
            return sb.ToString();
        }
        static string Encode(long value, byte[] key) {
            byte[] InputBuffer = new byte[16];
            byte[] OutputBuffer;
            unsafe {
                fixed (byte* pInputBuffer = InputBuffer) {
                    ((long*)pInputBuffer)[0] = value;
                    ((long*)pInputBuffer)[1] = value;
                }
            }
            AesCryptoServiceProvider Aes = new AesCryptoServiceProvider();
            Aes.Mode = CipherMode.ECB;
            Aes.Padding = PaddingMode.None;
            Aes.Key = key;

            using (ICryptoTransform Encryptor = Aes.CreateEncryptor()) {
                OutputBuffer = Encryptor.TransformFinalBlock(InputBuffer, 0, 16);
            }
            Aes.Clear();

            return ToHex(OutputBuffer);
        }
        static bool TryDecode(string value, byte[] key, out long result) {
            byte[] InputBuffer = new byte[16];
            byte[] OutputBuffer;

            for (int i = 0; i < 16; i++) {
                InputBuffer[i] = Convert.ToByte(value.Substring(i * 2, 2), 16);
            }

            AesCryptoServiceProvider Aes = new AesCryptoServiceProvider();
            Aes.Mode = CipherMode.ECB;
            Aes.Padding = PaddingMode.None;
            Aes.Key = key;

            using (ICryptoTransform Decryptor = Aes.CreateDecryptor()) {
                OutputBuffer = Decryptor.TransformFinalBlock(InputBuffer, 0, 16);
            }
            Aes.Clear();

            unsafe {
                fixed (byte* pOutputBuffer = OutputBuffer) {
                    //return ((long*)pOutputBuffer)[0];
                    if (((long*)pOutputBuffer)[0] == ((long*)pOutputBuffer)[1]) {
                        result = ((long*)pOutputBuffer)[0];
                        return true;
                    }
                    else {
                        result = 0;
                        return false;
                    }
                }
            }
        }
        static void Main(string[] args) {
            long NumberToEncode = (new Random()).Next();
            Console.WriteLine("Number to encode = {0}.", NumberToEncode);
            byte[] Key = new byte[24];
            (new RNGCryptoServiceProvider()).GetBytes(Key);
            Console.WriteLine("Key to encode with is {0}.", ToHex(Key));
            string EncodedValue = Encode(NumberToEncode, Key);
            Console.WriteLine("The encoded value is {0}.", EncodedValue);
            long DecodedValue;
            bool Success = TryDecode(EncodedValue, Key, out DecodedValue);
            if (Success) {
                Console.WriteLine("Successfully decoded the encoded value.");
                Console.WriteLine("The decoded result is {0}.", DecodedValue);
            }
            else
                Console.WriteLine("Failed to decode encoded value. Invalid result.");
        }
    }
}

The result should now look something like this:

Number to encode = 1795789891.
Key to encode with is 6c90323644c841a00d40d4407e23dbb2ab56530e1a4bae43.
The encoded value is 731fceec2af2fcc2790883f2b79e9a01.
Successfully decoded the encoded value.
The decoded result is 1795789891.

Also note that since we have now used a wider block cipher the encoded value is now 32 characters wide.

Scorper answered 26/8, 2010 at 0:4 Comment(6)
thanks for answer , looks great , ill give it a try. any idea about performance? is this a big overload?Ide
This shouldn't result in very significant overhead. If you are using HTTPS then this exact operation is performed a few hundred times just for that for a single HTML page so this should be trivial.Scorper
is it a must to use unsafe and pointers? those aren't really on my daily menu :)Ide
No, you can remove the pointers, but then you have to write a for loop to copy the integer into/from the byte array.Scorper
@Lunatic, @sharru: Neither a loop nor unsafe block is necessary, System.BitConverter will do the trick very nicely.Standpoint
Cool. Didn't see that before! Thanks!Scorper
S
4

So here's a working example that I put together from a few different examples that takes an integer ID and converts it to a hexidecimal formatted encrypted string. This encrypted string should not include URL-unfriendly characters and will not include escaped characters either.

Here's the entire working console app. Please note that it's a prototype and definitely not for production -- this just illustrates a solution and definitely needs to be refactored.

When you run the code, your output should be this:

1234 get encrypted as ZaB5GE/bWMJcNaeY/xJ6PQ==
ZaB5GE/bWMJcNaeY/xJ6PQ== encrypted is this in hex 5a61423547452f62574d4a634e6165592f784a3650513d3d
5a61423547452f62574d4a634e6165592f784a3650513d3d gets dehexed as ZaB5GE/bWMJcNaeY/xJ6PQ==
ZaB5GE/bWMJcNaeY/xJ6PQ== got decrypted as 1234

Sources:
byte to hex article on SO: Encryption to alphanumeric in System.Security.Cryptography
Crypto helper class: Encrypt and decrypt a string (4th answer)

Program2.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Security.Cryptography;
using System.IO;

namespace ConsoleApplication1
{
    class Program2
    {
        static void Main(string[] args)
        {
            int theId = 1234;   //the ID that's being manipulated
            byte[] byteArray;   //the byte array that stores

            //convert the ID to an encrypted string using a Crypto helper class
            string encryptedString = Crypto.EncryptStringAES(theId.ToString(), "mysecret");
            Console.WriteLine("{0} get encrypted as {1}", theId.ToString(), encryptedString);

            //convert the encrypted string to byte array
            byteArray = ASCIIEncoding.Default.GetBytes(encryptedString);
            StringBuilder result = new StringBuilder();

            //convert each byte to hex and append to a stringbuilder
            foreach (byte outputByte in byteArray)
            {
                result.Append(outputByte.ToString("x2"));
            }

            Console.WriteLine("{0} encrypted is this in hex {1}", encryptedString, result.ToString());

            //now reverse the process, and start with converting each char in string to byte
            int stringLength = result.Length;
            byte[] bytes = new byte[stringLength / 2];

            for (int i = 0; i < stringLength; i += 2)
            {
                bytes[i / 2] = System.Convert.ToByte(result.ToString().Substring(i, 2), 16);
            }

            //convert the byte array to de-"hexed" string
            string dehexedString = ASCIIEncoding.Default.GetString(bytes);

            Console.WriteLine("{0} gets dehexed as {1}", result, dehexedString);

            //decrypt the de-"hexed" string using Crypto helper class
            string decryptedString = Crypto.DecryptStringAES(dehexedString, "mysecret");
            Console.WriteLine("{0} got decrypted as {1}", dehexedString, decryptedString);

            Console.ReadLine();
        }
    }

    public class Crypto
    {
        private static byte[] _salt = Encoding.ASCII.GetBytes("o6806642kbM7c5");

        /// <summary>
        /// Encrypt the given string using AES.  The string can be decrypted using 
        /// DecryptStringAES().  The sharedSecret parameters must match.
        /// </summary>
        /// <param name="plainText">The text to encrypt.</param>
        /// <param name="sharedSecret">A password used to generate a key for encryption.</param>
        public static string EncryptStringAES(string plainText, string sharedSecret)
        {
            if (string.IsNullOrEmpty(plainText))
                throw new ArgumentNullException("plainText");
            if (string.IsNullOrEmpty(sharedSecret))
                throw new ArgumentNullException("sharedSecret");

            string outStr = null;                       // Encrypted string to return
            RijndaelManaged aesAlg = null;              // RijndaelManaged object used to encrypt the data.

            try
            {
                // generate the key from the shared secret and the salt
                Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);

                // Create a RijndaelManaged object
                // with the specified key and IV.
                aesAlg = new RijndaelManaged();
                aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
                aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8);

                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {

                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                    }
                    outStr = Convert.ToBase64String(msEncrypt.ToArray());
                }
            }
            finally
            {
                // Clear the RijndaelManaged object.
                if (aesAlg != null)
                    aesAlg.Clear();
            }

            // Return the encrypted bytes from the memory stream.
            return outStr;
        }

        /// <summary>
        /// Decrypt the given string.  Assumes the string was encrypted using 
        /// EncryptStringAES(), using an identical sharedSecret.
        /// </summary>
        /// <param name="cipherText">The text to decrypt.</param>
        /// <param name="sharedSecret">A password used to generate a key for decryption.</param>
        public static string DecryptStringAES(string cipherText, string sharedSecret)
        {
            if (string.IsNullOrEmpty(cipherText))
                throw new ArgumentNullException("cipherText");
            if (string.IsNullOrEmpty(sharedSecret))
                throw new ArgumentNullException("sharedSecret");

            // Declare the RijndaelManaged object
            // used to decrypt the data.
            RijndaelManaged aesAlg = null;

            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;

            try
            {
                // generate the key from the shared secret and the salt
                Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, _salt);

                // Create a RijndaelManaged object
                // with the specified key and IV.
                aesAlg = new RijndaelManaged();
                aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
                aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8);

                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                // Create the streams used for decryption.                
                byte[] bytes = Convert.FromBase64String(cipherText);
                using (MemoryStream msDecrypt = new MemoryStream(bytes))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))

                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }
            finally
            {
                // Clear the RijndaelManaged object.
                if (aesAlg != null)
                    aesAlg.Clear();
            }

            return plaintext;
        }
    }

}
Scour answered 25/8, 2010 at 21:20 Comment(1)
Glad it works! Unfortunately it is long because of the limited alphanumeric characters that can be used. :)Scour
R
3

The problem with obfuscating the id, is that you need a way to de-obfuscicate. This requires either:

  1. Fullblown encryption, which if it's any good will require a pretty large value.
  2. Storing the value along with the id number, so it becomes an alternative identifier.
  3. Something that depends on security-by-obscurity.

Alternatively, keep the id clear, but use a check as well.

public static String ChkSumStr(int id, int reduce)
{
  return string.Concat(ReduceStrength(ChkSum(id), reduce).Select(b => b.ToString("X2")).ToArray());
}
public static byte[] ChkSum(int id)
{
    byte[] idBytes = Encoding.UTF8.GetBytes("This is an arbitrary salt" + id);
    return SHA256.Create().ComputeHash(idBytes);
}
private static byte[] ReduceStrength(byte[] src, int reduce)
{
  byte[] ret = null;
  for(int i = 0; i != reduce; ++i)
  {
    ret = new byte[src.Length / 2];
    for(int j = 0; j != ret.Length; ++j)
    {
      ret[j] = (byte)(src[j * 2] ^ src[j * 2 + 1]);
    }
    src = ret;
  }
  return src;
}

The higher the value given for reduce, the smaller the result (until at 6 it keeps producing the empty string). A low value (or 0) gives better security, at the cost of a longer URI.

The string "This is an arbitrary salt" needs to be secret for best security. It can be hardcoded in some uses, but would want to be obtained from a secure source for others.

With the above, an id of 15 and a reduce of 3 produces a result of 05469B1E. We can then use this as:

www.domain.com/?id=15&chk=05469B1E

In the handler that would look up whatever 15 is, we do the same thing again, and if the result is different to 05469B1E we can either return a 403 Forbidden or arguably more reasonable 404 Not Found (on the basis that we've received a URI that as a whole doesn't identify anything).

Rainbow answered 25/8, 2010 at 21:37 Comment(0)
M
1

Have you tried URL encoding your query string text? It's part of the HttpUtility class which:

Provides methods for encoding and decoding URLs when processing Web requests.

and should allow you to pass your base64 encoded text in the query string.

Monetta answered 25/8, 2010 at 20:12 Comment(1)
thx for answer , i just dont want charaters like %F2 or %B2 in the url.Ide
S
0

Do your encryption and then use HttpServerUtility.UrlTokenEncode() to encode the byte array.

Spanker answered 25/8, 2010 at 20:18 Comment(1)
Sorry, I missed the additional requirement that all characters had to be alphanumeric. If that's not an absolute requirement, it is safe to include the "-" and "_" in a url parameter ...Spanker

© 2022 - 2024 — McMap. All rights reserved.