开发者社区> 问答> 正文

oss上传文件 模拟http头请求数字签名验证失败

c#   我模拟http put提交 通过socket 直接发送请求 但是不对 为什么 每个地方都对的啊 求指点

private void button1_Click(object sender, EventArgs e)
        {
          
          
            FileInfo file = new FileInfo(@"E:\Cshap_text\PublishUpdate\PublishUpdate\bin\Debug\2.jpg");
        
            string dtime = DateTime.Now.AddHours(-8).ToString("r");
            StringBuilder httpHeader = new StringBuilder();
          //构造http头
            httpHeader.Append("PUT /2.jpg HTTP/1.1\r\n");
            httpHeader.Append("Host:bucketdataupdate.oss-cn-beijing.aliyuncs.com\r\n");
            httpHeader.Append("Content-Encoding:utf-8\r\n");
            httpHeader.Append("Content-Disposition: attachment;filename=2.jpg\r\n");
            httpHeader.Append("Date:" + dtime + "\r\n");
            httpHeader.Append("Content-Type:image/jpg\r\n");
            httpHeader.Append("Content-Length:" + file.Length + "\r\n");
        
        //构造oss Authorization验证
            HMACSHA1 hmacsha1 = new HMACSHA1();
            hmacsha1.Key = Encoding.UTF8.GetBytes("我的key密码");
            StringBuilder mk = new StringBuilder();
            mk.Append("PUT\n");
            string md5 = GetMD5HashFromFile(@"E:\Cshap_text\PublishUpdate\PublishUpdate\bin\Debug\2.jpg");
            mk.Append(md5 + "\n");
            mk.Append("image/jpg\n");
            mk.Append(dtime + "\n");
            mk.Append("\n");
            mk.Append("/bucketdataupdate/2.jpg\n");
            byte[] dataBuffer = Encoding.UTF8.GetBytes(mk.ToString());
            byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
            string base64 = Convert.ToBase64String(hashBytes);
          
            httpHeader.Append("Authorization:OSS 我的keyID:" + base64 + "\r\n");
           //头部构造完毕
            httpHeader.Append("\r\n");
            byte[] header = Encoding.UTF8.GetBytes(httpHeader.ToString());
            Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            client.Connect("bucketdataupdate.oss-cn-beijing.aliyuncs.com", 80);
            client.Send(header);
            client.SendFile(@"E:\Cshap_text\PublishUpdate\PublishUpdate\bin\Debug\2.jpg");
            byte[] buffer = new byte[1024];

            client.Receive(buffer);
            string msg = Encoding.UTF8.GetString(buffer);
        

        }
这个msg 值是下面的 的东东 验证失败 我就没搞懂 我都是按照api做的啊 怎么会验证失败哦?什么地方写错了还是那个地方没有对 求指点
HTTP/1.1 403  Forbidden
Server: AliyunOSS
Date: Wed, 11 Nov 2015 03:40:50 GMT
Content-Type: application/xml
Content-Length: 810
Connection: keep-alive
x-oss-request-id: 5642B8C21FE4E74D7C6EDFA4

<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>SignatureDoesNotMatch</Code>
  <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
  <RequestId>5642B8C21FE4E74D7C6EDFA4</RequestId>
  <HostId>bucketdataupdate.oss-cn-beijing.aliyuncs.com</HostId>
  <OSSAccessKeyId>9Q619M9E5sL1ZtEb</OSSAccessKeyId>
  <SignatureProvided>q880m3K4MezNpplFpk5N+7jyWHU=</SignatureProvided>
  <StringToSign>PUT

image/jpg
Wed, 11 Nov 2015 03:40:49 GMT
/bucketdataupdate/2.jpg</StringToSign>
  <StringToSignBytes>50 55 54 0A 0A 69 6D 61 67 65 2F 6A 70 67 0A 57 65 64 2C 20 31 31 20 4E 6F 76 20 32 30 31 35 20 30 33 3A 34 30 3A 34 39 20 47 4D 54 0A 2F 62 75 63 6B 65 74 64 61 74 61 75 70 64 61 74 65 2F 32 2E 6A 70 67 </StringToSignBytes>
</Error>
HTTP/1.1 400

展开
收起
小白程序员 2015-11-11 11:43:33 16085 0
3 条回答
写回答
取消 提交回答
  • 回 楼主小白程序员的帖子
    我试了 去掉"/bucketdataupdate/2.jpg"后面的"\n"
    dtime后面 加了\n的
    运行还是同样的错误

    我把生成的头贴出来:
    PUT /2.jpg HTTP/1.1
    Host:bucketdataupdate.oss-cn-beijing.aliyuncs.com
    Content-Encoding:utf-8
    Content-Disposition: attachment;filename=2.jpg
    Date:Wed, 11 Nov 2015 05:50:29 GMT
    Content-Type:image/jpg
    Content-Length:176853
    Authorization:OSS 我的idkey:FNpk4LN0ZMgxktXiDw+WTXxx2SI=


    Authorization验证头:
    PUT
    0925f7b63fd62bbbc9db313676681658
    image/jpg
    Wed, 11 Nov 2015 05:50:29 GMT

    /bucketdataupdate/2.jpg

    -------------------------

    回 1楼姜恒的帖子

    还是不行 怎么办啊 你有qq吗加一个

    -------------------------

    回 2楼shinenuaa的帖子
    这个并没有什么用啊

    -------------------------

    回 8楼姜恒的帖子
    谢谢 指点 请求成功了 正确的Authorization
    应该是
    string mk = "PUT\n"                                          //VERB
                   + "\n"                                                 //CONTENT-MD5如果不需要验证内容 也必须加"\n"
                    + "image/jpg\n"                                 //CONTENT-TYPE
                    + dtime + "\n"                                   // DATE 服务器时间似乎不是北京时间 必须用当前时间减8个小时的时间 请求
                    + "/bucketdataupdate/6.jpg";           //访问的OSS资源

    但是又出一个问题 为什么我加上6.jpg的MD5 就验证不通过?是不是服务器端 求MD5的方式和我的不一样? 但是我求出来的md5绝对没有问题 因为我的系统右键属性可以看到文件的md5值 和我求出来的一样。为什么加上 就不行了呢?


    string fileMD5 = GetMD5HashFromFile(file.FullName);
                string mk = "PUT\n"
                   + fileMD5+"\n"
                    + "image/jpg\n"
                    + dtime + "\n"
                    + "/bucketdataupdate/6.jpg";

    这样就不可以 不加md5 就对  why?

    -------------------------

    Reoss上传文件 模拟http头请求数字签名验证失败
    谢谢大家问题终于全部解决了  
    研究了两天 现在分享出来 希望以后有人遇到这样的问题 可以很快的搞定
    string fileMD5 = GetMD5HashFromFile(file.FullName);
                string mk = "PUT\n"
                   + fileMD5+"\n"
                    + "image/jpg\n"
                    + dtime + "\n"
                    + "/bucketdataupdate/6.jpg";

    HTTP的Content-MD5并不是单纯的文件的MD5 ,是遵循rfc1864标准(就是把md5的二进制转换成base64)。
    所以上面的那个直接加fileMD5是错误的
    由于http首部无法记录二进制值 所以必须通过base64处理
    如果需要MD5验证 http头也需要加上Content-md5:值  这个字段


    直接上源码:
    const string accessId = "我的keyid";
            const string accessKey = "我的keypass";
            const string endpoint = "http://oss-cn-beijing.aliyuncs.com";
            const string bucketName = "bucketdataupdate";
    private void button1_Click(object sender, EventArgs e)
            {
              
                
                FileInfo file = new FileInfo(@"E:\Cshap_text\PublishUpdate\PublishUpdate\bin\Debug\2.jpg");
               byte[] fileMD5 = GetMD5HashByteFromFile(file.FullName);//这个地方得到的是md5的byte形式 不要转成16进制字符串
                string base64FileMd5 = Convert.ToBase64String(fileMD5);
            //由于服务器时间比本地时间晚8个小时 所以要减去8
                string dtime = DateTime.Now.AddHours(-8).ToString("r");
                StringBuilder httpHeader = new StringBuilder();
                httpHeader.Append("PUT /2.jpg HTTP/1.1\r\n");
                httpHeader.Append("Host:bucketdataupdate.oss-cn-beijing.aliyuncs.com\r\n");
              
                httpHeader.Append("Content-Md5:"+base64FileMd5 +"\r\n");
                httpHeader.Append("Content-Encoding:utf-8\n");
                httpHeader.Append("Content-Disposition: attachment;filename=2haha.jpg\r\n");
                httpHeader.Append("Date:" + dtime + "\r\n");
                httpHeader.Append("Content-Type:image/jpg\r\n");
                httpHeader.Append("Content-Length:" + file.Length + "\r\n");


              

                HMACSHA1 hmacsha1 = new HMACSHA1();
                hmacsha1.Key = Encoding.UTF8.GetBytes("我的keyPass");
            
                string mk = "PUT\n"
                      //0925F7B63FD62BBBC9DB313676681658
                   + base64FileMd5 + "\n"
                    + "image/jpg\n"
                    + dtime + "\n"
                    + "/bucketdataupdate/2.jpg";
                byte[] dataBuffer = Encoding.UTF8.GetBytes(mk);
                byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
                string base64 = Convert.ToBase64String(hashBytes);
              

                httpHeader.Append("Authorization:OSS 我的keyid:" + base64 + "\r\n");
                httpHeader.Append("\r\n");
                byte[] header = Encoding.UTF8.GetBytes(httpHeader.ToString());
                Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                client.Connect("bucketdataupdate.oss-cn-beijing.aliyuncs.com", 80);
                client.Send(header);
                FileStream fs = new FileStream(@"E:\Cshap_text\PublishUpdate\PublishUpdate\bin\Debug\2.jpg", FileMode.Open);
                byte[] buffer = new byte[1024];
                int redSize = 0;
                while ((redSize = fs.Read(buffer, 0, buffer.Length)) > 0)
                {
                    client.Send(buffer,0,redSize,SocketFlags.None);
                }
                fs.Close();
                //client.SendFile(@"E:\Cshap_text\PublishUpdate\PublishUpdate\bin\Debug\2.jpg");
                byte[] recbuffer = new byte[1024];

                client.Receive(recbuffer);
                string msg = Encoding.UTF8.GetString(recbuffer);
                client.Close();

            }

    private static byte[] GetMD5HashByteFromFile(string fileName)
            {
                try
                {
                    FileStream file = new FileStream(fileName, FileMode.Open);
                    System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                    byte[] retVal = md5.ComputeHash(file);
                    file.Close();
                    return retVal;
                }
                catch (Exception ex)
                {
                    throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
                }
            }
            private static string GetMD5HashStringFromFile(string fileName)
             {
             try
             {
             FileStream file = new FileStream(fileName, FileMode.Open);
             System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
             byte[] retVal = md5.ComputeHash(file);
             file.Close();
            
            StringBuilder sb = new StringBuilder();
             for (int i = 0; i < retVal.Length; i++)
             {
             sb.Append(retVal .ToString("x2"));
             }
             return sb.ToString();
             }
             catch (Exception ex)
             {
             throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
             }
             }
        }




    2015-11-11 13:52:01
    赞同 展开评论 打赏
  • 回 楼主(小白程序员) 的帖子
    用这个进行调试,http://oss-demo.aliyuncs.com/signature-demo/signature-demo.html
    2015-11-11 13:48:34
    赞同 展开评论 打赏
  • Reoss上传文件 模拟http头请求数字签名验证失败
    LZ你好, 返回的错误信息中, “<StringToSign>"这里面的内容是说, 服务器端用来加密的字符串。 通过对比下你上传时用以加密的字符串,我发现lz在这个地方有点小问题:
    mk.Append(dtime + "\n");
    mk.Append("\n");
    mk.Append("/bucketdataupdate/2.jpg\n");

    dtime后面应该是一个"\n",
    最后的"/bucketdataupdate/2.jpg"后面不应该加"\n".

    lz再试下,如有问题,可以继续在这里提问。

    -------------------------

    Reoss上传文件 模拟http头请求数字签名验证失败
    LZ, 可以加旺旺 @正柯

    -------------------------

    Reoss上传文件 模拟http头请求数字签名验证失败
    mk.Append(dtime + "\n");  
    mk.Append("\n");  
    mk.Append("/bucketdataupdate/2.jpg\n");  

    -------------------------

    Reoss上传文件 模拟http头请求数字签名验证失败
    抱歉,上一条没发完整。
    mk.Append(dtime + "\n");  
    mk.Append("\n");  
    mk.Append("/bucketdataupdate/2.jpg");  
    这条中间语句的"\n"不用加了, 即需要签名的字符串中,在dtime之后紧接着下一行应该是 “/bucketdataupdate/2.jpg”
    具体可参考 https://docs.aliyun.com/?spm=5176.383663.13.7.zNTX5D#/pub/oss/api-reference/access-control&signature-header中的 “Authorization字段计算的方法”

    -------------------------

    Reoss上传文件 模拟http头请求数字签名验证失败
    lz, put object时的md5是指 Conten-MD5, 是需要先对文件做md5操作,得到128比特位的数字,然后对该数字进行base64编码得到的,请参考官网文档中关于 Conten-MD5的说明。
    https://docs.aliyun.com/?spm=5176.383663.13.7.zNTX5D#/pub/oss/api-reference/object&PutObject

    def get_md5():
        if sys.version_info >= (2, 6):
            import hashlib
            hash = hashlib.md5()
        else:
            import md5
            hash = md5.new()
        return hash

        m = get_md5()
        d = fd.read()
        m.update(d)
        md5string = m.hexdigest()
        base64md5 = base64.encodestring(m.digest()).strip()
        return md5string, base64md5
    用户可以参考这段python代码了解如何计算Conten-MD5
    2015-11-11 13:08:29
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
OSS运维进阶实战手册 立即下载
《OSS运维基础实战手册》 立即下载
OSS运维基础实战手册 立即下载