API-tarkistesumma on olennainen osa turvallista API-kutsua, jolla varmistetaan, että viesti tulee luotetusta lähteestä. Creamailerin v2-API käyttää HMAC-SHA256-allekirjoitusta, joka muodostetaan yhdistämällä seuraavat elementit:
- API URL: API:n base-URL (esim.
https://api.cmfile.net), ilman lopun kauttaviivaa - Reitti: kutsun polku ilman alkavaa kauttaviivaa, esim.
v2/api/lists - Query string: query string ?-merkki mukaan luettuna, tai tyhjä merkkijono jos kyselyä ei ole
- JSON-body: lähetettävä raaka JSON-data (tyhjä GET- ja DELETE-pyynnöissä)
- Aikaleima: kutsun tekohetken UNIX-aikaleima sekunteina (±5 minuutin sisällä palvelimen kellosta)
- Yhteinen tunniste: ylläpidosta löytyvä avain, jota käytetään HMAC:n avaimena (ei yhdistetä merkkijonoon)
Tarkistesumma muodostetaan yhdistämällä viisi ensimmäistä komponenttia merkkijonoksi ja laskemalla siitä HMAC-SHA256-hash käyttäen yhteistä tunnistetta HMAC:n avaimena.
Kaava:
signature = HMAC-SHA256(api_url + "/" + route + query_string + json_body + timestamp, shared_secret)
Esimerkkidata
- API URL: https://api.cmfile.net
- Reitti: v2/api/lists
- Query string: (tyhjä merkkijono)
- JSON: {"name":"My list","language":"fi","auto_suppress":true}
- Aikaleima: 1724851326
- Yhteinen tunniste (shared_secret): 1234567890123456789012345678901234567890
Esimerkkidatan hash:
acf0c93e31b81571053a667933159e3f3ce9d5e199fff898308278dc6098d011
Esimerkkitoteutukset
PHP
function signature($apiUrl, $route, $queryString, $jsonBody, $timestamp, $sharedSecret)
{
$timestamp = is_null($timestamp) ? (string) time() : $timestamp;
$data = $apiUrl . '/' . $route . $queryString . $jsonBody . $timestamp;
return hash_hmac('sha256', $data, $sharedSecret);
}
// Esimerkki:
echo signature(
'https://api.cmfile.net',
'v2/api/lists',
'', // query string, tyhjä jos ei kyselyä
'{"name":"My list","language":"fi","auto_suppress":true}', // raw JSON body
'1724851326',
'1234567890123456789012345678901234567890'
);Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class ApiSignature {
public static String signature(String apiUrl, String route, String queryString, String jsonBody, String timestamp, String sharedSecret) throws Exception {
String data = apiUrl + "/" + route + queryString + jsonBody + timestamp;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(sharedSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
public static void main(String[] args) throws Exception {
String apiUrl = "https://api.cmfile.net";
String route = "v2/api/lists";
String queryString = "";
String jsonBody = "{\"name\":\"My list\",\"language\":\"fi\",\"auto_suppress\":true}";
String timestamp = "1724851326";
String sharedSecret = "1234567890123456789012345678901234567890";
System.out.println(signature(apiUrl, route, queryString, jsonBody, timestamp, sharedSecret));
}
}Node / JavaScript
// Node.js sisältää valmiin crypto-moduulin — erillistä asennusta ei tarvita.
// Selainympäristössä voi käyttää SubtleCrypto-rajapintaa tai CryptoJS-kirjastoa.
const crypto = require('crypto');
function signature(apiUrl, route, queryString, jsonBody, timestamp, sharedSecret) {
const data = apiUrl + '/' + route + queryString + jsonBody + timestamp;
return crypto
.createHmac('sha256', sharedSecret)
.update(data)
.digest('hex');
}
// Esimerkkidata
const apiUrl = 'https://api.cmfile.net';
const route = 'v2/api/lists';
const queryString = '';
const jsonBody = '{"name":"My list","language":"fi","auto_suppress":true}';
const timestamp = '1724851326';
const sharedSecret = '1234567890123456789012345678901234567890';
console.log(signature(apiUrl, route, queryString, jsonBody, timestamp, sharedSecret));Python
import hmac
import hashlib
def signature(api_url, route, query_string, json_body, timestamp, shared_secret):
data = f"{api_url}/{route}{query_string}{json_body}{timestamp}"
return hmac.new(
shared_secret.encode("utf-8"),
data.encode("utf-8"),
hashlib.sha256,
).hexdigest()
# Esimerkkidata
print(signature(
"https://api.cmfile.net",
"v2/api/lists",
"",
'{"name":"My list","language":"fi","auto_suppress":true}',
"1724851326",
"1234567890123456789012345678901234567890",
))cURL / bash
API_URL="https://api.cmfile.net"
ROUTE="v2/api/lists"
QUERY=""
BODY='{"name":"My list","language":"fi","auto_suppress":true}'
TIMESTAMP="1724851326"
SECRET="1234567890123456789012345678901234567890"
DATA="${API_URL}/${ROUTE}${QUERY}${BODY}${TIMESTAMP}"
echo -n "$DATA" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}'
Kommentit
0 kommenttia
Kirjaudu sisään jättääksesi kommentin.