Skip to main content

Redirect signature verification

Example

Link https://merchant.alikassa.com/cabinet/form/setting-api-certs generate "API certificate for notifications", save the archive, unpack

  • public.pem

Wrap all POST data in json (in the same order) and sign

$verif = openssl_verify(json_encode([
'order_id' => $_POST['order_id'],
'uuid' => $_POST['uuid'],
]),
base64_decode($_POST['sign']),
file_get_contents('./certs/notification/public.pem'));

if (!$verif) {
throw new \Exception;
}
import express from 'express';
import { createVerify } from 'crypto';
import { readFileSync } from 'fs';

const app = express();
app.use(express.urlencoded({ extended: true }));

app.post('/notification', (req, res) => {
const params = {
order_id: req.body.order_id,
uuid: req.body.uuid,
};

const data = JSON.stringify(params);
const signature = Buffer.from(req.body.sign || '', 'base64');
const publicKey = readFileSync('./certs/notification/public.pem');

const verifier = createVerify('SHA256');
verifier.update(data);
verifier.end();

const verified = verifier.verify(publicKey, signature);
if (!verified) {
res.status(400).send('Invalid signature');
return;
}

res.send('OK');
});

app.listen(8080);
from flask import Flask, request, abort
import json, base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

app = Flask(__name__)

@app.route('/notification', methods=['POST'])
def verify_notification():
params = {
'order_id': request.form.get('order_id'),
'uuid': request.form.get('uuid'),
}

data = json.dumps(params).encode('utf-8')
signature = base64.b64decode(request.form.get('sign', ''))

with open('certs/notification/public.pem', 'rb') as f:
public_key = serialization.load_pem_public_key(f.read())

try:
public_key.verify(
signature,
data,
padding.PKCS1v15(),
hashes.SHA256()
)
return 'OK', 200
except Exception:
abort(400, 'Invalid signature')

if __name__ == '__main__':
app.run(port=8080)
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.util.LinkedHashMap;
import javax.servlet.http.*;
import com.fasterxml.jackson.databind.ObjectMapper;

public class NotificationServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
try {
LinkedHashMap<String,String> params = new LinkedHashMap<>();
params.put("order_id", req.getParameter("order_id"));
params.put("uuid", req.getParameter("uuid"));

String data = new ObjectMapper().writeValueAsString(params);
byte[] signature = java.util.Base64.getDecoder().decode(req.getParameter("sign"));

CertificateFactory cf = CertificateFactory.getInstance("X.509");
PublicKey publicKey = cf.generateCertificate(
new FileInputStream("certs/notification/public.pem")
).getPublicKey();

Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(data.getBytes(StandardCharsets.UTF_8));

if (!sig.verify(signature)) {
resp.sendError(400, "Invalid signature");
return;
}

resp.getWriter().write("OK");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
package main

import (
"crypto"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"io/ioutil"
"net/http"
)

func notificationHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
params := map[string]string{
"order_id": r.FormValue("order_id"),
"uuid": r.FormValue("uuid"),
}

data, _ := json.Marshal(params)
sigData, _ := base64.StdEncoding.DecodeString(r.FormValue("sign"))

pemBytes, _ := ioutil.ReadFile("certs/notification/public.pem")
block, _ := pem.Decode(pemBytes)
cert, _ := x509.ParseCertificate(block.Bytes)
pubKey := cert.PublicKey.(*rsa.PublicKey)

hash := sha256.Sum256(data)
if err := rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, hash[:], sigData); err != nil {
http.Error(w, "Invalid signature", http.StatusBadRequest)
return
}

fmt.Fprint(w, "OK")
}

func main() {
http.HandleFunc("/notification", notificationHandler)
http.ListenAndServe(":8080", nil)
}

Parameters

NameDescription
order_idYour id
uuidPayment UUID