我将文件上传到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>
我想这是因为我的文件是加密的其他密钥。
如何正确处理?
答案 0 :(得分: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();
}
}
}
您还可以使用邮递员添加标题
Generating Signed URLs with Your Own Program | Cloud Storage | Google Cloud
Using Customer-Supplied Encryption Keys | Cloud Storage | Google Cloud
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
您好,穆罕默德(Mohamed),感谢您的全面答复。根据你的 答案,我了解我不能公开签署网址 将用于下载文件。我总是必须添加其他内容 标头(x-goog-encryption-algorithm,x-goog-encryption-key等) 为了得到文件?无法将此数据包含在 网址字段以某种方式出现?
无法以某种方式在URL字段中包含此数据?
基于我的逻辑
google Storage API是由Google程序员编写的软件
他们希望文档中的加密密钥位于标题中
如果您在没有输入标头的情况下调用API,则会返回错误消息
所以也许有未记录的方法,但我不知道
HTTP参数和HTTP标头用法之间有什么区别
如何解决这个问题?
如果您正在网页中使用此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,该API接受加密密钥作为参数,然后像谷歌可以和客户端浏览器之间的代理
什么是Google存储数据加密选项
云存储始终encrypts your data on the server side, 在将其写入磁盘之前,无需任何额外费用。除此之外 标准行为,还有其他方式可以在以下情况下加密数据 使用云存储。以下是加密选项的摘要 可供您使用:
服务器端加密:在Cloud Storage接收数据之后但在将数据写入磁盘并存储之前进行的加密。
- Customer-supplied encryption keys: 您可以为服务器端创建和管理自己的加密密钥 加密,作为加密基础之上的附加加密层 标准的云存储加密。
- Customer-managed encryption keys: 您可以使用Cloud Key生成和管理加密密钥 管理服务,充当顶部的附加加密层 标准云存储加密。
Client-side encryption:在将数据发送到Cloud Storage之前发生的加密。这样的数据 到达已经加密但还会经历的Cloud Storage 服务器端加密。
最好使用客户提供的加密密钥?
这取决于您的软件方案,但是
Cloud Storage总是先加密服务器端的数据,然后再加密 已写入磁盘,无需额外付费
也许您不需要使用客户提供的加密密钥来加密数据,因为google默认情况下也会加密静态数据一天之内,如果您害怕Google暗中监视您(只是我作为完美主义者的假设),这是不合逻辑的,因为当您请求文件