全部产品
Search
文档中心

:Tandatangani permintaan yang dikirim ke titik akhir

更新时间:Nov 09, 2025

Artikel ini menjelaskan cara menandatangani permintaan yang dikirim dari Message Service (MNS) ke titik akhir. Anda dapat mengambil sertifikat tanda tangan dari header x-mns-signing-cert-url dalam permintaan yang dikirim ke titik akhir, serta memverifikasi apakah permintaan tersebut berasal dari Simple Message Queue (sebelumnya MNS). Hal ini memungkinkan Anda mencegah dampak dari permintaan jahat.

Dalam permintaan pengiriman pesan dari Simple Message Queue (sebelumnya MNS) ke titik akhir, Simple Message Queue (sebelumnya MNS) menghasilkan tanda tangan di header Authorization dengan menerapkan algoritma RSA-SHA1 pada string-to-sign. Titik akhir dapat menggunakan pasangan AccessKey untuk memverifikasi tanda tangan. Berikut adalah prosedur verifikasi yang harus diikuti.

Langkah 1: Ambil sertifikat X509

Dalam permintaan HTTP yang dikirim dari Simple Message Queue (sebelumnya MNS) ke titik akhir, header x-mns-signing-cert-url menentukan string yang menunjukkan URL sertifikat tanda tangan. Anda harus melakukan dekode Base64 pada string tersebut untuk mendapatkan URL sertifikat tanda tangan dan mengambil pasangan AccessKey dari sertifikat.

Catatan Sertifikat tanda tangan hanya valid jika awalan URL sertifikat tanda tangan adalah https://mnstest.oss-cn-hangzhou.aliyuncs.com/. Jika tidak, sertifikat tersebut tidak valid. Untuk informasi lebih lanjut, lihat Bagaimana cara memeriksa apakah URL sertifikat tanda tangan adalah URL Alibaba Cloud?

Langkah 2: Hitung string-to-sign

VERB + "\n"
+ CONTENT-MD5 + "\n"
+ CONTENT-TYPE + "\n"
+ DATE + "\n"
+ CanonicalizedMNSHeaders
+ CanonicalizedResource 
  • VERB: metode HTTP.
  • CONTENT-MD5: hash MD5 dari badan permintaan.
  • CONTENT-TYPE: tipe konten dari badan permintaan. Nilai parameter ini harus dalam huruf kecil.
  • DATE: waktu ketika permintaan dikirim. Parameter ini tidak boleh disetel ke null. Waktu harus dalam format UTC.
  • CanonicalizedMNSHeaders: header permintaan HTTP yang diawali dengan x-mns-.
  • CanonicalizedResource: URL permintaan. Parameter ini tidak boleh disetel ke null.

Contoh:

POST
ZDgxNjY5ZjFlMDQ5MGM0YWMwMWE5ODlmZDVlYmQxYjI=
text/xml;charset=utf-8
Wed, 25 May 2016 10:46:14 GMT
x-mns-request-id:57458276F0E3D56D7C00****
x-mns-signing-cert-url:aHR0cDovL21uc3Rlc3Qub3NzLWNuLWhhbmd6aG91LmFsaXl1bmNzLmNvbS94NTA5X3B1YmxpY19jZXJ0aWZpY2F0ZS5w****
x-mns-version:2015-06-06
/notifications       

Langkah 3: Dekripsi header Authorization

Setelah melakukan dekode Base64 pada header Authorization, Anda dapat mendekripsi nilai yang telah didekode menggunakan pasangan AccessKey yang diambil di Langkah 1.

Langkah 4: Verifikasi tanda tangan

Bandingkan string-to-sign yang dihasilkan di Langkah 2 dengan string yang didekripsi yang dihasilkan di Langkah 3. Jika kedua string tersebut sama, permintaan dari Simple Message Queue (sebelumnya MNS) diverifikasi.

Penting

Anda harus memperhatikan konvensi penamaan berikut untuk parameter CanonicalizedHeaders (header yang diawali dengan CanonicalizedMNSHeaders):

  • Nama header harus dalam huruf kecil.
  • Header harus diurutkan secara menaik.
  • Jangan tambahkan spasi sebelum atau sesudah titik dua (:) yang memisahkan nama header dan nilai.
  • Setiap header diikuti oleh line feed (\n). Jangan tentukan parameter CanonicalizedMNSHeaders jika tidak ada header yang diawali dengan x-mns-.

Informasi tambahan:

  • String-to-sign harus dalam format UTF-8.
  • Algoritma tanda tangan sha1WithRSAEncryption yang didefinisikan dalam RFC 3447 harus digunakan.
  • Algoritma Base64 harus digunakan untuk mentranskode teks.

Contoh kode dalam Java

public class SignDemo {
    private Boolean authenticate(String method, String uri, Map<String, String> headers) {
        try {
            // Ambil URL sertifikat tanda tangan.
            if (!headers.containsKey("x-mns-signing-cert-url")) {
                System.out.println("Header x-mns-signing-cert-url tidak ditemukan");
                return false;
            }
            String cert = headers.get("x-mns-signing-cert-url");
            if (cert.isEmpty()) {
                System.out.println("x-mns-signing-cert-url kosong");
                return false;
            }
            cert = new String(Base64.decodeBase64(cert));
            System.out.println("x-mns-signing-cert-url:\t" + cert);

            // Gunakan URL untuk mengambil sertifikat dan ambil kunci publik dari sertifikat.
            URL url = new URL(cert);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            DataInputStream in = new DataInputStream(conn.getInputStream());
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Certificate c = cf.generateCertificate(in);
            PublicKey pk = c.getPublicKey();

            // Ambil string-to-sign.
            String str2sign = getSignStr(method, uri, headers);
            System.out.println("String2Sign:\t" + str2sign);

            // Lakukan dekode Base64 pada header Authorization.
            String signature = headers.get("Authorization");
            byte[] decodedSign = Base64.decodeBase64(signature);

            // Verifikasi tanda tangan.
            java.security.Signature signetcheck = java.security.Signature.getInstance("SHA1withRSA");
            signetcheck.initVerify(pk);
            signetcheck.update(str2sign.getBytes());
            Boolean res = signetcheck.verify(decodedSign);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private String getSignStr(String method, String uri, Map<String, String> headers) {
        StringBuilder sb = new StringBuilder();
        sb.append(method);
        sb.append("\n");
        sb.append(safeGetHeader(headers, "Content-md5"));
        sb.append("\n");
        sb.append(safeGetHeader(headers, "Content-Type"));
        sb.append("\n");
        sb.append(safeGetHeader(headers, "Date"));
        sb.append("\n");

        List<String> tmp = new ArrayList<String>();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            if (entry.getKey().startsWith("x-mns-")) {
                tmp.add(entry.getKey() + ":" + entry.getValue());
            }
        }
        Collections.sort(tmp);

        for (String kv : tmp) {
            sb.append(kv);
            sb.append("\n");
        }

        sb.append(uri);
        return sb.toString();
    }

    private String safeGetHeader(Map<String, String> headers, String name) {
        if (headers.containsKey(name)) {
            return headers.get(name);
        } else {
            return "";
        }
    }

    public static void main(String[] args) {
        SignDemo sd = new SignDemo();
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Authorization", "Mko2Azg9fhCw8qR6G7AeAFMyzjO9qn7LDA5/t9E+6X5XURXTqBUuhpK+K55UNhrnlE2UdDkRrwDxsaDP5ajQ****");
        headers.put("Content-md5", "M2ViOTE2ZDEyOTlkODBjMjVkNzM4YjNhNWI3ZWQ1****");
        headers.put("Content-Type", "text/xml;charset=utf-8");
        headers.put("Date", "Tue, 23 Feb 2016 09:41:06 GMT");
        headers.put("x-mns-request-id", "56CC2932F0E3D5BD5306****");
        headers.put("x-mns-signing-cert-url", "aHR0cDovL21uc3Rlc3Qub3NzLWNuLWhhbmd6aG91LmFsaXl1bmNzLmNvbS94NTA5X3B1YmxpY19jZXJ0aWZpY2F0ZS5w****");
        headers.put("x-mns-version", "2015-06-06");
        Boolean res = sd.authenticate("POST", "/notifications", headers);
        System.out.println("Hasil autentikasi:" + res);
    }
}