How to verify a Postback with Skadnetwork/Apple

934 Views Asked by At

I'm having issues to verify a postback with Skadnetwork/Apple according to the documentation Apple is giving out.

There are two issues I have (at least I think there are only two issues).

  1. \u2063 - I'm using a PHP to grab all the information from a POST and then create the string for later verification. Sadly I'm not sure if the \u2063 should simply be there in the string or if it should there be in some encoded/decoded way.
  2. The Apple Public Key - How should it be used. The version that is seen in the documentation in some decoded/encoded way. Docs say decode base 64 and then create X.509 standard public key from that.

Does anyone have a working example? At the moment I'm complete lost.

1

There are 1 best solutions below

1
On BEST ANSWER

Im using NodeJS and it was pretty simple. I took Apple's public key and wrapped it with -----BEGIN PUBLIC KEY-----\n and \n-----END PUBLIC KEY-----.

-----BEGIN PUBLIC KEY-----
<APPLE_PUBLIC_KEY_BASE_64 (copy paste from Apple's guide)>
-----END PUBLIC KEY-----

Or you can use NodeJs crypto module to load the public key:

const key = Buffer.from(`<APPLE_PUBLIC_KEY_BASE_64 (copy paste from Apple's guide)>`, 'base64');
const publicKey = crypto.createPublicKey({
  key,
  format: 'der',
  type: 'spki',
});

Then I concatenated the parts of the postback that are needed for the verification with \u2063 separator.

// ad network version 2.0/2.1
const message = [
  version,
  adNetworkId,
  campaignId,
  appId,
  transactionId,
  redownload,
].join('\u2063');

Then I used NodeJS crypto module to verify the signature:

const verify = crypto.createVerify('sha256');
verify.update(message);
verify.verify(publicKey, signature, 'base64'); // this returns a boolean

This can be done in a similar way with Singular-SKAdNetwork-App ECDSA wrapper class from here

SEPERATOR = u"\u2063"

postback = {
    "version": "2.1",
    "ad-network-id": "com.example",
    "campaign-id": 42,
    "transaction-id": "6aafb7a5-0170-41b5-bbe4-fe71dedf1e28",
    "app-id": 525463029,
    "attribution-signature": "MEUCID6rbq3qt4GvFaAaynh5/LAcvn1d8CQTRhrZhLIxLKntAiEAo7IrvoMw6u2qDg6Tr5vIsEHXjlLkPlCOL0ojJcEh3Qw=",
    "redownload": True,
    "source-app-id": 1234567891,
    "conversion-value": 20
}

pub_key = """
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWdp8GPcGqmhgzEFj9Z2nSpQVddayaPe4FMzqM9wib1+aHaaIzoHoLN9zW4K8y4SPykE3YVK3sVqW6Af0lfx3gg==
-----END PUBLIC KEY-----
"""

message = (
    postback["version"]
    + SEPERATOR
    + postback["ad-network-id"]
    + SEPERATOR
    + str(postback["campaign-id"])
    + SEPERATOR
    + str(postback["app-id"])
    + SEPERATOR
    + postback["transaction-id"]
    + SEPERATOR
    + str(postback["redownload"]).lower()
    + SEPERATOR
    + str(postback["source-app-id"])
)

ecdsa = ECDSA(pub_key)
signature = postback["attribution-signature"]
ecdsa.verify(message, signature) # this returns a boolean

I hope this will help. I don't have any experience with PHP :/