• 关于

    加密url php

    的搜索结果

问题

关于云存储URL防盗链

单独写了一个类,里面有main方法,生成出了一段带有Expires,OSSAccessKeyId,Signature的加密字符串。看API文档在4.1里面有这样一句话《 然后使用Acc...
change小李 2019-12-01 21:59:49 6638 浏览量 回答数 2

回答

Re存放在oss开放存储服务空间的文件,如何做到每次下载都自动生成加密 bucket设为private,客户端算出加密链接 ------------------------- 回3楼bart的帖子 需要用oss的php sdk,其中有签名url函数,具体请看说明
chuong 2019-12-02 02:25:12 0 浏览量 回答数 0

回答

折腾了很久,最后发现问题还是发生在自己身上,原因是CDN前端取数据的时候未进行加密SSL,导致PHPWIND程序判断我们访问的仍就是HTTP网站,所以他们生成的绝对路径就为HTTP://打头了。 我的解决方法是把绝对路径改为相对路径,以下是方法,但只是解决小绿锁的问题,有些链接没有完全处理,有空再去慢慢研究了。 Phpwind改相对路径的办法 ----对应版本 phpwind v9.0.1 20141223 /wind/utility/WindUrlHelper.php 注释第25行 //$url = trim($_baseUrl, '/') . '/' . trim($url, '/'); /src/library/engine/extension/viewer/PwTemplateCompilerUrlCreater.php 注释第105行 //$content = 'Wind::getComponent('response')->getData('G', 'url', 'base'),'/',' . $content; /wind/web/WindUrlHelper.php 注释第26行 //$url = trim($_baseUrl, '/') . '/' . trim($url, '/'); /src/library/Pw.php 第295行,删除 "PUBLIC_URL . "
1470848801047907 2020-01-08 08:45:55 0 浏览量 回答数 0

回答

遇到了楼主同样的问题,折腾了很久,最后发现问题还是发生在自己身上,原因是CDN前端取数据的时候未进行加密SSL,导致PHPWIND程序判断我们访问的仍就是HTTP网站,所以他们生成的绝对路径就为HTTP://打头了。 我的解决方法是把绝对路径改为相对路径,以下是方法,但只是解决小绿锁的问题,有些链接没有完全处理,有空再去慢慢研究了。 Phpwind改相对路径的办法 ----对应版本 phpwind v9.0.1 20141223 /wind/utility/WindUrlHelper.php 注释第25行 //$url = trim($_baseUrl, '/') . '/' . trim($url, '/'); /src/library/engine/extension/viewer/PwTemplateCompilerUrlCreater.php 注释第105行 //$content = 'Wind::getComponent('response')->getData('G', 'url', 'base'),'/',' . $content; /wind/web/WindUrlHelper.php 注释第26行 //$url = trim($_baseUrl, '/') . '/' . trim($url, '/'); /src/library/Pw.php 第295行,删除 "PUBLIC_URL . "
木吉 2020-01-09 21:03:00 0 浏览量 回答数 0

回答

Re关于免登授权码 引用楼主9tuo于2015-10-19 13:32发表的 关于免登授权码 : 我想问一下,后台服务端能不能直接获取免登授权码?我想在通过免登授权码做一个验证,确保用户是通过钉钉访问后台服务端,而不是通过浏览器直接访问。 [url=http://bbs.aliyun.com/job.php?action=topost&tid=260436&pid=tpc][/url] 同问 以http://开头,用于接收托管企业应用的用户消息,URL支持使用$CORPID$模板参数表示corpid,用户访问应用的时候将把$CORPID$替换成用户所属企业的corpid,例如http://www.dingtalk.com/index?corpid=$CORPID$ 希望后台地址能和前台地址一样可以带这个传或者加密后带corpid传
雨中枫叶 2019-12-01 23:37:50 0 浏览量 回答数 0

回答

Re如何实现在PC端直接用浏览器打开应用,类似微报销 你好,给你提供个思路,步骤如下: 做一个中转页,此页面在钉钉内部容器打开,该页面利用钉钉免登获取钉钉用户信息,并且完成jsapi权限验证,免登流程参照官方文档:h ttps://open-doc.dingtalk.com/docs/doc.htm?treeId=172&articleId=104969&docType=1步骤1中的中转页面和我们需要在外部浏览器打开的子应用约定好签名协议,在中转页调用打开外部浏览器URL的jsapi,将当前钉钉用户信息加密签名拼接到子应用跳转URL中,并且通过外部 浏览器打开此签名跳转URL。打开外部浏览器URL请参照官方文档:h ttps://open-doc.dingtalk.com/docs/doc.htm?treeId=176&articleId=104953&docType=1#s9子应用在外部浏览器打开,根据URL签名参数解析,得到当前钉钉用户信息,完成快捷登录。 如果还有不明之处,可以参考我发帖的SDK ,不过是php版的哦,原理都是一样的的
阅新悦心 2019-12-02 02:22:14 0 浏览量 回答数 0

问题

php模拟登录目标网站,为何302没有跟随跳转.cookie已经获得.?

<?php error_reporting(0); $user = 'cckk263'; //邮箱密码 $pass = '54131421'; //登陆 $url = 'https://www.mql5.com...
小旋风柴进 2019-12-01 20:09:50 1180 浏览量 回答数 1

问题

【71009,倒底要返回什么东西?】ISV接入验证URL有效性返回字符串不匹配。

用的nodejs,能解密能加密。并且用php的demo测试了encrypt,和nodejs结果一样。 按文档档返回JSON。msg_signature,encrypt,timeSt...
天下之中人 2019-12-01 21:00:09 3287 浏览量 回答数 1

回答

项目一直使用http未加密的域名,考虑安全性,购买了ca安全证书实现https化,但由于有些场景访问过来还是http,因为需要把http访问用户直接转为https 准备工作: 下载安装iis组件,url重写,下载地址:https://www.iis.net/downloads/microsoft/url-rewrite 按需下载,我这里下载中文64位版本 1、安装后,选中某个站点,IIS可视化管理界面上会多一个URL重写模块 开始工作: 1、购买SSL证书,打开阿里云,选择产品——ssl证书 2、选择 免费型DV SSL  IIS7 / IIS 7.5 下绑定 HTTPS 网站(购买Wildcard SSL泛域名证书可绑定多个子域名)参考上文购买成功后,进入证书控制台: 占申请: 填写证书的网址: 点验证: 提交审核: 成功后可以看到这个: 点下载: 下载成功后,可看到两个文件: IIS服务器SSL证书安装 • IIS7/IIS8在证书控制台下载IIS版本证书,下载到本地的是一个压缩文件,解压后里面包含.pfx文件是证书文件,pfx_password.txt是证书文件的密码。友情提示: 每次下载都会产生新密码,该密码仅匹配本次下载的证书。如果需要更新证书文件,同时也要更新密码。申请证书时如果没有选择系统创建CSR,则没有该文件,请选择其它服务器下载.crt文件,利用openssl命令自己生成pfx证书。也可右点击安装,默认目录: 输入密码后,会显示导入成功。下面进行iis绑定安装: 进入网站,选择类型https绑定刚才的证书: 3、先进入服务器看看有没有这个,有的话就不用下载(目录server2012以上都自带) 下载安装URL重写模块:Microsoft URL Rewrite Module32位:http://download.microsoft.com/download/4/9/C/49CD28DB-4AA6-4A51-9437-AA001221F606/rewrite_x86_zh-CN.msi64位:http://download.microsoft.com/download/4/E/7/4E7ECE9A-DF55-4F90-A354-B497072BDE0A/rewrite_x64_zh-CN.msi4、取消勾选“SSL设置”-》“要求 SSL” 5、ASP.NET站可直接修改web.config(与“6、IIS配置图示”效果相同),例如:见...节点 <?xml version="1.0" encoding="utf-8"?> <rewrite> <rules> <rule name="HTTP to HTTPS redirect" stopProcessing="true"> <match url="(.*)" /> <conditions> <add input="{HTTPS}" pattern="off" ignoreCase="true" /> </conditions> <action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" /> </rule> </rules> </rewrite> 6、IIS配置图示(图形化的操作过程,与上步效果相同,适用于asp/php等站)选择要配置的网站,找到“URL重写”,没有的话看上面第3步 双击网站,选择功能,找到url重写如果没有url重写,就要下载,看上面: 进入“URL重写”模块,点击“添加规则” 选择“空白规则” 编辑规则,名称:自己定义模式:(.*)条件:{HTTPS}条件模式: off 或 ^OFF$ 或 重定向URL:https://{HTTP_HOST}/{R:1}重定向类型:已找到(302) 或 参阅其它(303) 配置完成后“应用”到当前站点: URL重写配置结果: 至此配置完成! 需要技术支持联系QQ:1208877577  技术支持,100元每次。。。
kmptygya 2019-12-01 23:34:40 0 浏览量 回答数 0

问题

php应用oss签名url防盗链功能教程官方原文件

先声明一下,我不懂php语言,所以有什么问题不要来问我!贴子说错了也不要骂~分享是一种精神,论坛里有一份php签名防盗链的,但是不知怎么回事用不了,所以昨天...
ainpz 2019-12-01 21:17:40 9544 浏览量 回答数 4

问题

回调注册,一直返回文本非success

本地通过调用官方php demo实现加密,注册回调接口时,收到钉钉数据: "POST /callback?signature=fd4056afc884d860a0d4c13f7aa...
凯~ 2019-12-01 21:42:40 2147 浏览量 回答数 2

问题

API 签名机制是怎样的?

阿里云产品服务会对每个访问请求进行身份验证,所以无论您使用 HTTP 还是 HTTPS 协议提交请求,都需要在请求中包含签名(Signature)信息。 签名需要您在控制台 Acce...
轩墨 2019-12-01 22:05:38 1629 浏览量 回答数 0

问题

钉钉套件创建后Ticket推送失败!

使用了官方的PHP例子,使用云引擎ACE的空间。 在开发平台创建了钉钉套件后,使用生成的套件Key、套件secret和数据加密密钥重新配置了env.php文件 更新云引擎后,出现了: ...
北辰软件 2019-12-01 21:05:02 5563 浏览量 回答数 5

问题

请教ONS(PHP)的问题。。。

代码: //签名加密 public function calSignatue($str,$key) { $sign = ""; if(function_exists("hash_hmac")) { $...
mybizsite 2019-12-01 19:35:12 1156 浏览量 回答数 1

回答

Re斑主,阿里云服务器被黑,服务起不来,怎么备份数据? 参照之前的经验,可能是图片或论坛的上传插件有漏洞,导致上传了很多留言,像这种也需要重装吗? ------------------------- Re斑主,阿里云服务器被黑,服务起不来,怎么备份数据? 引用第2楼紫龙001于2016-07-17 10:06发表的  : 有做快照策略吗,有的话恢复快照就好了。 [url=https://bbs.aliyun.com/job.php?action=topost&tid=288896&pid=805188][/url] 谢谢斑主回复,阿里没具体说是哪个网站有问题,只是说服务器有木马,建议重装。 现在服务器远程及ftp都连不上,那可以让阿里云的工作人员帮我们备份好程序,再发给我们吗? ------------------------- ReRe斑主,阿里云服务器被黑,服务起不来,怎么备份数据? 引用第1楼kevingroup于2016-07-17 09:46发表的 Re斑主,阿里云服务器被黑,服务起不来,怎么备份数据? : 参照之前的经验,可能是图片或论坛的上传插件有漏洞,导致上传了很多留言,像这种也需要重装吗? [url=https://bbs.aliyun.com/job.php?action=topost&tid=288896&pid=805181][/url] 没有作快照,现在服务器还没有重装,只是远程和ftp连不上,数据还在服务器上。 不知道可不可以让阿里云的工作人员备份好再发给我们吗? ------------------------- Re斑主,阿里云服务器被黑,服务起不来,怎么备份数据? 引用第7楼紫龙001于2016-07-18 00:36发表的  : 试一下管理终端功能,用它应该可以连上服务器的。 [url=https://bbs.aliyun.com/job.php?action=topost&tid=288896&pid=805306][/url] 谢谢,我试试,看这样能不能解决问题 ------------------------- Re斑主,阿里云服务器被黑,服务起不来,怎么备份数据? 引用第7楼紫龙001于2016-07-18 00:36发表的  : 试一下管理终端功能,用它应该可以连上服务器的。 [url=https://bbs.aliyun.com/job.php?action=topost&tid=288896&pid=805306][/url] 好的,谢谢,我试试,看能不能解决问题。 ------------------------- Re斑主,阿里云服务器被黑,服务起不来,怎么备份数据? 引用第2楼紫龙001于2016-07-17 10:06发表的  : 有做快照策略吗,有的话恢复快照就好了。 [url=https://bbs.aliyun.com/job.php?action=topost&tid=288896&pid=805188][/url] 服务器操作系统恢复 了 但是硬盘上的文件,都变成xtbl格式了 被病毒感染 包括图片、asp脚本、数据库文件,全部被感染了 斑竹,有方法恢复吗? [attachment=106248] ------------------------- ReRe斑主,阿里云服务器被黑,服务起不来,怎么备份数据? 引用第11楼kevingroup于2016-07-18 13:37发表的 Re斑主,阿里云服务器被黑,服务起不来,怎么备份数据? : 服务器操作系统恢复 了 但是硬盘上的文件,都变成xtbl格式了 ....... [url=https://bbs.aliyun.com/job.php?action=topost&tid=288896&pid=805408][/url] 确实,常备份很重要。 郁闷啊,有10多个企业站,都没备份。。。。 ------------------------- Re斑主,阿里云服务器被黑全变成XTBL文件,服务起不来,怎么备份数据? 引用第12楼huweishen于2016-07-18 16:05发表的  : 楼主这个问题: 如果你没有旧的备份数据,根本上是没救了 这类的情况是中了叫“敲诈者病毒” 只有登录病毒那边按他们要求付款解密后,这些被加密的数据才能恢复正常 否则只有自认倒霉了 ....... [url=https://bbs.aliyun.com/job.php?action=topost&tid=288896&pid=805463][/url] 好的,谢谢斑主
kevingroup 2019-12-02 02:50:13 0 浏览量 回答数 0

问题

API 签名机制(签名操作)

阿里云产品服务会对每个访问请求进行身份验证,所以无论您使用 HTTP 还是 HTTPS 协议提交请求,都需要在请求中包含签名(Signature)信息。 签名需要您在控制台 Acce...
云栖大讲堂 2019-12-01 21:47:47 1666 浏览量 回答数 0

问题

关于触发异步处理{"error":"bad token"}的问题

//代码是这样的,我要异步处理图片持久化 function makeUrl($url,$bucket,$savekey,$ak="KUN6xYZlOAtid2MjHm90-6VFY2M7HC90ijDH4uOR",$sk="D-K57TE5...
落地花开啦 2019-12-01 20:02:18 1515 浏览量 回答数 1

回答

为保证API的安全调用,在调用API时,阿里云ENS会对每个API请求通过签名(Signature)进行身份验证。无论您使用HTTP还是HTTPS协议提交请求,都需要在请求中包含签名信息。 说明 阿里云ENS提供了多种编程语言的SDK及第三方SDK,可以省略计算签名步骤,SDK下载请单击阿里云SDK中心。 RAM授权 为了确保您的账号安全,建议您使用子账号的身份凭证调用API。如果您使用RAM账号调用API,您需要为该RAM账号创建、附加相应的授权策略。ENS中可授权的资源和接口列表,请参见RAM资源授权,获取AccessKey请参见获取AccessKey。 API签名 ENS服务会对每个API请求进行身份验证,无论您使用HTTP还是HTTPS协议提交请求,都需要在请求中包含签名(Signature)信息。具体签名计算方法,请参见签名机制。 ENS通过使用AccessKey ID和AccessKey Secret进行对称加密的方法来验证请求的发送者身份。AccessKey是为阿里云账号和RAM用户发布的一种身份凭证(类似于用户的登录密码),其中AccessKey ID用于标识访问者的身份,AccessKey Secret是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密。 以StartInstanceAPI为例,假设使用的AccessKeyId为testid, AccessKeySecret为testsecret。 签名前的请求URL如下: https://ens.aliyuncs.com/?Action=StartInstance &InstanceId=testId &Format=xml &AccessKeyId=testid &SignatureMethod=HMAC-SHA1 &SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf &Version=2017-11-10 &SignatureVersion=1.0 使用testsecret&,计算得到的签名值是: Y8c1u47r2gHn6scXqz92wklKws1= 将签名作为Signature参数加入到URL请求中,最后得到的URL为: https://ens.aliyuncs.com/?Action=StartInstance &InstanceId=testId &Format=xml &AccessKeyId=testid &SignatureMethod=HMAC-SHA1 &SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf &Version=2017-11-10 &SignatureVersion=1.0&Signature=Y8c1u47r2gHn6scXqz92wklKws1= 阿里云为您提供了多种编程语言SDK签名示例代码。 PHP 签名示例 Python签名示例 .NET 签名示例 Go 签名示例 Node.js 签名示例 C/C++ 签名示例
保持可爱mmm 2020-03-29 16:29:06 0 浏览量 回答数 0

回答

Access Key ID & Access Key Secret (API密钥) 用户注册OSS时,系统会给用户分配一对Access Key ID & Access Key Secret,称为ID对,用于标识用户,为访问OSS做签名验证。 现在Content-MD5这个字段和签名那里的算法一样 ,以官方oss开发文档参考准 由于OSS有着非常优秀的网络带宽质量,很多朋友希望基于OSS开发图片、音乐、视频等网站和应用。但如何有效地防盗链是个让人头疼的问题。这里介绍一个简单且安全的方法:通过签名URL防盗链。 首先,确认自己的bucket权限是private,即这个bucket的所有请求必须在签名认证通过后才被认为是合法的。然后根据操作类型、要访问的bucket、要访问的object以及超时时间,动态地生成一个经过签名的URL。通过这个签名URL,你授权的用户就可以在该签名URL过期时间前执行相应的操作。 签名的python代码如下:    url = my_store.sign_url (method, bucket_name, object_name,timeout = 60) 其中method可以是PUT,GET,HEAD,DELETE中的任意一种;最后一个参数“timeout”是超时的时间,单位是秒。一个通过上面python方法,计算得到的签名URL为:    http://storage.aliyun.com/sharedata/lingyun.jpg?OSSAccessKeyId=y6h7nbcothehvcp7jlnwmrw9&Expires=1335084740&Signature=LZeqnHSo5WkDNWKffKDgQBXR6fY= 通过这种动态计算签名URL的方法,可以有效地保护放在OSS上的数据,防止被其他人盗链。   技术来源: http://dev.aliyun.com/read.php?tid=16 ------------------------- 经过测试和交谈得到的最新答案head中的签名是CONTENT-MD5表示请求内容数据的MD5值 Delete Multiple Objects MD5字段内容方法:首先将Delete Multiple Object请求内容经过MD5加密后得到一个128位字节数组;再将该字节数组用base64算法编码;最后得到的字符串即是Content-MD5字段内容。 这里是先请求到xml文件的md5值,在经过base54位算法得到字段内容。 示例:python代码信息: def batch_delete_object(self, bucket, object_list_xml, headers=None, params=None): ''' Delete the objects in object_list_xml :type bucket: string :param: :type object_list_xml: string :param: :type headers: dict :param: HTTP header :type params: dict :param: the parameters that put in the url address as query string Returns: HTTP Response ''' if not headers: headers = {} if not params: params = {} method = 'POST' object = '' body = object_list_xml headers['Content-Length'] = str(len(body)) params['delete'] = '' base64md5 = base64.encodestring(md5.new(body).digest())if base64md5[-1] == '\n': base64md5 = base64md5[0:-1] headers['Content-MD5'] = base64md5 return self.http_request(method, bucket, object, headers, body, params) 相关信息请您参考api和sdk文件。 谢谢。 ------------------------- 回 10楼(一折) 的帖子 实在不懂  请发工单至阿里云。谢谢
梦幻星辰 2019-12-02 01:54:02 0 浏览量 回答数 0

回答

为保证API的安全调用,在调用API时,阿里云RTC会对每个API请求通过签名(Signature)进行身份验证。无论您使用HTTP还是HTTPS协议提交请求,都需要在请求中包含签名信息。 说明 阿里云RTC提供了多种编程语言的SDK及第三方SDK,可以省略计算签名步骤,SDK下载请单击阿里云SDK中心。 RAM授权 为了确保您的账号安全,建议您使用子账号的身份凭证调用API。如果您使用RAM账号调用API,您需要为该RAM账号创建、附加相应的授权策略。RTC中可授权的资源和接口列表,请参见RAM资源授权,获取AccessKey请参见获取AccessKey。 API签名 RTC服务会对每个API请求进行身份验证,无论您使用HTTP还是HTTPS协议提交请求,都需要在请求中包含签名(Signature)信息。 RTC通过使用AccessKey ID和AccessKey Secret进行对称加密的方法来验证请求的发送者身份。AccessKey是为阿里云账号和RAM用户发布的一种身份凭证(类似于用户的登录密码),其中AccessKey ID用于标识访问者的身份,AccessKey Secret是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密。 以CreateChannelAPI为例,假设使用的AccessKeyId为testid, AccessKeySecret为testsecret。 签名前的请求URL如下: https://rtc.aliyuncs.com/?Action=CreateChannel &AppId=a2h1**** &ChannelId=juz**** &Format=XML &AccessKeyId=testid &SignatureMethod=HMAC-SHA1 &SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf &Version=2018-01-11 &SignatureVersion=1.0 使用testsecret&,计算得到的签名值是: Y8c1u47r2gHn6scXqz92wklKws1= 将签名作为Signature参数加入到URL请求中,最后得到的URL为: https://rtc.aliyuncs.com/?Action=CreateChannel &AppId=a2h1**** &ChannelId=juz**** &Format=XML &AccessKeyId=testid &SignatureMethod=HMAC-SHA1 &SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf &Version=2018-01-11 &SignatureVersion=1.0 &Signature=Y8c1u47r2gHn6scXqz92wklKws1= 阿里云为您提供了多种编程语言SDK签名示例代码。 PHP 签名示例 Python签名示例 .NET 签名示例 Go 签名示例 Node.js 签名示例 C/C++ 签名示例
保持可爱mmm 2020-03-29 17:11:10 0 浏览量 回答数 0

问题

PHP中CURL POST数据的相关问题

今天用到CURL这个函数库,在进行POST数据传输时,出现了个很有趣的问题 $Postval = array('key'=&gt;$keycode,'action'=&gt;'dns_edit');//$keycode 是通过uc_auth...
吴孟桥 2019-12-01 19:48:12 903 浏览量 回答数 1

问题

php调用新版百度翻译api的问题? 400 报错

php调用新版百度翻译api的问题? 400 报错 百度给的官方demo中, function callOnce($url, $args=null, $method="post", $w...
爱吃鱼的程序员 2020-06-04 14:30:10 1 浏览量 回答数 1

回答

详细解答可以参考官方帮助文档报错情况比较复杂,此处列出比较常见的几种报错内容: 403 报错:403 报错是一个大类,403 的报错基本上是权限问题,出现 403 报错时您需要检测权限配置问题。 403.1 错误是由于“执行”访问被禁止而造成的。若试图从目录中执行 CGI、ISAPI 或其他可执行程序,但该目录不允许执行程序时便会出现此种错误。403.2 错误是由于”读取”访问被禁止而造成的。导致此错误是由于没有可用的默认网页并且没有对目录启用目录浏览,或者要显示的 HTML 网页所驻留的目录仅标记为“可执行”或“脚本”权限。403.3 错误是由于“写入”访问被禁止而造成的。当试图将文件上载到目录或在目录中修改文件,但该目录不允许“写”访问时就会出现此种错误。403.4 错误是由于要求 SSL 而造成的。您必须在要查看的网页的地址中使用 HTTPS。403.5 错误是由于要求使用 128 位加密算法的 Web 浏览器而造成的。如果您的浏览器不支持 128 位加密算法就会出现这个错误,您可以连接微软网站进行浏览器升级。403.6 错误是由于 IP 地址被拒绝而造成的。如果服务器中有不能访问该站点的IP地址列表,并且您使用的 IP 地址在该列表中时您就会返回这条错误信息。403.7 错误是因为要求客户证书。当需要访问的资源要求浏览器拥有服务器能够识别的安全套接字层(SSL)客户证书时会返回此种错误。403.8 错误是由于禁止站点访问而造成的。若服务器中有不能访问该站点的 DNS 名称列表,而您使用的 DNS 名称在列表中时就会返回此种信息。请注意区别 403.6 与 403.8 错误。403.9 错误是由于连接的用户过多而造成的,由于 Web 服务器很忙,因通讯量过多而无法处理请求时便会返回这条错误。403.10 错误是由于无效配置而导致的错误。当您试图从目录中执行 CGI、ISAPI 或其他可执行程序,但该目录不允许执行程序时便会返回这条错误。403.11 错误是由于密码更改而导致无权查看页面。403.12 错误是由于映射器拒绝访问而造成的。若要查看的网页要求使用有效的客户证书,而您的客户证书映射没有权限访问该 Web 站点时就会返回映射器拒绝访问的错误。403.13 错误是由于需要查看的网页要求使用有效的客户证书而使用的客户证书已经被吊销,或者无法确定证书是否已吊销造成的。403.14 错误 Web 服务器被配置为不列出此目录的内容,拒绝目录列表。403.15 错误是由于客户访问许可过多而造成的。当服务器超出其客户访问许可限制时会返回此条错误。403.16 错误是由于客户证书不可信或者无效而造成的。403.17 错误是由于客户证书已经到期或者尚未生效而造成的。 404 报错:404 报错主要是页面显示问题或者页面的链接有问题,意味着链接指向的网页不存在,即原始网页的 URL 失效。当 Web 服务器接到类似请求时,会返回一个 404 状态码,告诉浏览器已请求的资源并不存在。导致这个错误的原因一般有以下几种情况: 无法在所请求的端口上访问 Web 站点。Web 服务扩展锁定策略阻止本请求。MIME 映射策略阻止本请求。网站更新改版,但某些局部板块沿用原来的模块,而原有的模块调用的文件已经被删除或转移了路径。跟踪访问的各类脚码或 CSS 文件无效但调用代码依然存在。某个目录直接删除(导致一段时间该目录的文件在被爬行时全部报 404 Not Found 错误)网页 URL 生成规则改变、网页文件更名或移动位置、导入链接拼写错误等,导致原来的 URL 地址无法访问 502 报错:当测试访问报错为 502 Bad Gateway,这是 Web 程序配置异常导致的。建议结合 Web 访问日志,检测一下 Web 程序配置的参数设置是否有异常。详情请参见 502 bad gateway问题的解决方法。503 报错:503 报错是一种 HTTP 状态码,与 404 同属一种网页状态出错码。两者的区别是:前者是服务器出错的一种返回状态,后者是网页程序没有相关结果后返回的一种状态。503 报错产生的原因有可能是以下几种情况: 网络管理员可能关闭应用程序池以执行维护。当请求到达时应用程序池队列已满。应用程序池标识没有使用预定义账户:网络服务。而自己配置了标识,但是配置的这个用户不属于 IIS_WPG 组。应用程序池启用了 CPU 监视,并且设置了 CPU 利用率超过一定百分比关闭应用程序池,而开发人员写的服务端页面 (.asp、.aspx) 执行效率不高,会引起 CPU 的长时间占用,最终达到设置的百分比,从而引起应用程序池关闭。应用程序池的性能选项卡的请求队列限制所填的数值太小,默认为 1000。某个目录直接删除(导致一段时间该目录的文件在被爬行时全部报 404 Not Found 错误)。网页 URL 生成规则改变、网页文件更名或移动位置、导入链接拼写错误等,导致原来的 URL 地址无法访问。该站点正在被攻击。对于最新型的攻击,其实是 DDoS 的一种派生,原理在于找数千个IP,同时向服务器的 Apache 发出请求,然后 立即断开,让 Apache 处于等待状态,致使 Apache 线程全部被填满,致使服务器死机。因此,为了保证大多数客户的利益,我们给每个空间,作出了每 19 秒 64 个 php 请求的限制。注意,是 php 请求,一般的图片请求和 html 请求不包括在内。该程序占用的 php 线程过多,有的程序没有进行好优化处理,一个点击即可产生数个,甚至数十个 php 线程。这样的话,几个点击就可以把该时段的64个 php 线程全部填满了。因此出现 503 错误。建议优化一下程序,尽量少用 require (请求)等语句。 如问题还未解决,请您记录排查结果、相关日志信息或截图,提交工单联系阿里云。
2019-12-01 23:11:56 0 浏览量 回答数 0

问题

web应用安全防护经验小结

    很多时候服务器的脆弱不是因为服务器安全防护做到不够好,而是因为部署在服务器上的各种应用存在一定漏洞,比如最初的asp动态网页,发展之初非常流行非常广泛,可如今很少再听到用asp...
千鸟 2019-12-01 21:46:11 10119 浏览量 回答数 10

回答

详细解答可以参考官方帮助文档 用户只需要在发送给OSS的请求中携带相应的Callback参数,即能实现回调。 现在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。 构造CallBack参数 CallBack参数是由一段经过base64编码的Json字串,用户关键需要指定请求回调的服务器URL(callbackUrl)以及回调的内容(callbackBody)。详细的Json字段如下: 字段 含义 选项 callbackUrl 文件上传成功后OSS向此url发送回调请求,请求方法为POST,body为callbackBody指定的内容。正常情况下,该url需要响应“HTTP/1.1 200 OK”,body必须为JSON格式,响应头Content-Length必须为合法的值,且不超过3MB。 支持同时配置最多5个url,以”;”分割。OSS会依次发送请求直到第一个返回成功为止。 如果没有配置或者值为空则认为没有配置callback。 支持HTTPS地址。 为了保证正确处理中文等情况,callbackUrl需做url编码处理,比如http://example.com/中文.php?key=value&中文名称=中文值 需要编码成 http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC 必选项 callbackHost 发起回调请求时Host头的值,只有在设置了callbackUrl时才有效。 如果没有配置 callbckHost,则会解析callbackUrl中的url并将解析出的host填充到callbackHost中 可选项 callbackBody 发起回调时请求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 支持OSS系统变量、自定义变量和常量,支持的系统变量如下表所示 。自定义变量的支持方式在PutObject和CompleteMultipart中是通过callback-var来传递,在PostObject中则是将各个变量通过表单域来传递。 必选项 callbackBodyType 发起回调请求的Content-Type,支持application/x-www-form-urlencoded和application/json,默认为前者。 如果为application/x-www-form-urlencoded,则callbackBody中的变量将会被经过url编码的值替换掉,如果为application/json,则会按照json格式替换其中的变量。 可选项 示例json串如下 { "callbackUrl":"121.101.166.30/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" } { "callbackUrl":"121.43.113.8:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" } 其中callbackBody中可以设置的系统变量有,其中imageInfo针对于图片格式,如果为非图片格式都为空: 系统变量 含义 bucket bucket object object etag 文件的etag,即返回给用户的etag字段 size object大小,CompleteMultipartUpload时为整个object的大小 mimeType 资源类型,如jpeg图片的资源类型为image/jpeg imageInfo.height 图片高度 imageInfo.width 图片宽度 imageInfo.format 图片格式,如jpg、png等 自定义参数 用户可以通过callback-var参数来配置自定义参数。 自定义参数是一个Key-Value的Map,用户可以配置自己需要的参数到这个Map。在OSS发起POST回调请求的时候,会将这些参数和上一节所述的系统参数一起放在POST请求的body中以方便接收回调方获取。 构造自定义参数的方法和callback参数的方法是一样的,也是以json格式来传递。该json字符串就是一个包含所有自定义参数的Key-Value的Map。 说明 用户自定义参数的Key一定要以x:开头,且必须为小写。否则OSS会返回错误。 假定用户需要设定两个自定义的参数分别为x:var1和x:var2,对应的值分别为value1和value2,那么构造出来的json格式如下: { "x:var1":"value1", "x:var2":"value2" } 构造回调请求 构造完成上述的callback和callback-var两个参数之后,一共有三种方式传给OSS。其中callback为必填参数,callback-var为可选参数,如果没有自定义参数的话可以不用添加callback-var字段。这三种方式如下: 在URL中携带参数。 在Header中携带参数。 在POST请求的body中使用表单域来携带参数。 说明 在使用POST请求上传Object的时候只能使用这种方式来指定回调参数。 这三种方式只能同时使用其中一种,否则OSS会返回InvalidArgument错误。 要将参数附加到OSS的请求中,首先要将上文构造的json字符串使用base64编码,然后按照如下的方法附加到OSS的请求中: 如果在URL中携带参数。把callback=[CallBack]或者callback-var=[CallBackVar]作为一个url参数带入请求发送。计算签名CanonicalizedResource时 ,将callback或者callback-var当做一个sub-resource计算在内 如果在Header中携带参数。把x-oss-callback=[CallBack]或者x-oss-callback-var=[CallBackVar]作为一个head带入请求发送。在计算签名CanonicalizedOSSHeaders时,将x-oss-callback-var和x-oss-callback计算在内。如下示例:PUT /test.txt HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-ncoding: identity Content-Length: 5 x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0= Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: text/plain Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4= Test 如果需要在POST上传Object的时候附带回调参数会稍微复杂一点,callback参数要使用独立的表单域来附加,如下面的示例:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==如果拥有自定义参数的话,不能直接将callback-var参数直接附加到表单域中,每个自定义的参数都需要使用独立的表单域来附加,举个例子,如果用户的自定义参数的json为{ "x:var1":"value1", "x:var2":"value2" }那么POST请求的表单域应该如下:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ== --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2同时可以在policy中添加callback条件(如果不添加callback,则不对该参数做上传验证)如:{ "expiration": "2014-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="}, ["starts-with", "$key", "user/eric/"], ] } 发起回调请求 如果文件上传成功,OSS会根据用户的请求中的callback参数和自定义参数(callback-var参数),将特定内容以POST方式发送给应用服务器。 POST /index.html HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 181 Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test 返回回调结果 比如应用服务器端返回的回应请求为: HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"a":"b"} 返回上传结果 再给客户端的内容为: HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"a":"b"} 需要注意的是,如果类似CompleteMultipartUpload这样的请求,在返回请求本身body中存在内容(如XMl格式的信息),使用上传回调功能后会覆盖原有的body的内容如{"a":"b"},希望对此处做好判断处理。 回调签名 用户设置callback参数后,OSS将按照用户设置的callbackUrl发送POST回调请求给用户的应用服务器。应用服务器收到回调请求之后,如果希望验证回调请求确实是由OSS发起的话,那么可以通过在回调中带上签名来验证OSS的身份。 生成签名 签名在OSS端发生,采用RSA非对称方式签名,私钥加密的过程为:authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘\n’ + body, md5)) 说明 其中private_key为私钥,只有oss知晓,path为回调请求的资源路径,query_string为查询字符串,body为回调的消息体,所以签名过程由以下几步组成: 获取待签名字符串:资源路径经过url解码后,加上原始的查询字符串,加上一个回车符,加上回调消息体 RSA签名:使用秘钥对待签名字符串进行签名,签名的hash函数为md5 将签名后的结果做base64编码,得到最终的签名,签名放在回调请求的authorization头中 如下例:POST /index.php?id=1&index=2 HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ== bucket=yonghu-testpath为/index.php,query_string为?id=1&index=2,body为bucket=yonghu-test,最终签名结果为kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== 验证签名 验证签名的过程即为签名的逆过程,由应用服务器验证,过程如下:Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘\n’ + body), base64_decode(authorization))字段的含义与签名过程中描述相同,其中public_key为公钥, authorization为回调头中的签名,整个验证签名的过程分为以下几步: 回调请求的x-oss-pub-key-url头保存的是公钥的url地址的base64编码,因此需要对其做base64解码后获取到公钥,即public_key = urlopen(base64_decode(x-oss-pub-key-url头的值))这里需要注意,用户需要校验x-oss-pub-key-url头的值必须以http://gosspublic.alicdn.com/或者https://gosspublic.alicdn.com/开头,目的是为了保证这个publickey是由OSS颁发的。 获取base64解码后的签名signature = base64_decode(authorization头的值) 获取待签名字符串,方法与签名一致sign_str = url_decode(path) + query_string + ‘\n’ + body 验证签名result = rsa_verify(public_key, md5(sign_str), signature) 以上例为例: 获取到公钥的url地址,即aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==经过base64解码后得到http://gosspublic.alicdn.com/callback_pub_key_v1.pem 签名头kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==做base64解码(由于为非打印字符,无法显示出解码后的结果) 获取待签名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “\n” + “bucket=yonghu-test”,并做md5 验证签名 应用服务器示例 以下为一段python示例,演示了一个简单的应用服务器,主要是说明验证签名的方法,此示例需要安装M2Crypto库import httplib import base64 import md5 import urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): #get public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print 'Authorization verify failed!' print 'Public key : %s' % (pub_key) print 'Auth string : %s' % (auth_str) self.send_response(400) self.end_headers() return #do something accoding to callback_body #response to OSS resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()其它语言实现的应用服务器如下: Java版本: 下载地址:点击这里 运行方法:解压包运行java -jar oss-callback-server-demo.jar 9000(9000就运行的端口,可以自己指定) PHP版本: 下载地址:点击这里 运行方法:部署到Apache环境下,因为PHP本身语言的特点,取一些数据头部会依赖于环境。所以可以参考例子根据所在环境修改。 Python版本: 下载地址:点击这里 运行方法:解压包直接运行python callback_app_server.py,运行该程序需要安装rsa的依赖。 C#版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Ruby版本: 下载地址:点击这里 运行方法: ruby aliyun_oss_callback_server.rb 特别须知 如果传入的callback或者callback-var不合法,则会返回400错误,错误码为”InvalidArgument”,不合法的情况包括以下几类: PutObject()和CompleteMultipartUpload()接口中url和header同时传入callback(x-oss-callback)或者callback-var(x-oss-callback-var)参数 callback或者callback-var(PostObject()由于没有callback-var参数,因此没有此限制,下同)参数过长(超过5KB) callback或者callback-var没有经过base64编码 callback或者callback-var经过base64解码后不是合法的json格式 callback参数解析后callbackUrl字段包含的url超过限制(5个),或者url中传入的port不合法,比如{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"} callback参数解析后callbackBody字段为空 callback参数解析后callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json” callback参数解析后callbackBody字段中变量的格式不合法,合法的格式为${var} callback-var参数解析后不是预期的json格式,预期的格式应该为{"x:var1":"value1","x:var2":"value2"...} 如果回调失败,则返回203,错误码为”CallbackFailed”,回调失败只是表示OSS没有收到预期的回调响应,不代表应用服务器没有收到回调请求(比如应用服务器返回的内容不是json格式),另外,此时文件已经成功上传到了OSS 应用服务器返回OSS的响应必须带有Content-Length的Header,Body大小不要超过1MB。 Callback支持的地域 Callback目前支持的地域如下:华北 2(北京)、华东 1(杭州)、华北 1(青岛)、华东 2(上海)、上海金融云、华南 1(深圳)、香港、华北 5(呼和浩特)、华北 3(张家口)、中东东部 1(迪拜)、亚太东北 1(日本)、欧洲中部 1(法兰克福)、亚太东南 1(新加坡)、美国东部 1(弗吉尼亚)、美国西部 1(硅谷)、亚太东南 2 (悉尼)以及亚太东南 3(吉隆坡)。
2019-12-01 23:13:51 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户只需要在发送给OSS的请求中携带相应的Callback参数,即能实现回调。 现在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。 构造CallBack参数 CallBack参数是由一段经过base64编码的Json字串,用户关键需要指定请求回调的服务器URL(callbackUrl)以及回调的内容(callbackBody)。详细的Json字段如下: 字段 含义 选项 callbackUrl 文件上传成功后OSS向此url发送回调请求,请求方法为POST,body为callbackBody指定的内容。正常情况下,该url需要响应“HTTP/1.1 200 OK”,body必须为JSON格式,响应头Content-Length必须为合法的值,且不超过3MB。 支持同时配置最多5个url,以”;”分割。OSS会依次发送请求直到第一个返回成功为止。 如果没有配置或者值为空则认为没有配置callback。 支持HTTPS地址。 为了保证正确处理中文等情况,callbackUrl需做url编码处理,比如http://example.com/中文.php?key=value&中文名称=中文值 需要编码成 http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC 必选项 callbackHost 发起回调请求时Host头的值,只有在设置了callbackUrl时才有效。 如果没有配置 callbckHost,则会解析callbackUrl中的url并将解析出的host填充到callbackHost中 可选项 callbackBody 发起回调时请求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 支持OSS系统变量、自定义变量和常量,支持的系统变量如下表所示 。自定义变量的支持方式在PutObject和CompleteMultipart中是通过callback-var来传递,在PostObject中则是将各个变量通过表单域来传递。 必选项 callbackBodyType 发起回调请求的Content-Type,支持application/x-www-form-urlencoded和application/json,默认为前者。 如果为application/x-www-form-urlencoded,则callbackBody中的变量将会被经过url编码的值替换掉,如果为application/json,则会按照json格式替换其中的变量。 可选项 示例json串如下 { "callbackUrl":"121.101.166.30/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" } { "callbackUrl":"121.43.113.8:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" } 其中callbackBody中可以设置的系统变量有,其中imageInfo针对于图片格式,如果为非图片格式都为空: 系统变量 含义 bucket bucket object object etag 文件的etag,即返回给用户的etag字段 size object大小,CompleteMultipartUpload时为整个object的大小 mimeType 资源类型,如jpeg图片的资源类型为image/jpeg imageInfo.height 图片高度 imageInfo.width 图片宽度 imageInfo.format 图片格式,如jpg、png等 自定义参数 用户可以通过callback-var参数来配置自定义参数。 自定义参数是一个Key-Value的Map,用户可以配置自己需要的参数到这个Map。在OSS发起POST回调请求的时候,会将这些参数和上一节所述的系统参数一起放在POST请求的body中以方便接收回调方获取。 构造自定义参数的方法和callback参数的方法是一样的,也是以json格式来传递。该json字符串就是一个包含所有自定义参数的Key-Value的Map。 说明 用户自定义参数的Key一定要以x:开头,且必须为小写。否则OSS会返回错误。 假定用户需要设定两个自定义的参数分别为x:var1和x:var2,对应的值分别为value1和value2,那么构造出来的json格式如下: { "x:var1":"value1", "x:var2":"value2" } 构造回调请求 构造完成上述的callback和callback-var两个参数之后,一共有三种方式传给OSS。其中callback为必填参数,callback-var为可选参数,如果没有自定义参数的话可以不用添加callback-var字段。这三种方式如下: 在URL中携带参数。 在Header中携带参数。 在POST请求的body中使用表单域来携带参数。 说明 在使用POST请求上传Object的时候只能使用这种方式来指定回调参数。 这三种方式只能同时使用其中一种,否则OSS会返回InvalidArgument错误。 要将参数附加到OSS的请求中,首先要将上文构造的json字符串使用base64编码,然后按照如下的方法附加到OSS的请求中: 如果在URL中携带参数。把callback=[CallBack]或者callback-var=[CallBackVar]作为一个url参数带入请求发送。计算签名CanonicalizedResource时 ,将callback或者callback-var当做一个sub-resource计算在内 如果在Header中携带参数。把x-oss-callback=[CallBack]或者x-oss-callback-var=[CallBackVar]作为一个head带入请求发送。在计算签名CanonicalizedOSSHeaders时,将x-oss-callback-var和x-oss-callback计算在内。如下示例:PUT /test.txt HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-ncoding: identity Content-Length: 5 x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0= Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: text/plain Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4= Test 如果需要在POST上传Object的时候附带回调参数会稍微复杂一点,callback参数要使用独立的表单域来附加,如下面的示例:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==如果拥有自定义参数的话,不能直接将callback-var参数直接附加到表单域中,每个自定义的参数都需要使用独立的表单域来附加,举个例子,如果用户的自定义参数的json为{ "x:var1":"value1", "x:var2":"value2" }那么POST请求的表单域应该如下:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ== --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2同时可以在policy中添加callback条件(如果不添加callback,则不对该参数做上传验证)如:{ "expiration": "2014-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="}, ["starts-with", "$key", "user/eric/"], ] } 发起回调请求 如果文件上传成功,OSS会根据用户的请求中的callback参数和自定义参数(callback-var参数),将特定内容以POST方式发送给应用服务器。 POST /index.html HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 181 Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test 返回回调结果 比如应用服务器端返回的回应请求为: HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"a":"b"} 返回上传结果 再给客户端的内容为: HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"a":"b"} 需要注意的是,如果类似CompleteMultipartUpload这样的请求,在返回请求本身body中存在内容(如XMl格式的信息),使用上传回调功能后会覆盖原有的body的内容如{"a":"b"},希望对此处做好判断处理。 回调签名 用户设置callback参数后,OSS将按照用户设置的callbackUrl发送POST回调请求给用户的应用服务器。应用服务器收到回调请求之后,如果希望验证回调请求确实是由OSS发起的话,那么可以通过在回调中带上签名来验证OSS的身份。 生成签名 签名在OSS端发生,采用RSA非对称方式签名,私钥加密的过程为:authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘\n’ + body, md5)) 说明 其中private_key为私钥,只有oss知晓,path为回调请求的资源路径,query_string为查询字符串,body为回调的消息体,所以签名过程由以下几步组成: 获取待签名字符串:资源路径经过url解码后,加上原始的查询字符串,加上一个回车符,加上回调消息体 RSA签名:使用秘钥对待签名字符串进行签名,签名的hash函数为md5 将签名后的结果做base64编码,得到最终的签名,签名放在回调请求的authorization头中 如下例:POST /index.php?id=1&index=2 HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ== bucket=yonghu-testpath为/index.php,query_string为?id=1&index=2,body为bucket=yonghu-test,最终签名结果为kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== 验证签名 验证签名的过程即为签名的逆过程,由应用服务器验证,过程如下:Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘\n’ + body), base64_decode(authorization))字段的含义与签名过程中描述相同,其中public_key为公钥, authorization为回调头中的签名,整个验证签名的过程分为以下几步: 回调请求的x-oss-pub-key-url头保存的是公钥的url地址的base64编码,因此需要对其做base64解码后获取到公钥,即public_key = urlopen(base64_decode(x-oss-pub-key-url头的值))这里需要注意,用户需要校验x-oss-pub-key-url头的值必须以http://gosspublic.alicdn.com/或者https://gosspublic.alicdn.com/开头,目的是为了保证这个publickey是由OSS颁发的。 获取base64解码后的签名signature = base64_decode(authorization头的值) 获取待签名字符串,方法与签名一致sign_str = url_decode(path) + query_string + ‘\n’ + body 验证签名result = rsa_verify(public_key, md5(sign_str), signature) 以上例为例: 获取到公钥的url地址,即aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==经过base64解码后得到http://gosspublic.alicdn.com/callback_pub_key_v1.pem 签名头kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==做base64解码(由于为非打印字符,无法显示出解码后的结果) 获取待签名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “\n” + “bucket=yonghu-test”,并做md5 验证签名 应用服务器示例 以下为一段python示例,演示了一个简单的应用服务器,主要是说明验证签名的方法,此示例需要安装M2Crypto库import httplib import base64 import md5 import urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): #get public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print 'Authorization verify failed!' print 'Public key : %s' % (pub_key) print 'Auth string : %s' % (auth_str) self.send_response(400) self.end_headers() return #do something accoding to callback_body #response to OSS resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()其它语言实现的应用服务器如下: Java版本: 下载地址:点击这里 运行方法:解压包运行java -jar oss-callback-server-demo.jar 9000(9000就运行的端口,可以自己指定) PHP版本: 下载地址:点击这里 运行方法:部署到Apache环境下,因为PHP本身语言的特点,取一些数据头部会依赖于环境。所以可以参考例子根据所在环境修改。 Python版本: 下载地址:点击这里 运行方法:解压包直接运行python callback_app_server.py,运行该程序需要安装rsa的依赖。 C#版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Ruby版本: 下载地址:点击这里 运行方法: ruby aliyun_oss_callback_server.rb 特别须知 如果传入的callback或者callback-var不合法,则会返回400错误,错误码为”InvalidArgument”,不合法的情况包括以下几类: PutObject()和CompleteMultipartUpload()接口中url和header同时传入callback(x-oss-callback)或者callback-var(x-oss-callback-var)参数 callback或者callback-var(PostObject()由于没有callback-var参数,因此没有此限制,下同)参数过长(超过5KB) callback或者callback-var没有经过base64编码 callback或者callback-var经过base64解码后不是合法的json格式 callback参数解析后callbackUrl字段包含的url超过限制(5个),或者url中传入的port不合法,比如{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"} callback参数解析后callbackBody字段为空 callback参数解析后callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json” callback参数解析后callbackBody字段中变量的格式不合法,合法的格式为${var} callback-var参数解析后不是预期的json格式,预期的格式应该为{"x:var1":"value1","x:var2":"value2"...} 如果回调失败,则返回203,错误码为”CallbackFailed”,回调失败只是表示OSS没有收到预期的回调响应,不代表应用服务器没有收到回调请求(比如应用服务器返回的内容不是json格式),另外,此时文件已经成功上传到了OSS 应用服务器返回OSS的响应必须带有Content-Length的Header,Body大小不要超过1MB。 Callback支持的地域 Callback目前支持的地域如下:华北 2(北京)、华东 1(杭州)、华北 1(青岛)、华东 2(上海)、上海金融云、华南 1(深圳)、香港、华北 5(呼和浩特)、华北 3(张家口)、中东东部 1(迪拜)、亚太东北 1(日本)、欧洲中部 1(法兰克福)、亚太东南 1(新加坡)、美国东部 1(弗吉尼亚)、美国西部 1(硅谷)、亚太东南 2 (悉尼)以及亚太东南 3(吉隆坡)。
2019-12-01 23:13:51 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户只需要在发送给OSS的请求中携带相应的Callback参数,即能实现回调。 现在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。 构造CallBack参数 CallBack参数是由一段经过base64编码的Json字串,用户关键需要指定请求回调的服务器URL(callbackUrl)以及回调的内容(callbackBody)。详细的Json字段如下: 字段 含义 选项 callbackUrl 文件上传成功后OSS向此url发送回调请求,请求方法为POST,body为callbackBody指定的内容。正常情况下,该url需要响应“HTTP/1.1 200 OK”,body必须为JSON格式,响应头Content-Length必须为合法的值,且不超过3MB。 支持同时配置最多5个url,以”;”分割。OSS会依次发送请求直到第一个返回成功为止。 如果没有配置或者值为空则认为没有配置callback。 支持HTTPS地址。 为了保证正确处理中文等情况,callbackUrl需做url编码处理,比如http://example.com/中文.php?key=value&中文名称=中文值 需要编码成 http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC 必选项 callbackHost 发起回调请求时Host头的值,只有在设置了callbackUrl时才有效。 如果没有配置 callbckHost,则会解析callbackUrl中的url并将解析出的host填充到callbackHost中 可选项 callbackBody 发起回调时请求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 支持OSS系统变量、自定义变量和常量,支持的系统变量如下表所示 。自定义变量的支持方式在PutObject和CompleteMultipart中是通过callback-var来传递,在PostObject中则是将各个变量通过表单域来传递。 必选项 callbackBodyType 发起回调请求的Content-Type,支持application/x-www-form-urlencoded和application/json,默认为前者。 如果为application/x-www-form-urlencoded,则callbackBody中的变量将会被经过url编码的值替换掉,如果为application/json,则会按照json格式替换其中的变量。 可选项 示例json串如下 { "callbackUrl":"121.101.166.30/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" } { "callbackUrl":"121.43.113.8:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" } 其中callbackBody中可以设置的系统变量有,其中imageInfo针对于图片格式,如果为非图片格式都为空: 系统变量 含义 bucket bucket object object etag 文件的etag,即返回给用户的etag字段 size object大小,CompleteMultipartUpload时为整个object的大小 mimeType 资源类型,如jpeg图片的资源类型为image/jpeg imageInfo.height 图片高度 imageInfo.width 图片宽度 imageInfo.format 图片格式,如jpg、png等 自定义参数 用户可以通过callback-var参数来配置自定义参数。 自定义参数是一个Key-Value的Map,用户可以配置自己需要的参数到这个Map。在OSS发起POST回调请求的时候,会将这些参数和上一节所述的系统参数一起放在POST请求的body中以方便接收回调方获取。 构造自定义参数的方法和callback参数的方法是一样的,也是以json格式来传递。该json字符串就是一个包含所有自定义参数的Key-Value的Map。 说明 用户自定义参数的Key一定要以x:开头,且必须为小写。否则OSS会返回错误。 假定用户需要设定两个自定义的参数分别为x:var1和x:var2,对应的值分别为value1和value2,那么构造出来的json格式如下: { "x:var1":"value1", "x:var2":"value2" } 构造回调请求 构造完成上述的callback和callback-var两个参数之后,一共有三种方式传给OSS。其中callback为必填参数,callback-var为可选参数,如果没有自定义参数的话可以不用添加callback-var字段。这三种方式如下: 在URL中携带参数。 在Header中携带参数。 在POST请求的body中使用表单域来携带参数。 说明 在使用POST请求上传Object的时候只能使用这种方式来指定回调参数。 这三种方式只能同时使用其中一种,否则OSS会返回InvalidArgument错误。 要将参数附加到OSS的请求中,首先要将上文构造的json字符串使用base64编码,然后按照如下的方法附加到OSS的请求中: 如果在URL中携带参数。把callback=[CallBack]或者callback-var=[CallBackVar]作为一个url参数带入请求发送。计算签名CanonicalizedResource时 ,将callback或者callback-var当做一个sub-resource计算在内 如果在Header中携带参数。把x-oss-callback=[CallBack]或者x-oss-callback-var=[CallBackVar]作为一个head带入请求发送。在计算签名CanonicalizedOSSHeaders时,将x-oss-callback-var和x-oss-callback计算在内。如下示例:PUT /test.txt HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-ncoding: identity Content-Length: 5 x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0= Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: text/plain Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4= Test 如果需要在POST上传Object的时候附带回调参数会稍微复杂一点,callback参数要使用独立的表单域来附加,如下面的示例:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==如果拥有自定义参数的话,不能直接将callback-var参数直接附加到表单域中,每个自定义的参数都需要使用独立的表单域来附加,举个例子,如果用户的自定义参数的json为{ "x:var1":"value1", "x:var2":"value2" }那么POST请求的表单域应该如下:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ== --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2同时可以在policy中添加callback条件(如果不添加callback,则不对该参数做上传验证)如:{ "expiration": "2014-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="}, ["starts-with", "$key", "user/eric/"], ] } 发起回调请求 如果文件上传成功,OSS会根据用户的请求中的callback参数和自定义参数(callback-var参数),将特定内容以POST方式发送给应用服务器。 POST /index.html HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 181 Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test 返回回调结果 比如应用服务器端返回的回应请求为: HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"a":"b"} 返回上传结果 再给客户端的内容为: HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"a":"b"} 需要注意的是,如果类似CompleteMultipartUpload这样的请求,在返回请求本身body中存在内容(如XMl格式的信息),使用上传回调功能后会覆盖原有的body的内容如{"a":"b"},希望对此处做好判断处理。 回调签名 用户设置callback参数后,OSS将按照用户设置的callbackUrl发送POST回调请求给用户的应用服务器。应用服务器收到回调请求之后,如果希望验证回调请求确实是由OSS发起的话,那么可以通过在回调中带上签名来验证OSS的身份。 生成签名 签名在OSS端发生,采用RSA非对称方式签名,私钥加密的过程为:authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘\n’ + body, md5)) 说明 其中private_key为私钥,只有oss知晓,path为回调请求的资源路径,query_string为查询字符串,body为回调的消息体,所以签名过程由以下几步组成: 获取待签名字符串:资源路径经过url解码后,加上原始的查询字符串,加上一个回车符,加上回调消息体 RSA签名:使用秘钥对待签名字符串进行签名,签名的hash函数为md5 将签名后的结果做base64编码,得到最终的签名,签名放在回调请求的authorization头中 如下例:POST /index.php?id=1&index=2 HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ== bucket=yonghu-testpath为/index.php,query_string为?id=1&index=2,body为bucket=yonghu-test,最终签名结果为kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== 验证签名 验证签名的过程即为签名的逆过程,由应用服务器验证,过程如下:Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘\n’ + body), base64_decode(authorization))字段的含义与签名过程中描述相同,其中public_key为公钥, authorization为回调头中的签名,整个验证签名的过程分为以下几步: 回调请求的x-oss-pub-key-url头保存的是公钥的url地址的base64编码,因此需要对其做base64解码后获取到公钥,即public_key = urlopen(base64_decode(x-oss-pub-key-url头的值))这里需要注意,用户需要校验x-oss-pub-key-url头的值必须以http://gosspublic.alicdn.com/或者https://gosspublic.alicdn.com/开头,目的是为了保证这个publickey是由OSS颁发的。 获取base64解码后的签名signature = base64_decode(authorization头的值) 获取待签名字符串,方法与签名一致sign_str = url_decode(path) + query_string + ‘\n’ + body 验证签名result = rsa_verify(public_key, md5(sign_str), signature) 以上例为例: 获取到公钥的url地址,即aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==经过base64解码后得到http://gosspublic.alicdn.com/callback_pub_key_v1.pem 签名头kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==做base64解码(由于为非打印字符,无法显示出解码后的结果) 获取待签名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “\n” + “bucket=yonghu-test”,并做md5 验证签名 应用服务器示例 以下为一段python示例,演示了一个简单的应用服务器,主要是说明验证签名的方法,此示例需要安装M2Crypto库import httplib import base64 import md5 import urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): #get public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print 'Authorization verify failed!' print 'Public key : %s' % (pub_key) print 'Auth string : %s' % (auth_str) self.send_response(400) self.end_headers() return #do something accoding to callback_body #response to OSS resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()其它语言实现的应用服务器如下: Java版本: 下载地址:点击这里 运行方法:解压包运行java -jar oss-callback-server-demo.jar 9000(9000就运行的端口,可以自己指定) PHP版本: 下载地址:点击这里 运行方法:部署到Apache环境下,因为PHP本身语言的特点,取一些数据头部会依赖于环境。所以可以参考例子根据所在环境修改。 Python版本: 下载地址:点击这里 运行方法:解压包直接运行python callback_app_server.py,运行该程序需要安装rsa的依赖。 C#版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Ruby版本: 下载地址:点击这里 运行方法: ruby aliyun_oss_callback_server.rb 特别须知 如果传入的callback或者callback-var不合法,则会返回400错误,错误码为”InvalidArgument”,不合法的情况包括以下几类: PutObject()和CompleteMultipartUpload()接口中url和header同时传入callback(x-oss-callback)或者callback-var(x-oss-callback-var)参数 callback或者callback-var(PostObject()由于没有callback-var参数,因此没有此限制,下同)参数过长(超过5KB) callback或者callback-var没有经过base64编码 callback或者callback-var经过base64解码后不是合法的json格式 callback参数解析后callbackUrl字段包含的url超过限制(5个),或者url中传入的port不合法,比如{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"} callback参数解析后callbackBody字段为空 callback参数解析后callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json” callback参数解析后callbackBody字段中变量的格式不合法,合法的格式为${var} callback-var参数解析后不是预期的json格式,预期的格式应该为{"x:var1":"value1","x:var2":"value2"...} 如果回调失败,则返回203,错误码为”CallbackFailed”,回调失败只是表示OSS没有收到预期的回调响应,不代表应用服务器没有收到回调请求(比如应用服务器返回的内容不是json格式),另外,此时文件已经成功上传到了OSS 应用服务器返回OSS的响应必须带有Content-Length的Header,Body大小不要超过1MB。 Callback支持的地域 Callback目前支持的地域如下:华北 2(北京)、华东 1(杭州)、华北 1(青岛)、华东 2(上海)、上海金融云、华南 1(深圳)、香港、华北 5(呼和浩特)、华北 3(张家口)、中东东部 1(迪拜)、亚太东北 1(日本)、欧洲中部 1(法兰克福)、亚太东南 1(新加坡)、美国东部 1(弗吉尼亚)、美国西部 1(硅谷)、亚太东南 2 (悉尼)以及亚太东南 3(吉隆坡)。
2019-12-01 23:13:52 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户只需要在发送给OSS的请求中携带相应的Callback参数,即能实现回调。 现在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。 构造CallBack参数 CallBack参数是由一段经过base64编码的Json字串,用户关键需要指定请求回调的服务器URL(callbackUrl)以及回调的内容(callbackBody)。详细的Json字段如下: 字段 含义 选项 callbackUrl 文件上传成功后OSS向此url发送回调请求,请求方法为POST,body为callbackBody指定的内容。正常情况下,该url需要响应“HTTP/1.1 200 OK”,body必须为JSON格式,响应头Content-Length必须为合法的值,且不超过3MB。 支持同时配置最多5个url,以”;”分割。OSS会依次发送请求直到第一个返回成功为止。 如果没有配置或者值为空则认为没有配置callback。 支持HTTPS地址。 为了保证正确处理中文等情况,callbackUrl需做url编码处理,比如http://example.com/中文.php?key=value&中文名称=中文值 需要编码成 http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC 必选项 callbackHost 发起回调请求时Host头的值,只有在设置了callbackUrl时才有效。 如果没有配置 callbckHost,则会解析callbackUrl中的url并将解析出的host填充到callbackHost中 可选项 callbackBody 发起回调时请求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 支持OSS系统变量、自定义变量和常量,支持的系统变量如下表所示 。自定义变量的支持方式在PutObject和CompleteMultipart中是通过callback-var来传递,在PostObject中则是将各个变量通过表单域来传递。 必选项 callbackBodyType 发起回调请求的Content-Type,支持application/x-www-form-urlencoded和application/json,默认为前者。 如果为application/x-www-form-urlencoded,则callbackBody中的变量将会被经过url编码的值替换掉,如果为application/json,则会按照json格式替换其中的变量。 可选项 示例json串如下 { "callbackUrl":"121.101.166.30/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" } { "callbackUrl":"121.43.113.8:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" } 其中callbackBody中可以设置的系统变量有,其中imageInfo针对于图片格式,如果为非图片格式都为空: 系统变量 含义 bucket bucket object object etag 文件的etag,即返回给用户的etag字段 size object大小,CompleteMultipartUpload时为整个object的大小 mimeType 资源类型,如jpeg图片的资源类型为image/jpeg imageInfo.height 图片高度 imageInfo.width 图片宽度 imageInfo.format 图片格式,如jpg、png等 自定义参数 用户可以通过callback-var参数来配置自定义参数。 自定义参数是一个Key-Value的Map,用户可以配置自己需要的参数到这个Map。在OSS发起POST回调请求的时候,会将这些参数和上一节所述的系统参数一起放在POST请求的body中以方便接收回调方获取。 构造自定义参数的方法和callback参数的方法是一样的,也是以json格式来传递。该json字符串就是一个包含所有自定义参数的Key-Value的Map。 说明 用户自定义参数的Key一定要以x:开头,且必须为小写。否则OSS会返回错误。 假定用户需要设定两个自定义的参数分别为x:var1和x:var2,对应的值分别为value1和value2,那么构造出来的json格式如下: { "x:var1":"value1", "x:var2":"value2" } 构造回调请求 构造完成上述的callback和callback-var两个参数之后,一共有三种方式传给OSS。其中callback为必填参数,callback-var为可选参数,如果没有自定义参数的话可以不用添加callback-var字段。这三种方式如下: 在URL中携带参数。 在Header中携带参数。 在POST请求的body中使用表单域来携带参数。 说明 在使用POST请求上传Object的时候只能使用这种方式来指定回调参数。 这三种方式只能同时使用其中一种,否则OSS会返回InvalidArgument错误。 要将参数附加到OSS的请求中,首先要将上文构造的json字符串使用base64编码,然后按照如下的方法附加到OSS的请求中: 如果在URL中携带参数。把callback=[CallBack]或者callback-var=[CallBackVar]作为一个url参数带入请求发送。计算签名CanonicalizedResource时 ,将callback或者callback-var当做一个sub-resource计算在内 如果在Header中携带参数。把x-oss-callback=[CallBack]或者x-oss-callback-var=[CallBackVar]作为一个head带入请求发送。在计算签名CanonicalizedOSSHeaders时,将x-oss-callback-var和x-oss-callback计算在内。如下示例:PUT /test.txt HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-ncoding: identity Content-Length: 5 x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0= Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: text/plain Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4= Test 如果需要在POST上传Object的时候附带回调参数会稍微复杂一点,callback参数要使用独立的表单域来附加,如下面的示例:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==如果拥有自定义参数的话,不能直接将callback-var参数直接附加到表单域中,每个自定义的参数都需要使用独立的表单域来附加,举个例子,如果用户的自定义参数的json为{ "x:var1":"value1", "x:var2":"value2" }那么POST请求的表单域应该如下:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ== --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2同时可以在policy中添加callback条件(如果不添加callback,则不对该参数做上传验证)如:{ "expiration": "2014-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="}, ["starts-with", "$key", "user/eric/"], ] } 发起回调请求 如果文件上传成功,OSS会根据用户的请求中的callback参数和自定义参数(callback-var参数),将特定内容以POST方式发送给应用服务器。 POST /index.html HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 181 Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test 返回回调结果 比如应用服务器端返回的回应请求为: HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"a":"b"} 返回上传结果 再给客户端的内容为: HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"a":"b"} 需要注意的是,如果类似CompleteMultipartUpload这样的请求,在返回请求本身body中存在内容(如XMl格式的信息),使用上传回调功能后会覆盖原有的body的内容如{"a":"b"},希望对此处做好判断处理。 回调签名 用户设置callback参数后,OSS将按照用户设置的callbackUrl发送POST回调请求给用户的应用服务器。应用服务器收到回调请求之后,如果希望验证回调请求确实是由OSS发起的话,那么可以通过在回调中带上签名来验证OSS的身份。 生成签名 签名在OSS端发生,采用RSA非对称方式签名,私钥加密的过程为:authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘\n’ + body, md5)) 说明 其中private_key为私钥,只有oss知晓,path为回调请求的资源路径,query_string为查询字符串,body为回调的消息体,所以签名过程由以下几步组成: 获取待签名字符串:资源路径经过url解码后,加上原始的查询字符串,加上一个回车符,加上回调消息体 RSA签名:使用秘钥对待签名字符串进行签名,签名的hash函数为md5 将签名后的结果做base64编码,得到最终的签名,签名放在回调请求的authorization头中 如下例:POST /index.php?id=1&index=2 HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ== bucket=yonghu-testpath为/index.php,query_string为?id=1&index=2,body为bucket=yonghu-test,最终签名结果为kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== 验证签名 验证签名的过程即为签名的逆过程,由应用服务器验证,过程如下:Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘\n’ + body), base64_decode(authorization))字段的含义与签名过程中描述相同,其中public_key为公钥, authorization为回调头中的签名,整个验证签名的过程分为以下几步: 回调请求的x-oss-pub-key-url头保存的是公钥的url地址的base64编码,因此需要对其做base64解码后获取到公钥,即public_key = urlopen(base64_decode(x-oss-pub-key-url头的值))这里需要注意,用户需要校验x-oss-pub-key-url头的值必须以http://gosspublic.alicdn.com/或者https://gosspublic.alicdn.com/开头,目的是为了保证这个publickey是由OSS颁发的。 获取base64解码后的签名signature = base64_decode(authorization头的值) 获取待签名字符串,方法与签名一致sign_str = url_decode(path) + query_string + ‘\n’ + body 验证签名result = rsa_verify(public_key, md5(sign_str), signature) 以上例为例: 获取到公钥的url地址,即aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==经过base64解码后得到http://gosspublic.alicdn.com/callback_pub_key_v1.pem 签名头kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==做base64解码(由于为非打印字符,无法显示出解码后的结果) 获取待签名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “\n” + “bucket=yonghu-test”,并做md5 验证签名 应用服务器示例 以下为一段python示例,演示了一个简单的应用服务器,主要是说明验证签名的方法,此示例需要安装M2Crypto库import httplib import base64 import md5 import urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): #get public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print 'Authorization verify failed!' print 'Public key : %s' % (pub_key) print 'Auth string : %s' % (auth_str) self.send_response(400) self.end_headers() return #do something accoding to callback_body #response to OSS resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()其它语言实现的应用服务器如下: Java版本: 下载地址:点击这里 运行方法:解压包运行java -jar oss-callback-server-demo.jar 9000(9000就运行的端口,可以自己指定) PHP版本: 下载地址:点击这里 运行方法:部署到Apache环境下,因为PHP本身语言的特点,取一些数据头部会依赖于环境。所以可以参考例子根据所在环境修改。 Python版本: 下载地址:点击这里 运行方法:解压包直接运行python callback_app_server.py,运行该程序需要安装rsa的依赖。 C#版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Ruby版本: 下载地址:点击这里 运行方法: ruby aliyun_oss_callback_server.rb 特别须知 如果传入的callback或者callback-var不合法,则会返回400错误,错误码为”InvalidArgument”,不合法的情况包括以下几类: PutObject()和CompleteMultipartUpload()接口中url和header同时传入callback(x-oss-callback)或者callback-var(x-oss-callback-var)参数 callback或者callback-var(PostObject()由于没有callback-var参数,因此没有此限制,下同)参数过长(超过5KB) callback或者callback-var没有经过base64编码 callback或者callback-var经过base64解码后不是合法的json格式 callback参数解析后callbackUrl字段包含的url超过限制(5个),或者url中传入的port不合法,比如{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"} callback参数解析后callbackBody字段为空 callback参数解析后callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json” callback参数解析后callbackBody字段中变量的格式不合法,合法的格式为${var} callback-var参数解析后不是预期的json格式,预期的格式应该为{"x:var1":"value1","x:var2":"value2"...} 如果回调失败,则返回203,错误码为”CallbackFailed”,回调失败只是表示OSS没有收到预期的回调响应,不代表应用服务器没有收到回调请求(比如应用服务器返回的内容不是json格式),另外,此时文件已经成功上传到了OSS 应用服务器返回OSS的响应必须带有Content-Length的Header,Body大小不要超过1MB。 Callback支持的地域 Callback目前支持的地域如下:华北 2(北京)、华东 1(杭州)、华北 1(青岛)、华东 2(上海)、上海金融云、华南 1(深圳)、香港、华北 5(呼和浩特)、华北 3(张家口)、中东东部 1(迪拜)、亚太东北 1(日本)、欧洲中部 1(法兰克福)、亚太东南 1(新加坡)、美国东部 1(弗吉尼亚)、美国西部 1(硅谷)、亚太东南 2 (悉尼)以及亚太东南 3(吉隆坡)。
2019-12-01 23:13:52 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户只需要在发送给OSS的请求中携带相应的Callback参数,即能实现回调。 现在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。 构造CallBack参数 CallBack参数是由一段经过base64编码的Json字串,用户关键需要指定请求回调的服务器URL(callbackUrl)以及回调的内容(callbackBody)。详细的Json字段如下: 字段 含义 选项 callbackUrl 文件上传成功后OSS向此url发送回调请求,请求方法为POST,body为callbackBody指定的内容。正常情况下,该url需要响应“HTTP/1.1 200 OK”,body必须为JSON格式,响应头Content-Length必须为合法的值,且不超过3MB。 支持同时配置最多5个url,以”;”分割。OSS会依次发送请求直到第一个返回成功为止。 如果没有配置或者值为空则认为没有配置callback。 支持HTTPS地址。 为了保证正确处理中文等情况,callbackUrl需做url编码处理,比如http://example.com/中文.php?key=value&中文名称=中文值 需要编码成 http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC 必选项 callbackHost 发起回调请求时Host头的值,只有在设置了callbackUrl时才有效。 如果没有配置 callbckHost,则会解析callbackUrl中的url并将解析出的host填充到callbackHost中 可选项 callbackBody 发起回调时请求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 支持OSS系统变量、自定义变量和常量,支持的系统变量如下表所示 。自定义变量的支持方式在PutObject和CompleteMultipart中是通过callback-var来传递,在PostObject中则是将各个变量通过表单域来传递。 必选项 callbackBodyType 发起回调请求的Content-Type,支持application/x-www-form-urlencoded和application/json,默认为前者。 如果为application/x-www-form-urlencoded,则callbackBody中的变量将会被经过url编码的值替换掉,如果为application/json,则会按照json格式替换其中的变量。 可选项 示例json串如下 { "callbackUrl":"121.101.166.30/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" } { "callbackUrl":"121.43.113.8:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" } 其中callbackBody中可以设置的系统变量有,其中imageInfo针对于图片格式,如果为非图片格式都为空: 系统变量 含义 bucket bucket object object etag 文件的etag,即返回给用户的etag字段 size object大小,CompleteMultipartUpload时为整个object的大小 mimeType 资源类型,如jpeg图片的资源类型为image/jpeg imageInfo.height 图片高度 imageInfo.width 图片宽度 imageInfo.format 图片格式,如jpg、png等 自定义参数 用户可以通过callback-var参数来配置自定义参数。 自定义参数是一个Key-Value的Map,用户可以配置自己需要的参数到这个Map。在OSS发起POST回调请求的时候,会将这些参数和上一节所述的系统参数一起放在POST请求的body中以方便接收回调方获取。 构造自定义参数的方法和callback参数的方法是一样的,也是以json格式来传递。该json字符串就是一个包含所有自定义参数的Key-Value的Map。 说明 用户自定义参数的Key一定要以x:开头,且必须为小写。否则OSS会返回错误。 假定用户需要设定两个自定义的参数分别为x:var1和x:var2,对应的值分别为value1和value2,那么构造出来的json格式如下: { "x:var1":"value1", "x:var2":"value2" } 构造回调请求 构造完成上述的callback和callback-var两个参数之后,一共有三种方式传给OSS。其中callback为必填参数,callback-var为可选参数,如果没有自定义参数的话可以不用添加callback-var字段。这三种方式如下: 在URL中携带参数。 在Header中携带参数。 在POST请求的body中使用表单域来携带参数。 说明 在使用POST请求上传Object的时候只能使用这种方式来指定回调参数。 这三种方式只能同时使用其中一种,否则OSS会返回InvalidArgument错误。 要将参数附加到OSS的请求中,首先要将上文构造的json字符串使用base64编码,然后按照如下的方法附加到OSS的请求中: 如果在URL中携带参数。把callback=[CallBack]或者callback-var=[CallBackVar]作为一个url参数带入请求发送。计算签名CanonicalizedResource时 ,将callback或者callback-var当做一个sub-resource计算在内 如果在Header中携带参数。把x-oss-callback=[CallBack]或者x-oss-callback-var=[CallBackVar]作为一个head带入请求发送。在计算签名CanonicalizedOSSHeaders时,将x-oss-callback-var和x-oss-callback计算在内。如下示例:PUT /test.txt HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-ncoding: identity Content-Length: 5 x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0= Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: text/plain Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4= Test 如果需要在POST上传Object的时候附带回调参数会稍微复杂一点,callback参数要使用独立的表单域来附加,如下面的示例:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==如果拥有自定义参数的话,不能直接将callback-var参数直接附加到表单域中,每个自定义的参数都需要使用独立的表单域来附加,举个例子,如果用户的自定义参数的json为{ "x:var1":"value1", "x:var2":"value2" }那么POST请求的表单域应该如下:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ== --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2同时可以在policy中添加callback条件(如果不添加callback,则不对该参数做上传验证)如:{ "expiration": "2014-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="}, ["starts-with", "$key", "user/eric/"], ] } 发起回调请求 如果文件上传成功,OSS会根据用户的请求中的callback参数和自定义参数(callback-var参数),将特定内容以POST方式发送给应用服务器。 POST /index.html HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 181 Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test 返回回调结果 比如应用服务器端返回的回应请求为: HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"a":"b"} 返回上传结果 再给客户端的内容为: HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"a":"b"} 需要注意的是,如果类似CompleteMultipartUpload这样的请求,在返回请求本身body中存在内容(如XMl格式的信息),使用上传回调功能后会覆盖原有的body的内容如{"a":"b"},希望对此处做好判断处理。 回调签名 用户设置callback参数后,OSS将按照用户设置的callbackUrl发送POST回调请求给用户的应用服务器。应用服务器收到回调请求之后,如果希望验证回调请求确实是由OSS发起的话,那么可以通过在回调中带上签名来验证OSS的身份。 生成签名 签名在OSS端发生,采用RSA非对称方式签名,私钥加密的过程为:authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘\n’ + body, md5)) 说明 其中private_key为私钥,只有oss知晓,path为回调请求的资源路径,query_string为查询字符串,body为回调的消息体,所以签名过程由以下几步组成: 获取待签名字符串:资源路径经过url解码后,加上原始的查询字符串,加上一个回车符,加上回调消息体 RSA签名:使用秘钥对待签名字符串进行签名,签名的hash函数为md5 将签名后的结果做base64编码,得到最终的签名,签名放在回调请求的authorization头中 如下例:POST /index.php?id=1&index=2 HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ== bucket=yonghu-testpath为/index.php,query_string为?id=1&index=2,body为bucket=yonghu-test,最终签名结果为kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== 验证签名 验证签名的过程即为签名的逆过程,由应用服务器验证,过程如下:Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘\n’ + body), base64_decode(authorization))字段的含义与签名过程中描述相同,其中public_key为公钥, authorization为回调头中的签名,整个验证签名的过程分为以下几步: 回调请求的x-oss-pub-key-url头保存的是公钥的url地址的base64编码,因此需要对其做base64解码后获取到公钥,即public_key = urlopen(base64_decode(x-oss-pub-key-url头的值))这里需要注意,用户需要校验x-oss-pub-key-url头的值必须以http://gosspublic.alicdn.com/或者https://gosspublic.alicdn.com/开头,目的是为了保证这个publickey是由OSS颁发的。 获取base64解码后的签名signature = base64_decode(authorization头的值) 获取待签名字符串,方法与签名一致sign_str = url_decode(path) + query_string + ‘\n’ + body 验证签名result = rsa_verify(public_key, md5(sign_str), signature) 以上例为例: 获取到公钥的url地址,即aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==经过base64解码后得到http://gosspublic.alicdn.com/callback_pub_key_v1.pem 签名头kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==做base64解码(由于为非打印字符,无法显示出解码后的结果) 获取待签名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “\n” + “bucket=yonghu-test”,并做md5 验证签名 应用服务器示例 以下为一段python示例,演示了一个简单的应用服务器,主要是说明验证签名的方法,此示例需要安装M2Crypto库import httplib import base64 import md5 import urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): #get public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print 'Authorization verify failed!' print 'Public key : %s' % (pub_key) print 'Auth string : %s' % (auth_str) self.send_response(400) self.end_headers() return #do something accoding to callback_body #response to OSS resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()其它语言实现的应用服务器如下: Java版本: 下载地址:点击这里 运行方法:解压包运行java -jar oss-callback-server-demo.jar 9000(9000就运行的端口,可以自己指定) PHP版本: 下载地址:点击这里 运行方法:部署到Apache环境下,因为PHP本身语言的特点,取一些数据头部会依赖于环境。所以可以参考例子根据所在环境修改。 Python版本: 下载地址:点击这里 运行方法:解压包直接运行python callback_app_server.py,运行该程序需要安装rsa的依赖。 C#版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Ruby版本: 下载地址:点击这里 运行方法: ruby aliyun_oss_callback_server.rb 特别须知 如果传入的callback或者callback-var不合法,则会返回400错误,错误码为”InvalidArgument”,不合法的情况包括以下几类: PutObject()和CompleteMultipartUpload()接口中url和header同时传入callback(x-oss-callback)或者callback-var(x-oss-callback-var)参数 callback或者callback-var(PostObject()由于没有callback-var参数,因此没有此限制,下同)参数过长(超过5KB) callback或者callback-var没有经过base64编码 callback或者callback-var经过base64解码后不是合法的json格式 callback参数解析后callbackUrl字段包含的url超过限制(5个),或者url中传入的port不合法,比如{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"} callback参数解析后callbackBody字段为空 callback参数解析后callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json” callback参数解析后callbackBody字段中变量的格式不合法,合法的格式为${var} callback-var参数解析后不是预期的json格式,预期的格式应该为{"x:var1":"value1","x:var2":"value2"...} 如果回调失败,则返回203,错误码为”CallbackFailed”,回调失败只是表示OSS没有收到预期的回调响应,不代表应用服务器没有收到回调请求(比如应用服务器返回的内容不是json格式),另外,此时文件已经成功上传到了OSS 应用服务器返回OSS的响应必须带有Content-Length的Header,Body大小不要超过1MB。 Callback支持的地域 Callback目前支持的地域如下:华北 2(北京)、华东 1(杭州)、华北 1(青岛)、华东 2(上海)、上海金融云、华南 1(深圳)、香港、华北 5(呼和浩特)、华北 3(张家口)、中东东部 1(迪拜)、亚太东北 1(日本)、欧洲中部 1(法兰克福)、亚太东南 1(新加坡)、美国东部 1(弗吉尼亚)、美国西部 1(硅谷)、亚太东南 2 (悉尼)以及亚太东南 3(吉隆坡)。
2019-12-01 23:13:50 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 用户只需要在发送给OSS的请求中携带相应的Callback参数,即能实现回调。 现在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。 构造CallBack参数 CallBack参数是由一段经过base64编码的Json字串,用户关键需要指定请求回调的服务器URL(callbackUrl)以及回调的内容(callbackBody)。详细的Json字段如下: 字段 含义 选项 callbackUrl 文件上传成功后OSS向此url发送回调请求,请求方法为POST,body为callbackBody指定的内容。正常情况下,该url需要响应“HTTP/1.1 200 OK”,body必须为JSON格式,响应头Content-Length必须为合法的值,且不超过3MB。 支持同时配置最多5个url,以”;”分割。OSS会依次发送请求直到第一个返回成功为止。 如果没有配置或者值为空则认为没有配置callback。 支持HTTPS地址。 为了保证正确处理中文等情况,callbackUrl需做url编码处理,比如http://example.com/中文.php?key=value&中文名称=中文值 需要编码成 http://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC 必选项 callbackHost 发起回调请求时Host头的值,只有在设置了callbackUrl时才有效。 如果没有配置 callbckHost,则会解析callbackUrl中的url并将解析出的host填充到callbackHost中 可选项 callbackBody 发起回调时请求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 支持OSS系统变量、自定义变量和常量,支持的系统变量如下表所示 。自定义变量的支持方式在PutObject和CompleteMultipart中是通过callback-var来传递,在PostObject中则是将各个变量通过表单域来传递。 必选项 callbackBodyType 发起回调请求的Content-Type,支持application/x-www-form-urlencoded和application/json,默认为前者。 如果为application/x-www-form-urlencoded,则callbackBody中的变量将会被经过url编码的值替换掉,如果为application/json,则会按照json格式替换其中的变量。 可选项 示例json串如下 { "callbackUrl":"121.101.166.30/test.php", "callbackHost":"oss-cn-hangzhou.aliyuncs.com", "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}", "callbackBodyType":"application/json" } { "callbackUrl":"121.43.113.8:23456/index.html", "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}" } 其中callbackBody中可以设置的系统变量有,其中imageInfo针对于图片格式,如果为非图片格式都为空: 系统变量 含义 bucket bucket object object etag 文件的etag,即返回给用户的etag字段 size object大小,CompleteMultipartUpload时为整个object的大小 mimeType 资源类型,如jpeg图片的资源类型为image/jpeg imageInfo.height 图片高度 imageInfo.width 图片宽度 imageInfo.format 图片格式,如jpg、png等 自定义参数 用户可以通过callback-var参数来配置自定义参数。 自定义参数是一个Key-Value的Map,用户可以配置自己需要的参数到这个Map。在OSS发起POST回调请求的时候,会将这些参数和上一节所述的系统参数一起放在POST请求的body中以方便接收回调方获取。 构造自定义参数的方法和callback参数的方法是一样的,也是以json格式来传递。该json字符串就是一个包含所有自定义参数的Key-Value的Map。 说明 用户自定义参数的Key一定要以x:开头,且必须为小写。否则OSS会返回错误。 假定用户需要设定两个自定义的参数分别为x:var1和x:var2,对应的值分别为value1和value2,那么构造出来的json格式如下: { "x:var1":"value1", "x:var2":"value2" } 构造回调请求 构造完成上述的callback和callback-var两个参数之后,一共有三种方式传给OSS。其中callback为必填参数,callback-var为可选参数,如果没有自定义参数的话可以不用添加callback-var字段。这三种方式如下: 在URL中携带参数。 在Header中携带参数。 在POST请求的body中使用表单域来携带参数。 说明 在使用POST请求上传Object的时候只能使用这种方式来指定回调参数。 这三种方式只能同时使用其中一种,否则OSS会返回InvalidArgument错误。 要将参数附加到OSS的请求中,首先要将上文构造的json字符串使用base64编码,然后按照如下的方法附加到OSS的请求中: 如果在URL中携带参数。把callback=[CallBack]或者callback-var=[CallBackVar]作为一个url参数带入请求发送。计算签名CanonicalizedResource时 ,将callback或者callback-var当做一个sub-resource计算在内 如果在Header中携带参数。把x-oss-callback=[CallBack]或者x-oss-callback-var=[CallBackVar]作为一个head带入请求发送。在计算签名CanonicalizedOSSHeaders时,将x-oss-callback-var和x-oss-callback计算在内。如下示例:PUT /test.txt HTTP/1.1 Host: callback-test.oss-test.aliyun-inc.com Accept-ncoding: identity Content-Length: 5 x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0= User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4) x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0= Host: callback-test.oss-test.aliyun-inc.com Expect: 100-Continue Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: text/plain Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4= Test 如果需要在POST上传Object的时候附带回调参数会稍微复杂一点,callback参数要使用独立的表单域来附加,如下面的示例:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==如果拥有自定义参数的话,不能直接将callback-var参数直接附加到表单域中,每个自定义的参数都需要使用独立的表单域来附加,举个例子,如果用户的自定义参数的json为{ "x:var1":"value1", "x:var2":"value2" }那么POST请求的表单域应该如下:--9431149156168 Content-Disposition: form-data; name="callback" eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ== --9431149156168 Content-Disposition: form-data; name="x:var1" value1 --9431149156168 Content-Disposition: form-data; name="x:var2" value2同时可以在policy中添加callback条件(如果不添加callback,则不对该参数做上传验证)如:{ "expiration": "2014-12-01T12:00:00.000Z", "conditions": [ {"bucket": "johnsmith" }, {"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="}, ["starts-with", "$key", "user/eric/"], ] } 发起回调请求 如果文件上传成功,OSS会根据用户的请求中的callback参数和自定义参数(callback-var参数),将特定内容以POST方式发送给应用服务器。 POST /index.html HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 181 Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test 返回回调结果 比如应用服务器端返回的回应请求为: HTTP/1.0 200 OK Server: BaseHTTP/0.3 Python/2.7.6 Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 {"a":"b"} 返回上传结果 再给客户端的内容为: HTTP/1.1 200 OK Date: Mon, 14 Sep 2015 12:37:27 GMT Content-Type: application/json Content-Length: 9 Connection: keep-alive ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249" Server: AliyunOSS x-oss-bucket-version: 1442231779 x-oss-request-id: 55F6BF87207FB30F2640C548 {"a":"b"} 需要注意的是,如果类似CompleteMultipartUpload这样的请求,在返回请求本身body中存在内容(如XMl格式的信息),使用上传回调功能后会覆盖原有的body的内容如{"a":"b"},希望对此处做好判断处理。 回调签名 用户设置callback参数后,OSS将按照用户设置的callbackUrl发送POST回调请求给用户的应用服务器。应用服务器收到回调请求之后,如果希望验证回调请求确实是由OSS发起的话,那么可以通过在回调中带上签名来验证OSS的身份。 生成签名 签名在OSS端发生,采用RSA非对称方式签名,私钥加密的过程为:authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘\n’ + body, md5)) 说明 其中private_key为私钥,只有oss知晓,path为回调请求的资源路径,query_string为查询字符串,body为回调的消息体,所以签名过程由以下几步组成: 获取待签名字符串:资源路径经过url解码后,加上原始的查询字符串,加上一个回车符,加上回调消息体 RSA签名:使用秘钥对待签名字符串进行签名,签名的hash函数为md5 将签名后的结果做base64编码,得到最终的签名,签名放在回调请求的authorization头中 如下例:POST /index.php?id=1&index=2 HTTP/1.0 Host: 121.43.113.8 Connection: close Content-Length: 18 authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== Content-Type: application/x-www-form-urlencoded User-Agent: ehttp-client/0.0.1 x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ== bucket=yonghu-testpath为/index.php,query_string为?id=1&index=2,body为bucket=yonghu-test,最终签名结果为kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA== 验证签名 验证签名的过程即为签名的逆过程,由应用服务器验证,过程如下:Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘\n’ + body), base64_decode(authorization))字段的含义与签名过程中描述相同,其中public_key为公钥, authorization为回调头中的签名,整个验证签名的过程分为以下几步: 回调请求的x-oss-pub-key-url头保存的是公钥的url地址的base64编码,因此需要对其做base64解码后获取到公钥,即public_key = urlopen(base64_decode(x-oss-pub-key-url头的值))这里需要注意,用户需要校验x-oss-pub-key-url头的值必须以http://gosspublic.alicdn.com/或者https://gosspublic.alicdn.com/开头,目的是为了保证这个publickey是由OSS颁发的。 获取base64解码后的签名signature = base64_decode(authorization头的值) 获取待签名字符串,方法与签名一致sign_str = url_decode(path) + query_string + ‘\n’ + body 验证签名result = rsa_verify(public_key, md5(sign_str), signature) 以上例为例: 获取到公钥的url地址,即aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==经过base64解码后得到http://gosspublic.alicdn.com/callback_pub_key_v1.pem 签名头kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==做base64解码(由于为非打印字符,无法显示出解码后的结果) 获取待签名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “\n” + “bucket=yonghu-test”,并做md5 验证签名 应用服务器示例 以下为一段python示例,演示了一个简单的应用服务器,主要是说明验证签名的方法,此示例需要安装M2Crypto库import httplib import base64 import md5 import urllib2 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from M2Crypto import RSA from M2Crypto import BIO def get_local_ip(): try: csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) csock.connect(('8.8.8.8', 80)) (addr, port) = csock.getsockname() csock.close() return addr except socket.error: return "" class MyHTTPRequestHandler(BaseHTTPRequestHandler): ''' def log_message(self, format, *args): return ''' def do_POST(self): #get public key pub_key_url = '' try: pub_key_url_base64 = self.headers['x-oss-pub-key-url'] pub_key_url = pub_key_url_base64.decode('base64') if not pub_key_url.startswith("http://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"): self.send_response(400) self.end_headers() return url_reader = urllib2.urlopen(pub_key_url) #you can cache it pub_key = url_reader.read() except: print 'pub_key_url : ' + pub_key_url print 'Get pub key failed!' self.send_response(400) self.end_headers() return #get authorization authorization_base64 = self.headers['authorization'] authorization = authorization_base64.decode('base64') #get callback body content_length = self.headers['content-length'] callback_body = self.rfile.read(int(content_length)) #compose authorization string auth_str = '' pos = self.path.find('?') if -1 == pos: auth_str = urllib2.unquote(self.path) + '\n' + callback_body else: auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + '\n' + callback_body print auth_str #verify authorization auth_md5 = md5.new(auth_str).digest() bio = BIO.MemoryBuffer(pub_key) rsa_pub = RSA.load_pub_key_bio(bio) try: result = rsa_pub.verify(auth_md5, authorization, 'md5') except: result = False if not result: print 'Authorization verify failed!' print 'Public key : %s' % (pub_key) print 'Auth string : %s' % (auth_str) self.send_response(400) self.end_headers() return #do something accoding to callback_body #response to OSS resp_body = '{"Status":"OK"}' self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(resp_body))) self.end_headers() self.wfile.write(resp_body) class MyHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler) if '__main__' == __name__: server_ip = get_local_ip() server_port = 23451 server = MyHTTPServer(server_ip, server_port) server.serve_forever()其它语言实现的应用服务器如下: Java版本: 下载地址:点击这里 运行方法:解压包运行java -jar oss-callback-server-demo.jar 9000(9000就运行的端口,可以自己指定) PHP版本: 下载地址:点击这里 运行方法:部署到Apache环境下,因为PHP本身语言的特点,取一些数据头部会依赖于环境。所以可以参考例子根据所在环境修改。 Python版本: 下载地址:点击这里 运行方法:解压包直接运行python callback_app_server.py,运行该程序需要安装rsa的依赖。 C#版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Go版本: 下载地址:点击这里 运行方法:解压后参看 README.md。 Ruby版本: 下载地址:点击这里 运行方法: ruby aliyun_oss_callback_server.rb 特别须知 如果传入的callback或者callback-var不合法,则会返回400错误,错误码为”InvalidArgument”,不合法的情况包括以下几类: PutObject()和CompleteMultipartUpload()接口中url和header同时传入callback(x-oss-callback)或者callback-var(x-oss-callback-var)参数 callback或者callback-var(PostObject()由于没有callback-var参数,因此没有此限制,下同)参数过长(超过5KB) callback或者callback-var没有经过base64编码 callback或者callback-var经过base64解码后不是合法的json格式 callback参数解析后callbackUrl字段包含的url超过限制(5个),或者url中传入的port不合法,比如{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"} callback参数解析后callbackBody字段为空 callback参数解析后callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json” callback参数解析后callbackBody字段中变量的格式不合法,合法的格式为${var} callback-var参数解析后不是预期的json格式,预期的格式应该为{"x:var1":"value1","x:var2":"value2"...} 如果回调失败,则返回203,错误码为”CallbackFailed”,回调失败只是表示OSS没有收到预期的回调响应,不代表应用服务器没有收到回调请求(比如应用服务器返回的内容不是json格式),另外,此时文件已经成功上传到了OSS 应用服务器返回OSS的响应必须带有Content-Length的Header,Body大小不要超过1MB。 Callback支持的地域 Callback目前支持的地域如下:华北 2(北京)、华东 1(杭州)、华北 1(青岛)、华东 2(上海)、上海金融云、华南 1(深圳)、香港、华北 5(呼和浩特)、华北 3(张家口)、中东东部 1(迪拜)、亚太东北 1(日本)、欧洲中部 1(法兰克福)、亚太东南 1(新加坡)、美国东部 1(弗吉尼亚)、美国西部 1(硅谷)、亚太东南 2 (悉尼)以及亚太东南 3(吉隆坡)。
2019-12-01 23:13:51 0 浏览量 回答数 0

云产品推荐

上海奇点人才服务相关的云产品 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务 阿里云AIoT