Dalam permintaan untuk mendorong pesan dari Simple Message Queue (sebelumnya MNS) ke titik akhir, tanda tangan di header Authorization dihasilkan menggunakan algoritma RSA-SHA1 pada string-to-sign. Topik ini menjelaskan cara memverifikasi tanda tangan pada server HTTP menggunakan kunci publik.
Langkah 1: Ambil Sertifikat X509
Dalam permintaan HTTP yang dikirim dari SMQ ke titik akhir, header x-mns-signing-cert-url menentukan string yang menunjukkan URL sertifikat tanda tangan. Anda harus mendekode Base64 pada string tersebut untuk mengambil URL sertifikat tanda tangan dan mendapatkan kunci publik dari sertifikat.
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 kunci publik disediakan oleh Alibaba Cloud?
Langkah 2: Hitung nilai string-to-sign
Buat string-to-sign berdasarkan pseudocode berikut:
StringToSign = HttpMethod + "\n"
+ CONTENT-MD5 + "\n"
+ CONTENT-TYPE + "\n"
+ DATE + "\n"
+ CanonicalizedMNSHeaders
+ CanonicalizedResource;Tabel berikut menjelaskan parameter.
Parameter | Deskripsi |
HttpMethod | Metode HTTP dalam huruf besar, seperti PUT, GET, POST, atau DELETE. |
Content-MD5 | Nilai hash MD5 dari badan permintaan. Jika header Content-MD5 tidak ditentukan, biarkan parameter ini kosong. |
CONTENT-TYPE | Jenis badan permintaan. Jika header Content-Type tidak ditentukan, biarkan parameter ini kosong. |
DATE | Waktu ketika permintaan dikirim.
|
CanonicalizedMNSHeaders | Kombinasi header HTTP yang diawali oleh
|
CanonicalizedResource | Pengenal Sumber Daya Seragam (URI) dari sumber daya yang diminta oleh permintaan HTTP. Anda dapat memperoleh URI dengan menghapus nama domain dan nomor port dari alamat IP server HTTP yang merespons permintaan. Sebagai contoh, jika Anda menggunakan titik akhir Penting Dalam skenario di mana gateway atau gateway transit lainnya dikonfigurasikan di sistem Anda, URI sumber daya yang diminta oleh permintaan HTTP akan berlaku jika berbeda dari URI permintaan API yang diverifikasi oleh SMQ. |
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 didekode menggunakan kunci publik 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 sama, permintaan dari SMQ valid. Jika tidak, tolak permintaan.
Contoh kode Java
import org.apache.commons.codec.binary.Base64;
import java.io.DataInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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);
// Dekode header Authorization dalam Base64.
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);
}
}