【问题标题】:C# with Google Storage - Signed URL with customer encryption key带有 Google 存储的 C# - 带有客户加密密钥的签名 URL
【发布时间】: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>

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

怎么做才对?

【问题讨论】:

    标签: c# google-cloud-storage


    【解决方案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 stackoverflow54387198
    {
        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 = "stackoverflow54387198-xxxxxxxx.json";
    
                // step 3 get you service Acount cert for auth
    
                string bucketName = "stackoverflow_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

    额外

    您好 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

    问题3:

    如何解决这个问题?

    答案 3

    问题 4:

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

    回答 4

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

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

      • Customer-supplied encryption keys: 您可以为服务器端创建和管理自己的加密密钥 加密,它作为一个额外的加密层在顶部 标准云存储加密。
      • Customer-managed encryption keys: 您可以使用 Cloud Key 生成和管理您的加密密钥 管理服务,作为顶部的附加加密层 标准云存储加密。
    • Client-side encryption:在数据发送到云存储之前进行的加密。此类数据 到达已经加密的云存储,但也经历了 服务器端加密。

    问题 5:

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

    答案 5:

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

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

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

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

    参考。 2:

    【讨论】:

    • 您好 Mohamed,感谢您的全面回答。根据您的回答,我知道我不能只创建一个用于下载文件的公开签名 URL。我总是必须添加额外的标题(x-goog-encryption-algorithmx-goog-encryption-key,...)才能获取文件?无法以某种方式将这些数据包含在 URL 字段中?
    • @No1Lives4Ever 见我的update 并跳至问题 3 以获得解决方案
    猜你喜欢
    • 2021-11-27
    • 2021-06-23
    • 2017-08-31
    • 2013-04-06
    • 2022-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    相关资源
    最近更新 更多