带有 Google 存储的 C# - 带有客户加密密钥的签名 URL

Posted

技术标签:

【中文标题】带有 Google 存储的 C# - 带有客户加密密钥的签名 URL【英文标题】:C# with Google Storage - Signed URL with customer encryption key 【发布时间】:2019-01-27 10:36:27 【问题描述】:

我将文件上传到 Google 存储桶。现在,我生成了它的签名网址(基于此solution)

private static Uri SignUrl(Stream jsonCertificateStream, string bucketName, string objectName, TimeSpan expireAfter, string[] scopes, HttpMethod verb)

    string url;
    var urlSigner = UrlSigner.FromServiceAccountData(jsonCertificateStream);
    url = urlSigner.Sign(
                bucketName,
                objectName,
                expireAfter,
                verb);

    return new Uri(url);

我得到了一个在我的浏览器上运行良好的 URI。到这里——一切都很好。

现在,我正在使用客户加密密钥来加密我上传的文件。所以,我删除了文件并再次上传 - 现在它已加密。

问题是现在SignUrl() 方法不再起作用了。

使用浏览器测试SignUrl() 方法的结果时 - 我得到:

<Error>
    <Code>ResourceIsEncryptedWithCustomerEncryptionKey</Code>
    <Message>
        The resource is encrypted with a customer encryption key.
    </Message>
    <Details>
        The requested object is encrypted by a customer-supplied encryption key.
    </Details>
</Error>

我猜是因为我的文件是用其他密钥加密的。

怎么做才对?

【问题讨论】:

【参考方案1】:

基于 Customer-Supplied Encryption Keys documentation ,使用客户提供的加密密钥时需要添加以下标头

+------------------------------+--------+------------------------------------------------------------------------------+
|         Header name          | Value  |                                 Description                                  |
+------------------------------+--------+------------------------------------------------------------------------------+
| x-goog-encryption-algorithm  | string | The encryption algorithm to use. You must use the value AES256.              |
| x-goog-encryption-key        | string | An RFC 4648 Base64-encoded string of your AES-256 encryption key.            |
| x-goog-encryption-key-sha256 | string | An RFC 4648 Base64-encoded string of the SHA256 hash of your encryption key. |
+------------------------------+--------+------------------------------------------------------------------------------+

在使用 urlSigner 时,您还必须通过 x-goog-encryption-algorithm

这里是代码示例

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Google.Cloud.Storage.V1;
using System.IO;
using System.Net.Http;
using Google.Apis.Auth.OAuth2;

namespace ***54387198

    class Program
    
        static void Main(string[] args)
        

            // step 1 create customer encryption key
            var key = EncryptionKey.Generate().Base64Key;

            var encryptionKey = EncryptionKey.Create(Convert.FromBase64String(key));


            // step 2 get you service Acount cert for auth

            string serviceAcountCert = "***54387198-xxxxxxxx.json";

            // step 3 get you service Acount cert for auth

            string bucketName = "***_54387198_bucket";

            string localPath = "FileToUpload.txt";

            string objectName = null;


            // step 4 create a local text file to upload

            File.WriteAllText(localPath, "test");


            // step 5 Create Google Storage Client

            var storage = StorageClient.Create(
                GoogleCredential.FromJson(File.ReadAllText(serviceAcountCert)));


            // step 6 upload the file with the customer encryption key from step 1

            using (var f = File.OpenRead(localPath))

            

                objectName = objectName ?? Path.GetFileName(localPath);

                storage.UploadObject(bucketName, objectName, null, f,

                    new UploadObjectOptions()

                    

                        EncryptionKey = encryptionKey

                    );

                Console.WriteLine($"Uploaded objectName.");

            


            // step 7 create a url


            // step 7.1 create add x-goog-encryption-algorithm hear 
            //to tell google you are using  customer encryption key

            var requestHeaders = new Dictionary<string, IEnumerable<string>>
            
                
                    "x-goog-encryption-algorithm", new []  "AES256" 
                
            ;


            // step 7.2  set other parameters

            var expireAfter = TimeSpan.FromHours(30.0);

            var verb = HttpMethod.Get;


            // step 7.3  create a Url Signer

            var urlSigner = UrlSigner.FromServiceAccountPath(serviceAcountCert);


            // step 7.4  create a secure url
            var url = urlSigner.Sign(
                        bucketName,
                        objectName,
                        expireAfter,
                        verb,
                        requestHeaders);



            // step 8  use the Your Url


            // step 8.1 create HttpClient

            var client = new HttpClient();


            // step 8.1  add x-goog-encryption-algorithm header the same from step 7

            client.DefaultRequestHeaders.Add("x-goog-encryption-algorithm", "AES256");


            // step 8.2  add x-goog-encryption-key header with customer encryption key (Base64Hash)

            client.DefaultRequestHeaders.Add("x-goog-encryption-key", encryptionKey.Base64Key);


            // step 8.3  add x-goog-encryption-key header with customer encryption key (Base64Hash)

            client.DefaultRequestHeaders.Add("x-goog-encryption-key-sha256", encryptionKey.Base64Hash);

            // step 8.4  Download the file 
            Task.Run(async () =>
            
                var response = await client.GetAsync(url);
                var contents = await response.Content.ReadAsStringAsync();
                // contents == "test"
                Console.WriteLine($"contents=>contents");

            ).GetAwaiter().GetResult();

            Console.ReadLine();

        


    

你也可以使用邮递员来包含标题

参考。 1

Generating Signed URLs with Your Own Program  |  Cloud Storage  |  Google Cloud

Using Customer-Supplied Encryption Keys  |  Cloud Storage  |  Google Cloud

Creating Storage Buckets  |  Cloud Storage  |  Google Cloud

GCS Signed URL with Customer Supplied Encryption Key

dotnet-docs-samples/Storage.cs at master · GoogleCloudPlatform/dotnet-docs-samples

c# - Adding headers when using httpClient.GetAsync - Stack Overflow

c# - Can't specify the 'async' modifier on the 'Main' method of a console app - Stack Overflow

How to put tables in Stack Overflow? - Meta Stack Overflow

额外

您好 Mohamed,感谢您提供全面的回答。根据你的 回答,我知道我不能只创建一个公开签名的 URL 将用于下载文件。我总是必须添加额外的 标头(x-goog-encryption-algorithm,x-goog-encryption-key,...) 为了得到文件?不可能将这些数据包含在 URL 字段不知何故?

为了回答这个问题,我将使用流动的问题:

跳至问题 3 寻求解决方案

问题 1

不可能以某种方式将这些数据包含在 URL 字段中吗?

回答 1

我不知道

为什么要回答 1?

基于我的逻辑

google Storage API 是由 google 程序员编写的软件

从文档中他们希望加密密钥位于标头中

如果调用 API 时没有在标头中输入密钥,则会返回错误消息

所以也许有无证的方式,但我不知道

问题 2

HTTP参数和HTTP头的使用有什么区别

回答 2

见What is the difference between HTTP parameters and HTTP headers?

问题3:

如何解决这个问题?

答案 3

如果您在网页中使用此 URL,请参阅:javascript - How to set a header for a HTTP GET request, and trigger file download? - Stack Overflow

如果您在移动应用程序中使用此 URL:您可以使用 swift 或 java 或应用程序的语言下载文件

如果您在 电子邮件 中使用此 URL:您可以使用 asp.net MVC 或接受加密密钥作为参数的 API 创建自己的 REST API,然后您的行为就像一个谷歌可以和客户端浏览器之间的代理

问题 4:

什么是谷歌存储数据加密选项

回答 4

云存储始终encrypts your data on the server side, 在写入磁盘之前,无需额外费用。除此以外 标准行为,还有其他方法可以在以下情况下加密您的数据 使用云存储。以下是加密选项的摘要 可供您使用:

服务器端加密:在 Cloud Storage 收到您的数据之后,但在数据写入磁盘和存储之前进行的加密。

Customer-supplied encryption keys: 您可以为服务器端创建和管理自己的加密密钥 加密,它作为一个额外的加密层在顶部 标准云存储加密。 Customer-managed encryption keys: 您可以使用 Cloud Key 生成和管理您的加密密钥 管理服务,作为顶部的附加加密层 标准云存储加密。

Client-side encryption:在数据发送到云存储之前进行的加密。此类数据 到达已经加密的云存储,但也经历了 服务器端加密。

参考。 :Data Encryption Options  |  Cloud Storage  |  Google Cloud

问题 5:

最好使用客户提供的加密密钥

答案 5:

这取决于你的软件场景,但是

Cloud Storage 总是先在服务器端加密您的数据 写入磁盘,无需额外费用

参考:Data Encryption Options  |  Cloud Storage  |  Google Cloud

也许您不需要使用 客户提供的加密密钥 加密您的数据,因为谷歌默认加密 静态数据,最后也是如果你害怕谷歌监视你(只是我自己作为完美主义者的假设?),这是不合逻辑的,因为当你请求文件时,你正在将加密密钥发送到那里的服务器

参考。 2:

Mark It Down: convert rich text to Markdown

【讨论】:

您好 Mohamed,感谢您的全面回答。根据您的回答,我知道我不能只创建一个用于下载文件的公开签名 URL。我总是必须添加额外的标题(x-goog-encryption-algorithmx-goog-encryption-key,...)才能获取文件?无法以某种方式将这些数据包含在 URL 字段中? @No1Lives4Ever 见我的update 并跳至问题 3 以获得解决方案

以上是关于带有 Google 存储的 C# - 带有客户加密密钥的签名 URL的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 C# 的 Google OAuth 2.0 登录

带有私钥加密的公钥加密

带有 MimeKit、C# Winforms 和 Google API 的 Gmail 草稿(带附件的 HTML)

在带有 WCF 服务的 C# 服务器中使用穷人的 DI [重复]

如何在 C# 中使用带有服务帐户的 gmail api 或 google Oauth 来发送邮件?

带有 Google JavaScript 客户端库的 Google Contacts API