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,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
2月前
|
存储 数据管理 Java
基于OSS、NFS构建高性能可扩展的遥感智能解译系统实践之路
该文探讨了构建高性能、可扩展的遥感智能解译系统的架构演进过程。作者强调架构应根据业务场景而定,而非追求单一的“最佳”架构。文章分为五个部分,介绍了从初步的业务场景分析到逐步优化的架构设计。 1. 业务场景描述了服务于地理信息行业的遥感数据管理平台,包括数据湖和遥感智能解译系统的功能和架构设计。 2. 初代系统解决了数据管理和智能解译的基本需求,但存在数据同步效率低下的问题。 3. 自动化阶段通过消息推送和数据接收模块减少了人工干预,将处理时间减半,但仍存在效率和稳定性问题。 4. 高性能阶段引入数据订阅/推送和数据接收Agent,实现了稳定、高速的数据传输,性能提升了6倍。
48767 2
|
2月前
|
安全 Go 开发工具
对象存储OSS产品常见问题之go语言SDK client 和 bucket 并发安全如何解决
对象存储OSS是基于互联网的数据存储服务模式,让用户可以安全、可靠地存储大量非结构化数据,如图片、音频、视频、文档等任意类型文件,并通过简单的基于HTTP/HTTPS协议的RESTful API接口进行访问和管理。本帖梳理了用户在实际使用中可能遇到的各种常见问题,涵盖了基础操作、性能优化、安全设置、费用管理、数据备份与恢复、跨区域同步、API接口调用等多个方面。
|
2月前
|
存储 监控 开发工具
对象存储OSS产品常见问题之python sdk中的append_object方法支持追加上传xls文件如何解决
对象存储OSS是基于互联网的数据存储服务模式,让用户可以安全、可靠地存储大量非结构化数据,如图片、音频、视频、文档等任意类型文件,并通过简单的基于HTTP/HTTPS协议的RESTful API接口进行访问和管理。本帖梳理了用户在实际使用中可能遇到的各种常见问题,涵盖了基础操作、性能优化、安全设置、费用管理、数据备份与恢复、跨区域同步、API接口调用等多个方面。
|
2月前
|
存储 JSON 前端开发
Javaweb之SpringBootWeb案例之阿里云OSS服务集成的详细解析
Javaweb之SpringBootWeb案例之阿里云OSS服务集成的详细解析
88 0
|
2月前
|
存储 开发工具 对象存储
Javaweb之SpringBootWeb案例之阿里云OSS服务入门的详细解析
Javaweb之SpringBootWeb案例之阿里云OSS服务入门的详细解析
60 0
|
2月前
|
存储 文字识别 安全
Javaweb之SpringBootWeb案例之阿里云OSS服务的详细解析
Javaweb之SpringBootWeb案例之阿里云OSS服务的详细解析
103 0
|
2月前
|
存储 移动开发 前端开发
对象存储oss使用问题之OSS SDK .net 使用下载例程报错如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
|
2月前
|
开发工具 对象存储 Android开发
对象存储oss使用问题之C++使用OSS SDK时遍历OSS上的文件时崩溃如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
|
9天前
|
存储 弹性计算 对象存储
预留空间是什么?阿里云OSS对象存储预留空间说明
阿里云OSS预留空间是预付费存储产品,提供折扣价以锁定特定容量,适用于抵扣有地域属性的Bucket标准存储费用及ECS快照费。通过购买预留空间,如500GB通用预留+100GB标准-本地冗余存储包,用户可优化成本。
|
1月前
|
SQL 分布式计算 DataWorks
DataWorks产品使用合集之如何将CSV文件从阿里云OSS同步到ODPS表,并且使用列作为表分区
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
DataWorks产品使用合集之如何将CSV文件从阿里云OSS同步到ODPS表,并且使用列作为表分区