OSS 实践篇-OSS API 鉴权剖析

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000 次 1年
简介: 出现 signature 一般出现客户端自签名调 API 的操作中, signature 的计算稍微复杂点,建议最好用 SDK 来替代计算的过程和多样性。如果业务强需求,先要读懂如果计算 signature。

背景

使用过阿里云 OSS 存储 API 的用户都知道,如果 OSS 是私有的权限,需要进行验签才能访问。验签过程要求客户端请求的 http request header 中有一个 Authorization(鉴权) 的 header,计算的复杂性和带来的很多问题让客户头痛不已,尤其 OSS Authorization 头的计算,今天带这大家剖析下鉴权的 API。

使用规范预热

官网鉴权文章:
header 签名
[URL 签名](URL 中携带签名。
https://help.aliyun.com/document_detail/31952.html)
PutObject 规范

签名区别

Header URL
不支持设置 expires ,但是要求请求时间不能超过 15min 支持设置 expires
常用 method GET、POST、PUT 常用 method GET、PUT
Date 时间是 GMT 格式 Date 替换成 expires 变成时间戳
signature 不需要 URL encode signature 需要 URL encode

鉴权名词

AccessKey

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

Access Key Secret

简称 SK,访问云产品的秘钥,类似宝藏的钥匙,可以是主账号或者 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 等操作。

主账号 AK SK 获取方式

image.png

子账号 AK SK获取方式

进入到 RAM 访问控制台,找到对应的子账号

image.png

计算鉴权

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

使用方法

$PSA1#: python Signature.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        本地文件的名称
#! /us/bin/env 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

注意事项

1、Signature 中所有加入计算的参数都要放在 header 中,保持 header 和 Signature 一致。

2、PUT 上传时,Signature 计算的 Content-Type 必须是 application/x-www-form-urlencoded 。

3、通过header 方式进行签名认证时无法设置过期时间。目前只有 SDK 、URL 签名支持设置过期时间。

4、用户想要保证文件一致性,可以在请求头增加 Content-MD5,但是不注意的人就会忘记加了,补充如下:根据协议 RFC 1864 对消息内容(不包括头部)计算 MD5 值获得 128 比特位数字,对该数字进行 base64 编码为一个消息的 Content-MD5 值,并且 MD5 是 大写。

5、如果用户想要单独加项目 CanonicalizedOSSHeaders 一定要记得不仅在 Header 中加,你的 hmac 计算时也要加

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)

6、如果遇到 client 计算的 MD5 和 Server 不一致的情况请直接使用 HTTPS 传输,很可能中间的网络设置有故障或者劫持时导致内存被篡改,只要将 url 改为 https:// 就是启动 HTTPS 协议 上传/ 下载 了。

常见案例

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

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

image.png

结论:

1、通过 403 和 200 的抓包反复对比发现,通过小程序发出的 HTTP 请求和浏览器发起的 HTTP 请求的 URL 、signature、expires 都一样,唯一的区别就是微信小程序携带了 Content-type ,而通过 Chrom 的请求是没有携带 Content-type,怀疑矛头指向了这里。
2、经过代码确认,发现 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

image.png

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

相关实践学习
通义万相文本绘图与人像美化
本解决方案展示了如何利用自研的通义万相AIGC技术在Web服务中实现先进的图像生成。
目录
相关文章
|
2月前
|
自然语言处理 供应链 前端开发
深度解析与技术实践:高效调用淘宝商品评论API的策略与代码实现
本文深入解析淘宝开放平台商品评论接口(Taobao.item_review),涵盖接口功能、调用逻辑与实战代码,助力开发者高效获取用户评价数据,提升电商数据分析能力。
|
3月前
|
缓存 监控 搜索推荐
电商生态协同的关键:API接口在电商数据对接中的应用与实践
电商数据对接API接口是连接电商平台与外部系统的智慧桥梁,通过标准化协议实现商品管理、订单处理、支付结算、物流追踪及数据分析等全链路支持。本文从核心功能、对接流程、应用场景和优化策略四个方面解析其技术逻辑与实践路径。API接口助力店铺管理自动化、精准营销与跨境电商全链路管理,同时通过安全防护、性能调优与合规管理提升效能,推动电商行业向智能化、高效化发展。
|
3月前
|
人工智能 自然语言处理 API
电商API技术文档编写规范白皮书:方法论与行业实践
本文系统阐述电商API接口文档的编写规范与最佳实践,涵盖结构设计、技术语言、开发者体验、版本控制及质量保障等方面,助力企业提升开发效率,构建开放共赢的电商生态。
|
4月前
|
机器学习/深度学习 JSON 算法
京东拍立淘图片搜索 API 接入实践:从图像识别到商品匹配的技术实现
京东拍立淘图片搜索 API 是基于先进图像识别技术的购物搜索接口,支持通过上传图片、URL 或拍摄实物搜索相似商品。它利用机器学习和大数据分析,精准匹配商品特征,提供高效、便捷的搜索体验。接口覆盖京东海量商品资源,不仅支持外观、颜色等多维度比对,还结合用户行为数据实现智能推荐。请求参数包括图片 URL 或 Base64 编码,返回 JSON 格式的商品信息,如 ID、价格、链接等,助力消费者快速找到心仪商品,满足个性化需求。
321 18
|
2月前
|
数据采集 缓存 JSON
1688商品API全链路开发实践
本文介绍了对接1688开放平台的核心要点,涵盖OAuth2.0认证流程、商品列表接口调用技巧、高并发优化策略及异常处理清单。内容包含获取access_token示例、隐藏参数解析、数据清洗方案与缓存设计,并强调合规调用注意事项。
1688商品API全链路开发实践
|
4月前
|
算法 搜索推荐 API
京东拍立淘图片搜索 API 接口使用指南:从原理到实践
京东拍立淘图片搜索API,基于先进图像识别技术,支持上传图片、URL或拍摄实物搜索相似商品。其特点包括:搜索便捷高效,用户可快速发起搜索;精准匹配结果,通过算法捕捉商品特征确保准确;数据覆盖广泛,依托京东海量商品资源满足个性化需求;智能推荐拓展,根据用户行为挖掘潜在需求,提升购物体验。
|
5月前
|
监控 测试技术 数据库连接
利用 RunnerGo 深度探索 API 性能测试:从理论到实践
API性能测试是保障应用稳定性和用户体验的关键环节。本文详细探讨了如何使用RunnerGo全栈测试平台进行高效API性能测试,涵盖测试计划创建、场景设计、参数配置到执行与分析全过程。通过电商平台促销活动案例,展示了高并发下的测试策略与优化措施,如代码与数据库查询优化、数据库连接池扩容、服务器资源配置调整及缓存策略实施等。最终显著提升系统性能,满足高并发需求。API性能测试需持续关注与优化,以适应业务发展和用户需求变化。
208 33
|
6月前
|
人工智能 缓存 自然语言处理
构建智能天气助手:基于大模型API与工具函数的调用实践
在人工智能快速发展的今天,大语言模型(LLM)已经成为构建智能应用的重要基础设施。本文将介绍如何利用大模型API和工具函数集成,构建一个能够理解自然语言并提供精准天气信息的智能助手。
721 11
|
6月前
|
存储 Cloud Native 安全
API 安全之认证鉴权
API 作为企业的重要数字资源,在给企业带来巨大便利的同时也带来了新的安全问题,一旦被攻击可能导致数据泄漏重大安全问题,从而给企业的业务发展带来极大的安全风险。
|
6月前
|
关系型数据库 数据库 对象存储
Dify实践|Dify on DMS+对象存储OSS,实现多副本部署方案
本文介绍了在DMS上部署Dify的详细步骤,用户可选择一键购买资源或基于现有资源部署Dify,需配置RDS PostgreSQL、Redis、AnalyticDB for PostgreSQL等实例,并设置存储路径和资源规格。文中还提供了具体配置参数说明及操作截图,帮助用户顺利完成部署。