我已经使用客户密钥(SSE-C)为AWS S3服务器端加密创建了客户密钥。
我可以使用键上传对象。但是,当我使用AWS Java SDK生成一个预签名URL时,该URL已成功创建,但是当我单击该URL时,出现了以下错误。
SignatureDoesNotMatch
我们计算出的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.HttpMethod;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.Headers;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.SSEAlgorithm;
import com.amazonaws.services.s3.model.SSECustomerKey;
import com.amazonaws.util.Base64;
import com.amazonaws.util.Md5Utils;
public class GeneratePresignedURL {
public GeneratePresignedURL() throws IOException {
String bucketName = "abctest";
String keyName = "testnew.mp4";
try {
SSECustomerKey SSE_KEY = new SSECustomerKey("KLgsVafKowMCfKDsbIh597CmMUSoPBn6QJ8OIGxAMBw=");
ClientConfiguration cnf = new ClientConfiguration();
cnf.withSignerOverride("AWSS3V4SignerType");
AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withClientConfiguration(cnf)
.withCredentials(new ProfileCredentialsProvider()).build();
// Set the presigned URL to expire after one hour.
java.util.Date expiration = new java.util.Date();
long expTimeMillis = expiration.getTime();
expTimeMillis += 1000 * 60 * 60;
expiration.setTime(expTimeMillis);
// Generate the presigned URL.
System.out.println("Generating pre-signed URL.");
GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName,
keyName).withMethod(HttpMethod.PUT).withExpiration(expiration).withSSECustomerKey(SSE_KEY);
generatePresignedUrlRequest.setSSECustomerKeyAlgorithm(SSEAlgorithm.AES256);
URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
System.out.println("Pre-Signed URL: " + url.toExternalForm());
} catch (AmazonServiceException e) {
// The call was transmitted successfully, but Amazon S3 couldn't process
// it, so it returned an error response.
e.printStackTrace();
} catch (SdkClientException e) {
// Amazon S3 couldn't be contacted for a response, or the client
// couldn't parse the response from Amazon S3.
e.printStackTrace();
}
}
中的代码
我在使用SSE S3的预签名URL时没有问题,我仅遇到SSE-C的问题
我尝试设置默认加密和其他配置,但没有帮助。任何指针都会有很大帮助。
谢谢, AK
答案 0 :(得分:0)
您不能通过浏览器直接调用预签名的URL
您需要在请求中传递标头
x-amz-server-side-encryption-customer-algorithm
x-amz-server-side-encryption-customer-key
x-amz服务器端加密-客户密钥MD5
请检查文档以获取更多信息 https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html
使用预先签名的URL上载新对象,检索现有对象或仅检索对象元数据时,必须在客户端应用程序中提供所有加密标头。
请检查通过Unirest库调用签名URL的示例代码 https://github.com/pavanpawar4591/s3signurlwith-sse-c
public static void getPreSignedURL() throws URISyntaxException {
java.util.Date expiration = new java.util.Date();
long expTimeMillis = expiration.getTime();
expTimeMillis += 1000 * 60 * 60;
expiration.setTime(expTimeMillis);
System.out.println("Generating pre-signed URL.");
GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, keyName)
.withMethod(HttpMethod.GET).withExpiration(expiration).withSSECustomerKey(SSE_KEY);
// generatePresignedUrlRequest.setContentType("video/mp4");
generatePresignedUrlRequest.setSSECustomerKeyAlgorithm(SSEAlgorithm.AES256);
URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
System.out.println("Pre-Signed URL: " + url.toURI() + " With key: " + SSE_KEY);
System.out.println("------------------------------");
//https://aws.amazon.com/blogs/developer/generating-amazon-s3-pre-signed-urls-with-sse-c-part-4/
// refer to above doc
try {
HttpResponse<String> response = Unirest.get(url.toURI().toString())
.header(Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM, SSEAlgorithm.AES256.getAlgorithm())
.header(Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY, Base64.encodeAsString(SECRET_KEY.getEncoded()))
.header(Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
Md5Utils.md5AsBase64(SECRET_KEY.getEncoded()))
.header("cache-control", "no-cache").header("postman-token", "d3453c38-1b59-a12e-fd97-dbe2150eadf5")
.asString();
System.out.println(response.getStatus());
System.out.println(response.getStatusText());
System.out.println(response.getBody());
} catch (UnirestException e) {
e.printStackTrace();
}
}
答案 1 :(得分:0)
感谢@pavan
任何需要使用SSE-C的客户端,该客户端都必须能够发送“以下”标头。
使用预签名URL检索现有对象或仅检索对象元数据时,我们需要在客户端应用程序中提供所有加密标头。
对于S3托管或KMS托管的服务器端加密,我们可以生成一个预签名的URL,并将其直接粘贴到浏览器或播放器中。
但是,这对于SSE-C对象不是正确的,因为除了 预先签署的URL,还需要包括HTTP标头 特定于SSE-C对象。因此,您可以使用预签名的URL 只能以编程方式用于SSE-C对象。
上传:
我选择了S3托管密钥,而不是客户提供的客户端密钥。
FileInputStream fin = new FileInputStream(uploadFileName);
byte fileContent[] = new byte[(int) uploadFileName.length()];
// Reads up to certain bytes of data from this input stream into an array of
// bytes.
fin.read(fileContent);
// create string from byte array
// Specify server-side encryption.
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(fileContent.length);
objectMetadata.setSSEAlgorithm(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION);
PutObjectRequest putRequest = new PutObjectRequest(bucketName, keyName,
new ByteArrayInputStream(fileContent), objectMetadata);
// Upload the object and check its encryption status.
PutObjectResult putResult = s3Client.putObject(putRequest);
System.out.println("Object \"" + keyName + "\" uploaded with SSE.");
获取预签名网址:
java.util.Date expiration = new java.util.Date();
long expTimeMillis = expiration.getTime();
expTimeMillis += 1000 * 60 * 60;
expiration.setTime(expTimeMillis);
System.out.println("Generating pre-signed URL.");
GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, keyName)
.withMethod(HttpMethod.GET).withExpiration(expiration);
URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
System.out.println("Pre-Signed URL: " + url.toURI());
参考: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html