OSS 实践篇-OSS C SDK 深度案例

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: 概述:客户使用 OSS C SDK 3.5 版本,通过 get_object_to_local_file 方法直接下载 OSS文件到本地,测试过程返回 403 签名不对;搜集信息挖取有价值的信息很重要,通过基础信息可以筛选下客户上传日志的详细描述,通过堆栈报错可以找到客户大概原因;OSS...

概述:

客户使用 OSS C SDK 3.5 版本,通过 get_object_to_local_file 方法直接下载 OSS文件到本地,测试过程返回 403 签名不对;

搜集信息

挖取有价值的信息很重要,通过基础信息可以筛选下客户上传日志的详细描述,通过堆栈报错可以找到客户大概原因;

  • OSS response header 中包含 requestID ,记录客户端请求到 OSS 的详细日志;
  • 堆栈完整报错信息;

分析 requestID 对应的服务端错误日志

服务端返回 4xx 2xx 3xx 500 的状态码都会返回 requestID;通过 requestID 我们可以过滤到服务的错误日志如下;

java
Method:HEAD    Host:oss-cn-shanghai.aliyuncs.com    URI:/vod%2Fplat%2Fupdate%2Fhaimu_21_9%2FBasketball.zip

StringToSign:HEAD\n\n\nWed, 06 Nov 2019 07:55:44 GMT\n/vod/plat/update/haimu_21_9/Basketball.zip
UserSignature:LIMmOQ/5TLs2Gk24MuNVRl+Lu0Q=    OssServerSignature:P+YZauMD+fRtZjeMWkauuN6A4eU=

ErrorCode:SignatureDoesNotMatch    ErrorMsg:The request signature we calculated does not match the signature you provided. Check your key and signing method.

image

  • 通过日志可以明显看出客户端签名和服务端签名不一致导致校验失败;
  • 根据签名算法可以知道这算计算签名的参数中 /vod/plat/update/haimu_21_9/Basketball.zip 其中 vod 是 bucket 的位置;
  • Host: oss-cn-shanghai.aliyuncs.com 这个位置是错误,因为正常的直接访问 OSS ,Host 正确写法应该是 bucket.oss-cn-region.aliyuncs.com(region 替换成 bucket 所在地区)

问题分析

线索一

已经知道问题出现在签名不对,而且 Host 也不对;问题出现在这里,但是如果 Host ,但 OSS 还能识别出 bucket ,这很奇怪;于是和用户沟通, vod 并不是用户的 bucket,那这个桶是怎么获取到的呢?遂让用户在端上进行 Wireshark 抓包, 得到报文

image

  1. 从报文中可以看到 Host 是客户端传的时候就没有 bucket ;
  2. 而 vod 是用户 objectkey 文件前缀而已;
  3. 通过上述几点可以知道问题一定是用户代码上哪里出现的变量写错或者用法不对;

线索二

请用户在本地 debug ,将关键签名的变量信息打印出来看是否完整;

关键信息位置

image

用户自己 debug 出来变量的位置

image

通过客户 debug 看到变量都正确,为什么还会出现 bucket “丢失” 的情况呢;

线索三

分析源码

int get_object_to_local_file(char *bucketname, char *objectname, char *filename)
{
    aos_pool_t *p = NULL;
    aos_string_t bucket;
    aos_string_t object;
    oss_request_options_t *options = NULL;
    aos_table_t *headers = NULL;
    aos_table_t *params = NULL;
    aos_table_t *resp_headers = NULL;
    aos_status_t *s = NULL;
    aos_string_t file;
    int is_cname = 1;

    if (bucketname == NULL || objectname == NULL || filename == NULL)
        return -1;

    aos_pool_create(&p, NULL);
    options = oss_request_options_create(p);
    init_sample_request_options(options, is_cname);
    aos_str_set(&bucket, bucketname);
    aos_str_set(&object, objectname);
    headers = aos_table_make(p, 0);
    aos_str_set(&file, filename);

    s = oss_get_object_to_file(options, &bucket, &object, headers,
        params, &file, &resp_headers);
    if (aos_status_is_ok(s))
    {
        printf("get object to local file succeeded\n");
    }
    else
    {
        printf("get object to local file failed\n");
        aos_pool_destroy(p);
        return -2;
    }
    aos_pool_destroy(p);
    return 0;
}

— —> 从源码中可以,getobject 下载时形参都是传进来的,既然客户 debug 的变量都是正确的,那么肯定不是传进来变量 ,问题一定是方法内的常量导致;对比官方源码:

void get_object_to_local_file()
{
    aos_pool_t *p = NULL;
    aos_string_t bucket;
    char *download_filename = "get_object_to_local_file.txt";
    aos_string_t object;
    int is_cname = 0;
    oss_request_options_t *options = NULL;
    aos_table_t *headers = NULL;
    aos_table_t *params = NULL;
    aos_table_t *resp_headers = NULL;
    aos_status_t *s = NULL;
    aos_string_t file;

    aos_pool_create(&p, NULL);
    options = oss_request_options_create(p);
    init_sample_request_options(options, is_cname);
    aos_str_set(&bucket, BUCKET_NAME);
    aos_str_set(&object, OBJECT_NAME);
    headers = aos_table_make(p, 0);
    aos_str_set(&file, download_filename);

    s = oss_get_object_to_file(options, &bucket, &object, headers, 
                               params, &file, &resp_headers);
    if (aos_status_is_ok(s)) {
        printf("get object to local file succeeded\n");
    } else {
        printf("get object to local file failed\n");
    }

    aos_pool_destroy(p);
}

— —> 从源码和用户的源码对比发现有个 cname 的参数,这个参数用户端是 1,官网的源码是 0,参数的含义,是否启用 cname 方式上传, cname 简称别名,比如用户给 bucket 绑定一个备案的域名后,那个域名就是 cname;我们追下 cname 的用法。

    if (options->config->is_cname ||
        is_valid_ip(raw_endpoint_str))
    {
        req->host = apr_psprintf(options->pool, "%.*s",
                raw_endpoint.len, raw_endpoint.data);
        req->uri = apr_psprintf(options->pool, "%.*s", bucket->len,
                                bucket->data);
    } else {
        req->host = apr_psprintf(options->pool, "%.*s.%.*s",
                bucket->len, bucket->data,
                raw_endpoint.len, raw_endpoint.data);
        req->uri = apr_psprintf(options->pool, "%s", "");
    }

— —> 从这端代码中可以看到,启用了 cname 后,Host 直接取的 endpoint 值;基本上找到了和用户用了 cname 有关系;

  • 经过后台分析发现用户端并没有绑定 oss+域名 的映射关系,而 SDK 在启动了 cname 上传,把 endpoint 当做完成的域名,没有把用户的 bucket name 拼到 Host 中,认为启用 cname 后, endpoint 就是完成域名;(设计就是这样并不是缺陷)
  • 让用户把 cname 改为 0 ,采用直接的方式,这样 SDK 会把 bucketname 和 endpoint 拼成一个 完成域名再上传;

总结

该问题核心在于

1、要对 OSS SDK 的用法熟悉,知道如何进行本地对比用户测试;

2、要清楚排查思路知道搜集哪些有价值的信息;

3、层级递进,从签名算法着眼,推测到是代码中的使用;

4、善用 tcpdump/wireshark 抓包分析请求报文;

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
30天前
|
存储 JavaScript 前端开发
oss使用SDK上传文件
oss使用SDK上传文件
103 2
|
2天前
|
存储 移动开发 前端开发
对象存储oss使用问题之OSS SDK .net 使用下载例程报错如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
18 0
|
1月前
|
Rust API 开发工具
Rust初学者,边学边写的OSS的sdk,欢迎批评指正 :)
`Rust`语言编写的阿里云OSS的SDK,依据官方文档并参考了其他语言的实现。
212 5
Rust初学者,边学边写的OSS的sdk,欢迎批评指正 :)
|
2月前
|
对象存储
阿里云oss-cloud-sdk-springboot3兼容问题
阿里云oss-cloud-sdk-springboot3兼容问题
70 0
|
4月前
|
存储 DataWorks 开发工具
在DataWorks中,可以使用Python SDK操作阿里云OSS存储服
在DataWorks中,可以使用Python SDK操作阿里云OSS存储服
134 1
|
Web App开发 JavaScript PHP
【视频点播最佳实践】使用OSS SDK上传视频到点播
场景 点播上传SDK缺乏需要的语言版本(如C/C++、Go等)或相应的功能(如网络流上传、追加上传),可以直接使用OSS的SDK进行上传。 准备工作 确认已开通点播服务并完成了相关配置。确认已准备了阿里云账号AK,并授予了上传权限。
9605 0
|
1月前
|
Java API 开发工具
如何用阿里云 oss 下载文件
阿里云对象存储服务(OSS)提供了多种方式下载文件,以下讲解下各种方式的下载方法
749 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
|
30天前
|
弹性计算 前端开发 小程序
微信小程序上传文件至阿里云OSS直传(java后端签名+前端直传)
当前的通用文件上传方式是通过前端上传到服务器,再由服务器转存至对象存储。这种方式在处理小文件时效率尚可,但大文件上传因受限于服务器带宽,速度较慢。例如,一个100MB的文件在5Mbps带宽的阿里云ECS上上传至服务器需160秒。为解决此问题,可以采用后端签名的方式,使微信小程序直接上传文件到阿里云OSS,绕过服务器中转。具体操作包括在JAVA后端引入相关依赖,生成签名,并在微信小程序前端使用这个签名进行文件上传,注意设置正确的请求头和formData参数。这样能提高大文件上传的速度。

热门文章

最新文章