OSS signature 计算

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: 场景 通过多个语言版本 OSS SDK 测试,在使用 CDN 结合 OSS 用法时,客户端使用 CDN 域名计算 signature,发起 HEAD 请求,OSS 收到后返回 403 ; 分析: 出现这个问题不区分什么 SDK 都会出现,问题原因是由于客户端发起的 HEAD 请求在通过 CDN 回原到 OSS 时,CDN 回原是用的 GET 请求,而 OSS 收到时就用 GET 请求方式去计算签名,得到的结果肯定和客户端计算不一致,可以升级到阿里云 CDN 处理。

背景

出现 signature 一般出现客户端自签名调 API 的操作中, signature 的计算稍微复杂点,建议最好用 SDK 来替代计算的过程和多样性。如果业务强需求,先要读懂如果计算 signature。

签名分类

Header 头中携带签名。

https://help.aliyun.com/document_detail/31951.html?spm=a2c4g.11174283.6.1078.40437da2HGkyMH

URL 中携带签名。

https://help.aliyun.com/document_detail/31952.html?spm=a2c4g.11186623.6.1079.7b61734cNAir2U

签名区别

Header URL
不支持设置 expires 支持设置 expires
常用 method GET、POST、PUT 常用 method GET、PUT
date 时间是 GMT 格式 date 替换成 expires 变成时间戳
signature 不需要 URL encode signature 需要 URL encode

计算签名 demo

当客户通过 header 或者 URL 中自签名计算 signature 时,经常会遇到计算签名失败 “The request signature we calculated does not match the signature you provided” ,可以参考以下 demo 演示了如何调用 API 自签名时上传 Object 到 OSS,注意签名和 header 加入的内容。

#! /us/bin/envy python
#Author: hanli
#Update: 2018-09-29

from optparse import OptionParser
import urllib, urllib2
import datetime
import base64
import hmac
import sha
import os
import sys
import time


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.left = '\033[1;31;40m'
    self.right = '\033[0m'
    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):
        self.PutObject()
    else:
      self.ConsoleLog("error","Input parameters cannot be empty")

  # GET local GMT time

  def GetGMT(self):
  
    SRM = datetime.datetime.utcnow()
    GMT = SRM.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 as e:
      self.ConsoleLog("error",e)
  
    try:
      request = urllib2.Request(self.url, files)
      request.add_header('Host','{0}.{1}'.format(self.bk,self.ed))
      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)
      fd.close()
      self.ConsoleLog(response.code,response.headers)
    except Exception,e:
      self.ConsoleLog("error",e)
 
  # output error log

  def ConsoleLog(self,level=None,mess=None):

    if level == "error":
      sys.exit('{0}[ERROR:]{1}{2}'.format(self.left,self.right,mess))
    else:
      sys.exit('\nHTTP/1.1 {0} OK\n{1}'.format(level,mess))

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 uploaded to oss")
  parser.add_option("-f",dest="fi",help="Must fill localfile path")

  (options, args) = parser.parse_args()
  handler = Main(options)
  handler.CheckParse()

请求头:

PUT /yuntest HTTP/1.1
Accept-Encoding: identity
Content-Length: 147
Connection: close
User-Agent: Python-urllib/2.7
Date: Sat, 22 Sep 2018 04:36:52 GMT
Host: yourBucket.oss-cn-shanghai.aliyuncs.com
Content-Type: application/x-www-form-urlencoded
Authorization: OSS B0g3mdt:lNCA4L0P43Ax

响应头:

HTTP/1.1 200 OK
Server: AliyunOSS
Date: Sat, 22 Sep 2018 04:36:52 GMT
Content-Length: 0
Connection: close
x-oss-request-id: 5BA5C6E4059A3C2F
ETag: "D0CAA153941AAA1CBDA38AF"
x-oss-hash-crc64ecma: 8478734191999037841
Content-MD5: 0MqhU5QbIp3Ujqqhy9o4rw==
x-oss-server-time: 15

注意

  • Signature 中所有加入计算的参数都要放在 header 中,保持 header 和 Signature 一致。
  • PUT 上传时,Signature 计算的 Content-Type 必须是 application/x-www-form-urlencoded 。
  • 通过header 方式进行签名认证时无法设置过期时间。目前只有 SDK 、URL 签名支持设置过期时间。

使用问题

案例:通过微信小程序请求 OSS 返回签名失败,通过浏览器正常

分析:

  • 只要通过浏览器访问,鉴权通过就证明 OSS 的签名校验是正常的没有问题,可以先排除掉 OSS 端。
  • 客户端一定要在微信小程序上部署 HTTP 抓包,对后续分析很重要,抓包中可以看到所有的请求头和请求参数。
  • 通过浏览器访问时的 HTTP 抓包。

5

  • 通过 403 和 200 的抓包反复对比发现,通过小程序发出的 HTTP 请求和浏览器发起的 HTTP 请求的 URL 、signature、expires 都一样,唯一的区别就是微信小程序携带了 Content-type ,而通过 Chrom 的请求是没有携带 Content-type,怀疑矛头指向了这里。
  • 经过代码确认,发现 signature 计算时是没有包含 Content-tpye 头的,而小程序发起的请求携带的 Content-tpye ,OSS 收到后会按照携带了 Content-tpye 去计算 signature ,所以每次计算都不一样。

遇到类似问题,抓包是最能快速看到问题的。同时也必须要了解下 OSS 请求 header 中携带了 Content-tpye ,那么 signature 计算就要加上 Content-tpye ,保持一致。

案例:通过多个语言版本 OSS SDK 测试,在使用 CDN 结合 OSS 用法时,客户端使用 CDN 域名计算 signature,发起 HEAD 请求,OSS 收到后返回 403 ;

1

分析:

出现这个问题不区分什么 SDK 都会出现,问题原因是由于客户端发起的 HEAD 请求在通过 CDN 回原到 OSS 时,CDN 回原是用的 GET 请求,而 OSS 收到时就用 GET 请求方式去计算签名,得到的结果肯定和客户端计算不一致,可以升级到阿里云 CDN 处理。以上分析只适合上述场景。

问题可以通过 tcpdump 抓包或者 Wireshark 对比一下即可知道。

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
1月前
|
Java API 开发工具
如何用阿里云 oss 下载文件
阿里云对象存储服务(OSS)提供了多种方式下载文件,以下讲解下各种方式的下载方法
756 1
|
27天前
|
存储 安全 对象存储
手把手教你搭建阿里云图床(PicGo+Typora+阿里云OSS),新手小白一看就会
本文详细介绍了怎样帮助新手小白从注册,购买阿里云OSS,到一步一步配置OSS做为图床,和PicGo、Typora软件连接,配置好关联之后,在使用Typora写文章时,如果需要插入图片,只需要将图片复制粘贴到Typora的编辑区域,就会自动通过PicGo上传到指定图床,自动复制外网能访问的URL并展示,简直不要太方便,极大的解决了编辑文章时复制处理图片链接的痛点。
147 2
手把手教你搭建阿里云图床(PicGo+Typora+阿里云OSS),新手小白一看就会
|
2月前
|
对象存储
minio临时凭证直传切换到阿里云oss
minio临时凭证直传切换到阿里云oss
170 1
|
4月前
|
存储 测试技术 区块链
阿里云、百度云及移动云对象存储横向性能对比测试
在企业的数字化转型进程中,我们观察到越来越多的公司将其IT基础设施迁移到云端。随着企业业务的持续运营,无论是储存、处理、分享还是删除,都会产生大量的数据,这就要求有一个既可靠又高效的系统来管理和存储这些信息。对象存储产品在这个场景中扮演了至关重要的角色。它们以一种可扩展、安全、持久的方式,有效地满足了对大规模非结构化数据存储的需求。 尽管市场上云计算提供商众多,各自都有自己独特的对象存储产品,面对这样的丰富选择,如何寻找最符合企业需求的产品呢?这正是企业今天寻求解答的问题。 在本篇文章中,我们将深入进行一项横向对比测试,专门对阿里云OSS、百度云BOS和移动云EOS这三大云服务提供商的对象
1358 0
|
30天前
|
弹性计算 前端开发 小程序
微信小程序上传文件至阿里云OSS直传(java后端签名+前端直传)
当前的通用文件上传方式是通过前端上传到服务器,再由服务器转存至对象存储。这种方式在处理小文件时效率尚可,但大文件上传因受限于服务器带宽,速度较慢。例如,一个100MB的文件在5Mbps带宽的阿里云ECS上上传至服务器需160秒。为解决此问题,可以采用后端签名的方式,使微信小程序直接上传文件到阿里云OSS,绕过服务器中转。具体操作包括在JAVA后端引入相关依赖,生成签名,并在微信小程序前端使用这个签名进行文件上传,注意设置正确的请求头和formData参数。这样能提高大文件上传的速度。
|
3月前
|
存储 Java 对象存储
springboot配置阿里云OSS存储实现文件上传下载功能
【1月更文挑战第1天】springboot配置阿里云OSS存储实现文件上传下载功能
526 2
|
3月前
|
Cloud Native Java 开发工具
云原生 阿里云分布式文件系统 对象存储OSS 服务配置
【1月更文挑战第8天】云原生 阿里云分布式文件系统 对象存储OSS 服务配置
|
3天前
|
存储 Java API
阿里云oss简介和使用流程
本文档介绍了如何准备阿里云OSS(对象存储服务)并开始使用它。首先,需要注册阿里云账号并进行实名认证,然后购买OSS资源包。在阿里云控制台中,可以创建和管理OSS存储空间(称为“Bucket”)。接着,文章简要介绍了阿里云OSS,它是一个基于云端的对象存储服务,提供高可靠性、高性能、低成本和易于使用的特性。 在阿里云OSS控制台,用户可以进行文件的上传和下载操作。通过API,开发者可以使用各种编程语言(如Java)来创建、删除Bucket以及上传、下载和删除文件。例如,Java代码示例展示了如何创建Bucket、上传文件、删除文件以及下载文件到本地的操作。
|
10天前
|
开发工具 对象存储
阿里云OSS文件上传
阿里云OSS文件上传
52 0
|
10天前
|
存储 缓存 Java
阿里云OSS实战从入门到大神
说起阿里云OSS,那作用和功能都是非常强大的,它可以存放图片,音频,视频等资源文件,这些资源文件,你不必存放到服务器的硬盘里,这样既可以节省服务器硬盘空间,又可以降低服务器的读写压力,非常适合大并发的架构。
51 0