0

i am implementing the application using asp.net.

I want to make the querysting unchangeable. if i do the changes in manually , some exception needs to thrown .

how do i implement ?

Siddharth
  • 35
  • 1
  • 8
  • 1
    You are probably trying to solve the wrong problem. You have to check on the server-side if the user has actual permission to do what he requests. Never trust the data you receive from the client. – ZippyV Apr 17 '13 at 07:49
  • @ZippyV While a good sentiment to have, when you're dealing with - for example - payment providers that require POSTs back and forth, you will want to keep a hash for certain data-objects to make sure the data hasn't been tampered with in a man-in-the-middle attack. – J. Steen Apr 17 '13 at 07:50
  • @J.Steen That's where SSL comes in. – ZippyV Apr 17 '13 at 07:53
  • @ZippyV SSL will not hide or disable POST/GET-values from being changed, if one wants to. I had to help a company fix their communication where they sent a value to deposit to a payment provider, and then the payment provider sent that value back. This was easily changed with just the developer tools in, e.g., Chrome. Hashing with a salt, or even storing the value before hand, solved this issue completely. And no, changing payment providers wasn't an option. =) – J. Steen Apr 17 '13 at 07:55
  • @ZippyV That said, I'm fairly sure the OP doesn't have these requirements, in this particular case, so another approach might be better. – J. Steen Apr 17 '13 at 07:56

1 Answers1

1

"Try encrypting the querystring and append the resulting string to the querystring. When reading out your querystring, first encrypt the normal parameters again and compare it to the string. Then when any parameters get changed, the hash will not match anymore and you can throw an exception.

Something like this. Search for a nice Querystring reader/writer class to make life easier.

private string GetSecureQsToken(string querystring)
{
    Byte[] buffer = Encoding.UTF8.GetBytes(querystring);
    SHA1CryptoServiceProvider cryptoTransformSha1 =
    new SHA1CryptoServiceProvider();
    string hash = BitConverter.ToString(
        cryptoTransformSha1.ComputeHash(buffer)).Replace("-", "");

    return hash;
}

private void GoToSecureQsPage()
{
    string qsvalues = "id=1&page=4";
    Response.Redirect(string.Format("Default.aspx?{0}&hash={1}", qsvalues, GetSecureQsToken(qsvalues)));
}

private void ReadSecureQs()
{
    //here check the normal querystring parameters again against the hash parameter
    if (GetSecureQsToken("id=1&page=4") != Request.QueryString["hash"])
    {
        throw new Exception("Error here");
    }
}

I simply went for the Hash version as it was suggested in the comments, but yes, then it becomes changeable again by the client. SO you will need some encryption like this:

public class SecureQuerystring
{
    public SecureQuerystring()
    {
        m_passPhrase = "#oqT6%hKg";
        m_saltValue = "7651273512";
        m_initVector = "@1B2c3D4e5F6g7H8";
        m_hashAlgorithm = "SHA1";
        m_passwordIterations = 5;
        m_keySize = 128;
    }


    private string m_plaintext;
    private string m_ciphertext;
    private byte[] m_plaintextbytes;
    private byte[] m_ciphertextbytes;
    private string m_passPhrase;
    private string m_saltValue;
    private string m_hashAlgorithm;
    private Int32 m_passwordIterations;
    private string m_initVector;
    private Int32 m_keySize;


    public string plaintext
    {
        get { return m_plaintext; }
        set { m_plaintext = value; }
    }


    public string ciphertext
    {
        get { return m_ciphertext; }
        set { m_ciphertext = value; }
    }


    public byte[] plaintextbytes
    {
        get { return m_plaintextbytes; }
        set { m_plaintextbytes = value; }
    }


    public byte[] ciphertextbytes
    {
        get { return m_ciphertextbytes; }
        set { m_ciphertextbytes = value; }
    }


    public string passPhrase
    {
        get { return m_passPhrase; }
        set { m_passPhrase = value; }
    }


    public string saltValue
    {
        get { return m_saltValue; }
        set { m_saltValue = value; }
    }


    public string hashAlgorithm
    {
        get { return m_hashAlgorithm; }
        set { m_hashAlgorithm = value; }
    }


    public Int32 passwordIterations
    {
        get { return m_passwordIterations; }
        set { m_passwordIterations = value; }
    }


    public string initVector
    {
        get { return m_initVector; }
        set { m_initVector = value; }
    }


    public Int32 keySize
    {
        get { return m_keySize; }
        set { m_keySize = value; }
    }

    public string ASCIIEncrypt(string plaintext2)
    {
        try
        {
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(m_initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(m_saltValue);
            byte[] plainTextBytes = Encoding.ASCII.GetBytes(plaintext2);
            PasswordDeriveBytes password = new PasswordDeriveBytes(m_passPhrase, saltValueBytes, m_hashAlgorithm, m_passwordIterations);
            byte[] keyBytes = password.GetBytes(m_keySize / 8);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream();
            CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
            cryptoStream.FlushFinalBlock();
            byte[] cipherTextBytes = memoryStream.ToArray();
            memoryStream.Close();
            cryptoStream.Close();
            m_ciphertext = Convert.ToBase64String(cipherTextBytes);
            return "SUCCESS";
        }
        catch (Exception ex)
        {
            return ex.Message.ToString();
        }


    }

    public string ASCIIDecrypt(string ciphertext2)
    {
        try
        {
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(m_initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(m_saltValue);
            byte[] cipherTextBytes = Convert.FromBase64String(ciphertext2);
            PasswordDeriveBytes password = new PasswordDeriveBytes(m_passPhrase, saltValueBytes, m_hashAlgorithm, m_passwordIterations);
            byte[] keyBytes = password.GetBytes(keySize / 8);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
            CryptoStream 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();
            m_plaintext = Encoding.ASCII.GetString(plainTextBytes);
            return "SUCCESS";


        }
        catch (Exception ex)
        {
            return ex.Message.ToString();
        }


    }


}

So append to the qyerstring the ASCIIEncrypt("yourquerstring without encryption string") and when reading read the normal qs paramaters again and compare the hash in the qs to the result.

Yeronimo
  • 1,731
  • 15
  • 28
  • Don't encrypt - hash. http://stackoverflow.com/questions/326699/difference-between-hashing-a-password-and-encrypting-it – J. Steen Apr 17 '13 at 07:48
  • I tried encryption technology,but its lead to make so difficult.Can you please give me some other suggestion ? – Siddharth Apr 17 '13 at 07:51
  • Nothing stops the client from computing the hash himself. – ZippyV Apr 17 '13 at 07:52
  • Salt etc added. @OP I don't know any other method that will prevent the tampering. Maybe some fellow commenters have a different solution – Yeronimo Apr 17 '13 at 08:01