---
title: Query string hashing
related:
  - https://docs.kentico.com/13/macro-expressions/troubleshooting-macros/working-with-macro-signatures.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

Query strings in URLs are useful and important in many ways, for example, when passing various values between pages or retrieving data from the database. In some cases though, an unauthorized user could obtain sensitive data or harm the system by entering a URL with **tampered query string parameters**.

To prevent tampering with query string parameters, the system adds the result of a **hash function** at the end of each URL. Such URLs can look like this:

> **Info:** http://localhost/Xperience/cms/getfile/2d003444-9a27-43c9-be97-4f5832474015/Partners\_logos\_silver.aspx?latestfordocid=75&**hash=eee41e027bd45142fd1f44d173d61950f34d6e98f4e35018fda70542322adc77\&chset=013bca78-6bf2-42ac-8959-b8bbbeb0a8e8**

The part in bold is the hash parameter added to the URL. If an attacker modifies the parameters and tries to submit such a URL, the system rejects it, because the query string parameters and hash do not match.

The hash function is calculated from the query string parameters using [SHA-2](http://en.wikipedia.org/wiki/SHA-2). The hashing is used in various parts of the system:

- Dialogs in the administration
- [Macro signatures](https://docs.kentico.com/13/macro-expressions/troubleshooting-macros/working-with-macro-signatures.md)
- In links for downloading files (e.g., getamazonfile.aspx, getazurefile.aspx or sometimes even with getfile.aspx) – to ensure that users download only the file specified in the original URL and nothing else.

## Salt

Protection of query string parameters using only the hash function would not be enough because attackers are able to reverse the hash function using [rainbow tables](http://en.wikipedia.org/wiki/Rainbow_table). For this reason, the system adds a **salt** to the URL before hashing it.

> **Info:** **Hash calculation:**
>
> URL parameters + salt -> all this is hashed using [SHA-2](http://en.wikipedia.org/wiki/SHA-2) and added to the original URL.

The salt is a secret string of characters, which users do not have access to. In Xperience, the default salt added to the URL is a **randomly generated GUID** specified by the _CMSHashStringSalt_ key in the web.config file:

```xml

<add key="CMSHashStringSalt" value="e68b9ad6-a461-4707-8e3e-ece73f03dd02" />

```

You may change this value if you need to. If you delete this key completely, the system uses the connection string stored in the web.config file as the salt.

> **Warning:** If you have already stored some persistent information (links for downloading files, image links, macros) in the system and you change the salt calculation, then these links and **information may become broken**. You will have to re-save the content to create hashes with the new salt.

## User specific hash

Sometimes it is useful to add user-specific information to the hash. Either the user session ID or IP address (if there is no session ID) are used for this purpose. If attackers manage to eavesdrop a URL and try to exploit it to gain sensitive data, they would not succeed, as their session ID would not match the hash.

The user specific hash is used mainly for non-persistent information, such as displaying dialog boxes.

> **Note:** Note that if you use user specific hashing and save some content with it, users other than the one who saved the content will not be able to use it.

## Custom hash validation

We recommend using hashing features when developing custom dialog boxes for the administration interface. The following methods are available in the Xperience API:

Hash calculation:

- **QueryHelper.BuildQueryWithHash** - builds the entire query string with any number of parameters, automatically calculates and adds a hash parameter (with all parameters as the input).

  ```csharp title="Example - BuildQueryWithHash"

  using CMS.Helpers;

  ...

  // Sample URL parameter values
  string urlParamValue1 = "value1";
  string urlParamValue2 = "value2";

  // Sample base URL
  string url = "base";

  // Creates a query string containing the sample parameters and the hash
  string queryString = QueryHelper.BuildQueryWithHash("parameter1", urlParamValue1, "parameter2", urlParamValue2);

  // Adds the query string parameters to the URL, including the hash
  url += queryString;


  ```
- **ValidationHelper.GetHashString** - creates a SHA2 hash of a specified value. Can be used to create hashes for any values, not just query strings. The optional _HashSettings_ parameter allows you to specify whether the hash is user-specific, and also add a custom salt.

  ```csharp title="Example - GetHashString"

  using CMS.Helpers;

  ...

  // Sample string value
  string customValue = "value";

  // Creates a hash for the custom value
  string hash = ValidationHelper.GetHashString(urlParameterValue);

  ```

Hash validation:

- **QueryHelper.ValidateHash** - works directly with the query string and can exclude individual parameters from hash validation.
- **ValidationHelper.ValidateHash** - general hash validation method, can be used for macro signatures.

You can validate hashes on pages individually:

```csharp

using CMS.Helpers;

...

// Validates a hash value
if (QueryHelper.ValidateHash("hash"))
{
    // The validation was successful, perform any required actions
}

```

Or you can validate hashes automatically by including the _\[HashValidation(Name="hash2")]_ attribute on a page:

```csharp

using CMS.UIControls;
using CMS.Helpers;
using CMS.Base;

[HashValidation(HashValidationSalts.REDIRECT_PAGE)]
public partial class CMSMessages_Redirect : MessagePage
{
    /// <summary>
    /// OnInit event.
    /// </summary>
    protected override void OnPreInit(EventArgs e)
    {
        string url = QueryHelper.GetText("url", String.Empty);
        CheckHashValidationAttribute = !(url.StartsWithAny(StringComparison.InvariantCulture, "~", "/"));
        base.OnPreInit(e);
    }

```
