探秘之阿里云 OSS 数据存储 API-阿里云开发者社区

开发者社区> 阿里云支持与服务> 正文

探秘之阿里云 OSS 数据存储 API

简介: 为什么叫探秘 使用过阿里云 OSS 存储 API 的用户和客服都知道有一个通用的环节就是 Authorization 的计算,以及请求头的一些添加规范,给用户和客服烙下了不小的 “心理阴影” ,尤其 OSS Authorization  头的计算,光文章就密密麻麻的一篇(反正我的密集恐惧症犯了)。

为什么叫探秘



使用过阿里云 OSS 存储 API 的用户和客服都知道有一个通用的环节就是 Authorization 的计算,以及请求头的一些添加规范,给用户和客服烙下了不小的 “心理阴影” ,尤其 OSS Authorization  头的计算,光文章就密密麻麻的一篇(反正我的密集恐惧症犯了)。由于本人趟过坑今天就手把手,嘴对嘴的把过程说下,“活”儿不好,请各路老司机温柔以待!

官网的文章https://help.aliyun.com/document_detail/31951.html?spm=a2c4g.11186623.6.1012.5bb84b4e6wXZcI

PutObject  规范https://help.aliyun.com/document_detail/31978.html?spm=a2c4g.11186623.6.994.1632734cIiNNmj


先了解名词



AccessKey:访问云产品的凭证,类似宝藏的锁,可以是主账号或者 RAM 子账号的。

Access Key Secret:访问云产品的秘钥,类似宝藏的钥匙,可以是主账号或者 RAM 子账号的。

Authorization:Header 来包含签名(Signature)信息,表明这个消息已被授权。

Signature:经过各种计算得到的鉴权指纹信息。

CanonicalizedOSSHeaders:访问 OSS 时,用户想要加的自定义头,必须以 "x-oss-" 为头的前缀。如果使用,也必须要加到 Signature  中计算。

CanonicalizedResource:访问 OSS 的资源 object,结构是 /bucket/ object,来个板“例”

  •  /zhangyibo/Japan/video/tokhot.avi  将视频上传到 bucket 为 zhangyibo 的虚拟目录 Japan 下面,命名为 tokhot.avi ,可以是 PUT / GET 等操作。
  • /zhangybi/ 针对 bucket 是 zhangyibo 进行的操作,可以是 PUT / GET 等操作。
主账号 / RAM 子账号的 AccessKey 、Access Key Secret 获取方式如下



丑话说在前面



  • 我也是个客服,并非正规阿里云研发代码,仅个人分享。
  • 本次代码仅仅演示最简单的 OSS 上传操作,没有做过多的校验,请使用者自行判断提交信息的正确性。
  • 如果 “活” 儿不好,请客官们手指一二,下次改正缺点。

“被窝” 脚本如下



确实是在被窝里花了 30 分钟写出来的~,环境基础 2.7.5 来编写,如移植到各位客户机器上有异常,请看下对应的库文件,或者兼容性问题。
使用说明(都是必选):

PSA1#: python beiwo.py -h
Usage: beiwo.py [options]
Options:
  -h, --help  show this help message and exit
  -i AK       Must fill in Accesskey          访问云产品的 Accesskey
  -k SK       Must fill in AccessKeySecrety   访问云产品的 Accesskey Secret
  -e ED       Must fill in endpoint           OSS 的 endpoint 地理信息
  -b BK       Must fill in bucket             OSS bucket 
  -o OBJECTS  File name uploaded to oss       上传的 object 名称
  -f FI       Must fill localfile path        本地文件的名称 

趟坑

  • 客观想要玩的 安全,可以加个外套 Content-MD5,但是不注意的人就会忘记加了,补充如下:根据协议 RFC 1864 对消息内容(不包括头部)计算 MD5 值获得 128 比特位数字,对该数字进行 base64 编码为一个消息的 Content-MD5 值,并且 MD5 是 大写 哦。
  • 如果客观想要单独加项目 CanonicalizedOSSHeaders 一定要记得不仅在 Header 中加,你的 hmac 计算时也要加,来个板 “例”
  • Content-Type 一定要在 hmac 计算中
  • 如果遇到 client 计算的 MD5 和 Server 不一致的情况请直接使用 HTTPS 传输,很可能中间的网络设置有故障或者劫持时导致内存被篡改,只要将 url 改为 https:// 就是启动 HTTPS 协议 上传/ 下载 了。
hmac.new("5Lic5Lqs5LiA54K56YO95LiN54Ot","PUT\n\napplication/x-www-form-urlencoded\nSun, 02 Sep 2018 03:20:05 GMT\nx-oss-video:tokhot.avi/zhangyibo/tokhot.avi", sha)

脚本源码:

from optparse import OptionParser
import urllib,urllib2
import datetime
import base64
import hmac
import sha
import os
import sys
class Main():
  # Initial input parse
  def __init__(self,options):
    self.ak = options.ak
    self.sk = options.sk
    self.ed = options.ed
    self.bk = options.bk
    self.fi = options.fi
    self.oj = options.objects
    self.types = "application/x-www-form-urlencoded"   
    self.url = 'http://{0}.{1}/{2}'.format(self.bk,self.ed,self.oj)
  # Check client input parse
  def CheckParse(self):
    if (self.ak and self.sk and self.ed and self.bk and self.oj and self.fi) != None:
      if str(self.ak and self.sk and self.ed and self.bk and self.oj and self.fi):
        return True
    else:
      return False

  # GET local GMT time
  def GetGMT(self):
    GMT = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
    return GMT

  # GET Signature
  def GetSignature(self):
    mac = hmac.new("{0}".format(self.sk),"PUT\n\n{0}\n{1}\n/{2}/{3}".format(self.types,self.GetGMT(),self.bk,self.oj), sha)
    Signature = base64.b64encode(mac.digest())
  
    return Signature
  # PutObject
  def PutObject(self):
    try:
      with open(self.fi) as fd:
        files = fd.read()
    except Exception:
      sys.exit('\033[1;31;40m[error:]\033[0mFail to read localfile')

    try:
      request = urllib2.Request(self.url, files)
    except Exception:
      sys.exit('\033[1;31;40m[error:]\033[0mraise AttributeError, attr')
    try:
     request.add_header('Host','ali-beijing.oss-cn-beijing.aliyuncs.com')
     request.add_header('Date','{0}'.format(self.GetGMT()))
     request.add_header('Authorization','OSS {0}:{1}'.format(self.ak,self.GetSignature()))
     request.get_method = lambda:'PUT'
     response = urllib2.urlopen(request,timeout=10)
     sys.exit("\n%s"%response.headers)
    except Exception,e:
      sys.exit('\n\033[1;31;40m[error:]\033[0m%s'%e)
  
if __name__ == "__main__":
  parser = OptionParser()
  parser.add_option("-i",dest="ak",help="Must fill in Accesskey")
  parser.add_option("-k",dest="sk",help="Must fill in AccessKeySecrety")
  parser.add_option("-e",dest="ed",help="Must fill in endpoint")
  parser.add_option("-b",dest="bk",help="Must fill in bucket")
  parser.add_option("-o",dest="objects",help="File name uploadd to oss")
  parser.add_option("-f",dest="fi",help="Must fill localfile path")
  (options, args) = parser.parse_args()
  handler = Main(options)
  if handler.CheckParse():
    handler.PutObject()
  else:
    sys.exit('\033[1;31;40m[error:]\033[0mCheck your parse not null')

运行结果:

cae132fce8d1d4a3dec45938f71a94e6069229f9

85b6fdaca0c2bfef6581bcd3214b3c2e1c170f60

版权声明:本文中所有内容均属于阿里云开发者社区所有,任何媒体、网站或个人未经阿里云开发者社区协议授权不得转载、链接、转贴或以其他方式复制发布/发表。申请授权请邮件developerteam@list.alibaba-inc.com,已获得阿里云开发者社区协议授权的媒体、网站,在转载使用时必须注明"稿件来源:阿里云开发者社区,原文作者姓名",违者本社区将依法追究责任。 如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:developer2020@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:

分享阿里云支持与服务团队最佳实践、经典案例与故障排查。

官方博客
文档