294
阿裏雲
Endpoint簽名認證__調用方式_API使用手冊_消息服務-阿裏雲
用戶可以通過推送請求Header中的 x-mns-signing-cert-url 獲取簽名證書,並根據相應的方法來驗證該請求是否由MNS係統發出,防止惡意請求對用戶造成負麵影響。
在 MNS 推送請求的 Header 中,Authorization 字段的值是MNS根據待簽名字符串,用 SHA1-RSA 簽名算法生成簽名。Endpoint 可以使用公鑰對簽名進行驗證,具體的驗證方法如下:
第一步:獲取X509證書
在 MNS 發送給 Endpoint 的 http 請求 Header 中,x-mns-signing-cert-url 指定了簽名證書的地址( Base64 編碼),用戶需要通過 Base64 解碼,獲取該簽名文件 URL 地址,再從中提取出簽名的公鑰。
第二步:計算待簽名字符串
VERB + "n"+ CONTENT-MD5 + "n"+ CONTENT-TYPE + "n"+ DATE + "n"+ CanonicalizedMNSHeaders+ CanonicalizedResource
VERB表示HTTP的MethodCONTENT-MD5表示請求內容數據的MD5值CONTENT-TYPE表示請求內容的類型,對應的值為全小寫DATE表示此次操作的時間,不能為空,目前隻支持GMT格式CanonicalizedMNSHeaders表示 http 請求 Header 中的x-mns-開始的字段組合(見下文注意事項)CanonicalizedResource表示 http 請求的相對地址,不能為空
待簽名字符串示例(注:不應該出現空的行全小寫,Content-Type值為全小寫):
POSTZDgxNjY5ZjFlMDQ5MGM0YWMwMWE5ODlmZDVlYmQxYjI=text/xml;charset=utf-8Wed, 25 May 2016 10:46:14 GMTx-mns-request-id:57458276F0E3D56D7C00054Bx-mns-signing-cert-url:aHR0cDovL21uc3Rlc3Qub3NzLWNuLWhhbmd6aG91LmFsaXl1bmNzLmNvbS94NTA5X3B1YmxpY19jZXJ0aWZpY2F0ZS5wZW0=x-mns-version:2015-06-06/notifications
第三步:Authorization 解密
對Authorization 簽名字段進行 Base64 Decode 解碼後,使用從第一步從證書中提取的公鑰對其進行解密;
第四步:認證
比較第二步生成的待簽名字符串與第三步解密的結果是否一致。如果一致,則表明請求來自MNS,訪問合法。
注意事項
CanonicalizedMNSHeaders(即
x-mns-開頭的head)在簽名驗證前需要符合以下規範:
- head 的名字需要變成小寫
- head 自小到大排序
- 分割 head name 和 value 的冒號前後不能有空格
- 每個Head之後都有一個
n,如果沒有以x-mns-開頭的head,則在簽名時CanonicalizedMNSHeaders就設置為空
其他
- 用來簽名的字符串為 UTF-8 格式;
- 簽名的方法用 RFC 3447 (https://tools.ietf.org/html/rfc3447)中定義的 sha1WithRSAEncryption 方法;
- Base64 是指使用 base64 算法轉碼文本。
Java示例代碼
public class SignDemo {private Boolean authenticate(String method, String uri, Map<String, String> headers) {try {//獲取證書的URLif (!headers.containsKey("x-mns-signing-cert-url")) {System.out.println("x-mns-signing-cert-url Header not found");return false;}String cert = headers.get("x-mns-signing-cert-url");if (cert.isEmpty()) {System.out.println("x-mns-signing-cert-url empty");return false;}cert = new String(Base64.decodeBase64(cert));System.out.println("x-mns-signing-cert-url:t" + cert);//根據URL獲取證書,並從證書中獲取公鑰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();//獲取待簽名字符串String str2sign = getSignStr(method, uri, headers);System.out.println("String2Sign:t" + str2sign);//對Authorization字段做Base64解碼String signature = headers.get("Authorization");byte[] decodedSign = Base64.decodeBase64(signature);//認證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+K55UNhrnlE2UdDkRrwDxsaDP5ajQdg==");headers.put("Content-md5", "M2ViOTE2ZDEyOTlkODBjMjVkNzM4YjNhNWI3ZWQ1M2E=");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", "56CC2932F0E3D5BD530685CB");headers.put("x-mns-signing-cert-url", "aHR0cDovL21uc3Rlc3Qub3NzLWNuLWhhbmd6aG91LmFsaXl1bmNzLmNvbS94NTA5X3B1YmxpY19jZXJ0aWZpY2F0ZS5wZW0=");headers.put("x-mns-version", "2015-06-06");Boolean res = sd.authenticate("POST", "/notifications", headers);System.out.println("Authenticate result:" + res);}}
最後更新:2016-11-23 17:16:04
上一篇:
請求簽名機製__調用方式_API使用手冊_消息服務-阿裏雲
下一篇:
RESTfulAPI概述__隊列接口規範_API使用手冊_消息服務-阿裏雲
CDN監控__雲服務監控_用戶指南_雲監控-阿裏雲
OSS插件最佳功能組合__最佳實踐_Eclipse 插件-阿裏雲
VpcAttributesType__數據類型_API 參考_雲服務器 ECS-阿裏雲
修改RDS實例數據複製和高可用策略__實例管理_API 參考_雲數據庫 RDS 版-阿裏雲
ECS雲服務器帶寬FAQ
圖文識別同步調用接口__OCR圖文識別API_內容檢測API文檔_阿裏綠網-阿裏雲
AnalyticDB數據源配置__數據源配置_數據同步手冊_用戶操作指南_大數據開發套件-阿裏雲
優化建議__最佳實踐_雲數據庫 PetaData-阿裏雲
Topic操作__主題接口規範_API使用手冊_消息服務-阿裏雲
修改、查詢、刪除定時任務__定時任務_用戶指南_彈性伸縮-阿裏雲
相關內容
常見錯誤說明__附錄_大數據計算服務-阿裏雲
發送短信接口__API使用手冊_短信服務-阿裏雲
接口文檔__Android_安全組件教程_移動安全-阿裏雲
運營商錯誤碼(聯通)__常見問題_短信服務-阿裏雲
設置短信模板__使用手冊_短信服務-阿裏雲
OSS 權限問題及排查__常見錯誤及排除_最佳實踐_對象存儲 OSS-阿裏雲
消息通知__操作指南_批量計算-阿裏雲
設備端快速接入(MQTT)__快速開始_阿裏雲物聯網套件-阿裏雲
查詢API調用流量數據__API管理相關接口_API_API 網關-阿裏雲
使用STS訪問__JavaScript-SDK_SDK 參考_對象存儲 OSS-阿裏雲