带有 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
参考。 :Data Encryption Options | Cloud Storage | Google Cloud云存储始终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:
Mark It Down: convert rich text to Markdown【讨论】:
您好 Mohamed,感谢您的全面回答。根据您的回答,我知道我不能只创建一个用于下载文件的公开签名 URL。我总是必须添加额外的标题(x-goog-encryption-algorithm
,x-goog-encryption-key
,...)才能获取文件?无法以某种方式将这些数据包含在 URL 字段中?
@No1Lives4Ever 见我的update 并跳至问题 3 以获得解决方案以上是关于带有 Google 存储的 C# - 带有客户加密密钥的签名 URL的主要内容,如果未能解决你的问题,请参考以下文章
带有 MimeKit、C# Winforms 和 Google API 的 Gmail 草稿(带附件的 HTML)
在带有 WCF 服务的 C# 服务器中使用穷人的 DI [重复]