Signed URLs
Overview
URL signing is a technique that can be used by Apps to verify the authenticity of HTTP requests originating from us, using information contained in the URL itself.
This adds an additional layer of security for interactions between your Application and the our ecosystem.
1. Generate the URL Signing Secret
First you must generate the URL Signing Secret for your Application. Navigate to your Application in the Developer Portal and on the Basic Details page locate the URL Signing Secret section.
Upon clicking “Create”.
A pop-up will appear for confirmation.
Once confirmed, the platform will generate the Signing Secret and display it to you in plain text.
This is the only time the secret will appear in plain text, you must copy it and store it somewhere safe. The generated secret is unrecoverable. If the secret is lost, you’ll have to generate a new one using this process.
2. Verifying a signed URL
Once you have generated a URL Signing Secret, any future redirects from the App Store to your Application will include an additional query string parameter named signature.
https://your.app.com
?accountServicerId=0f1011ea-6701-4a7c-ab92-bdc01600dfc8
×tamp=1630687797463
&signature=9466417f6b0a4fbe82bd0d701c62ea80fb353693976f3ef3bd01f95571221f1f
This parameter contains a signature which is generated by signing the original URL with the URL Signing Secret generated in Step 1.
The following steps are required to verify the signature:
- Parse the signature query string parameter from the URL.
- Remove the signature query string parameter from the URL so you’re just left with the original URL.
- Compute the HMAC SHA256 hash of the original URL, using the Signing Secret generated in Step 1. We’ve provided code snippets below outlining how to do this.
- Compare your generated hash with the signature parsed from the URL. If it matches then the signature is valid.
Here’s a couple example code snippets outlining how to verify the signature:
import crypto from 'crypto'
/**
* Validate the signature of the given url
* @param url the signed url to validate
* @param signingSecret your Application's signing secret
* @returns
*/
function validateSignedContext(url: string, signingSecret: string) {
if (!url) {
throw new Error('Missing url')
}
if (!signingSecret) {
throw new Error('Missing signingSecret')
}
const parsedURL = new URL(url)
// 1. Parse the signature query string parameter from the URL
const receivedSignature = parsedURL.searchParams.get('signature')
// 2. Remove the signature parameter from the URL
parsedURL.searchParams.delete('signature')
const urlToVerify = parsedURL.toString()
// 3. Compute the HMAC SHA256 hash of the original URL, using the signing secret from your Application
const calculatedSignature = crypto
.createHmac('sha256', signingSecret)
.update(urlToVerify)
.digest('hex')
// 4. Compare your generated signature with the signature parsed from the URL
const isValidSignature = calculatedSignature === receivedSignature
return isValidSignature
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Collections.Specialized;
using System.Security.Cryptography;
namespace VerifySignatureExample
{
public class SignatureVerifier
{
/**
* Validate the signature of the given url
* @param url the signed url to validate
* @param signingSecret your Application's signing secret
* @returns
*/
public static bool validateSignedContext(string url, string signingSecret) {
if (string.IsNullOrEmpty(url)){
throw new Exception("Missing url");
}
if (string.IsNullOrEmpty(url)){
throw new Exception("Missing signingSecret");
}
var parsedURL = new UriBuilder(url);
NameValueCollection query = HttpUtility.ParseQueryString(parsedURL.Query);
// 1. Parse the signature query string parameter from the URL
var receivedSignature = query.Get("signature");
// 2. Remove the signature parameter from the URL
query.Remove("signature");
parsedURL.Query = query.ToString();
var urlToVerify = parsedURL.ToString();
// 3. Compute the HMAC SHA256 hash of the original URL, using the signing secret from your Application
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] secretAsBytes = encoding.GetBytes(secret);
HMACSHA256 hmacsha256 = new HMACSHA256(secretAsBytes);
byte[] urlToVerifyBytes = encoding.GetBytes(urlToVerify);
byte[] computedHash = hmacsha256.ComputeHash(urlToVerifyBytes);
// BitConverter is used to convert the byte array into a hexadecimal string.
// We need to strip out any - characters and make sure it's all lower case
var calculatedSignature = BitConverter.ToString(computedHash).Replace("-", "").ToLower();
// 4. Compare your generated signature with the signature parsed from the URL
var isValidSignature = calculatedSignature == receivedSignature;
return isValidSignature;
}
}
}
Updated 7 months ago