腾讯云对象存储回调服务器设置签名认证

回调服务器设置签名认证概述

如果你的回调服务器被人恶意攻击了,例如恶意回调你的应用服务器,导致应用服务器收到一些非法的请求,影响正常逻辑,此时你就需要判断回调请求是否来自腾讯云对象存储。

在腾讯云对象存储回调通知及视频回调中,通知消息通过NS服务发到你的回调服务器。NS支持签名认证,具体方法如下:

验证回调签名

用户可以通过推送请求Header中的x-jdcloud-signing-cert-url获取签名证书,并根据相应的方法来验证该请求是否由NS系统发出,防止恶意请求对用户造成负面影响。

在NS推送请求的Header中,Authorization字段的值是MNS根据待签名字符串,用SHA1-RSA签名算法生成签名。Endpoint可以使用公钥对签名进行验证,具体的验证方法如下:

第一步:获取X509证书

在NS发送给Endpoint的http请求Header中,x-jdcloud-signing-cert-url指定了签名证书的地址(Base64编码),用户需要通过Base64解码,获取该签名文件URL地址,再从中提取出签名的公钥。

第二步:计算待签名字符串VERB+" "+CONTENT-MD5+" "+CONTENT-TYPE+" "+DATE+" "+CanonicalizedNSHeaders+CanonicalizedResource注:

  • VERB表示HTTP的Method
  • CONTENT-MD5表示请求内容数据的MD5值
  • CONTENT-TYPE表示请求内容的类型,对应的值为全小写
  • DATE表示此次操作的时间,不能为空,目前只支持GMT格式
  • CanonicalizedNSHeaders表示http请求Header中的x-jdcloud-开始的字段组合(见下文注意事项)
  • CanonicalizedResource表示http请求的相对地址,不能为空待签名字符串示例(注:不应该出现空的行全小写,Content-Type值为全小写):

POSTZDgxNjY5ZjFlMDQ5MGM0YWMwMWE5ODlmZDVlYmQxYjI=text/xml;charset=utf-8Wed,25May201610:46:14GMTx-jdcloud-request-id:57458276F0E3D56D7C00054Bx-jdcloud-signing-cert-url:aHR0cDovL25zdGVzdC5vc3MuY24tbm9ydGgtMS5qY2xvdWRjcy5jb20veDUwOV9wdWJsaWNfY2VydGlmaWNhdGUucGVtCg==x-jdcloud-version:2015-06-06/notifications
第三步:Authorization解密

对Authorization签名字段进行Base64Decode解码后,使用从第一步从证书中提取的公钥对其进行解密;

第四步:认证

比较第二步生成的待签名字符串与第三步解密的结果是否一致。如果一致,则表明请求来自NS,访问合法。注:

  • CanonicalizedNSHeaders(即x-jdcloud-开头的head)在签名验证前需要符合以下规范:
  • head的名字需要变成小写
  • head自小到大排序
  • 分割headname和value的冒号前后不能有空格
  • 每个Head之后都有一个 ,如果没有以x-jdcloud-开头的head,则在签名时CanonicalizedNSHeaders就设置为空

其他

1.用来签名的字符串为UTF-8格式;

2.签名的方法用RFC3447(http://tools.ietf.org/html/rfc3447)中定义的sha1WithRSAEncryption方法;

3.Base64是指使用base64算法转码文本

Java示例代码publicclassSignDemo{privateBooleanauthenticate(Stringmethod,Stringuri,MapString,Stringheaders){try{//获取证书的URLif(!headers.containsKey("x-jdcloud-signing-cert-url")){System.out.println("x-jdcloud-signing-cert-urlHeadernotfound");returnfalse;}Stringcert=headers.get("x-jdcloud-signing-cert-url");if(cert.isEmpty()){System.out.println("x-jdcloud-signing-cert-urlempty");returnfalse;}cert=newString(Base64.decodeBase64(cert));System.out.println("x-jdcloud-signing-cert-url: "+cert);//根据URL获取证书,并从证书中获取公钥URLurl=newURL(cert);HttpURLConnectionconn=(HttpURLConnection)url.openConnection();DataInputStreamin=newDataInputStream(conn.getInputStream());CertificateFactorycf=CertificateFactory.getInstance("X.509");Certificatec=cf.generateCertificate(in);PublicKeypk=c.getPublicKey();//获取待签名字符串Stringstr2sign=getSignStr(method,uri,headers);System.out.println("String2Sign: "+str2sign);//对Authorization字段做Base64解码Stringsignature=headers.get("Authorization");byte[]decodedSign=Base64.decodeBase64(signature);//认证java.security.Signaturesignetcheck=java.security.Signature.getInstance("SHA1withRSA");signetcheck.initVerify(pk);signetcheck.update(str2sign.getBytes());Booleanres=signetcheck.verify(decodedSign);returnres;}catch(Exceptione){e.printStackTrace();returnfalse;}}privateStringgetSignStr(Stringmethod,Stringuri,MapString,Stringheaders){StringBuildersb=newStringBuilder();sb.append(method);sb.append(" ");sb.append(safeGetHeader(headers,"Content-md5"));sb.append(" ");sb.append(safeGetHeader(headers,"Content-Type"));sb.append(" ");sb.append(safeGetHeader(headers,"Date"));sb.append(" ");ListStringtmp=newArrayListString();for(Map.EntryString,Stringentry:headers.entrySet()){if(entry.getKey().startsWith("x-jdcloud-")){tmp.add(entry.getKey()+":"+entry.getValue());}}Collections.sort(tmp);for(Stringkv:tmp){sb.append(kv);sb.append(" ");}sb.append(uri);returnsb.toString();}privateStringsafeGetHeader(MapString,Stringheaders,Stringname){if(headers.containsKey(name)){returnheaders.get(name);}else{return"";}}publicstaticvoidmain(String[]args){SignDemosd=newSignDemo();MapString,Stringheaders=newHashMapString,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,23Feb201609:41:06GMT");headers.put("x-jdcloud-request-id","56CC2932F0E3D5BD530685CB");headers.put("x-jdcloud-signing-cert-url","aHR0cDovL25zdGVzdC5vc3MuY24tbm9ydGgtMS5qY2xvdWRjcy5jb20veDUwOV9wdWJsaWNfY2VydGlmaWNhdGUucGVtCg==");Booleanres=sd.authenticate("POST","/notifications",headers);System.out.println("Authenticateresult:"+res);}}