Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] 최신 sdk 사용에 따른 cloudFrontService 및 S3Service validateURL 로직, 에러핸들링 수정 #57

Merged
merged 4 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions nonsoolmateServer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,7 @@ dependencies {
// AWS sdk
implementation("software.amazon.awssdk:bom:2.21.0")
implementation("software.amazon.awssdk:s3:2.21.0")
compileOnly group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.534'
implementation 'software.amazon.awssdk:cloudfront:2.18.26' // AWS SDK for Java v2의 버전

compileOnly group: 'org.springframework.cloud', name: 'spring-cloud-starter-aws', version: '2.2.1.RELEASE'

implementation 'software.amazon.awssdk:cloudfront:2.22.3'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

보안적으로 취약한지는 생각을 못했네요..! 역시 보안전문가십니다 ㅎㅎ

// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ public UniversityExamImageAndAnswerResponseDTO getUniversityExamImageAndAnswer(L
UniversityExamExceptionType.NOT_FOUND_UNIVERSITY_EXAM));

String examAnswerUrl = cloudFrontService.createPreSignedGetUrl(EXAM_ANSWER_FOLDER_NAME,
universityExam.getExamAnswerFileName());
universityExam.getExamAnswerFileName(), universityExam.getExamTimeLimit());
List<UniversityExamImageResponseDTO> examImageUrls = new ArrayList<>();

List<UniversityExamImage> UniversityExamImages = universityExamImageRepository.findAllByUniversityExam(
universityExam);

UniversityExamImages.stream().forEach(universityExamImage -> {
String presignedGetUrl = cloudFrontService.createPreSignedGetUrl(EXAM_RESULT_FOLDER_NAME,
universityExamImage.getUniversityExamImageFileName());
universityExamImage.getUniversityExamImageFileName(), universityExam.getExamTimeLimit());

examImageUrls.add(
UniversityExamImageResponseDTO.of(presignedGetUrl));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ public UniversityExamRecordResponseDTO getUniversityExamRecord(Long universityEx
UniversityExamRecord universityExamRecord = getUniversityExamByUniversityExamAndMember(universityExam, member);

String answerUrl = cloudFrontService.createPreSignedGetUrl(EXAM_ANSWER_FOLDER_NAME,
universityExam.getExamAnswerFileName());
universityExam.getExamAnswerFileName(), universityExam.getExamTimeLimit());
String resultUrl = cloudFrontService.createPreSignedGetUrl(EXAM_RESULT_FOLDER_NAME,
universityExamRecord.getExamRecordResultFileName());
universityExamRecord.getExamRecordResultFileName(), universityExam.getExamTimeLimit());

return UniversityExamRecordResponseDTO.of(answerUrl, resultUrl);
}
Expand All @@ -52,7 +52,7 @@ public UniversityExamRecordResultResponseDTO getUniversityExamRecordResult(Long
UniversityExamRecord universityExamRecord = getUniversityExamByUniversityExamAndMember(universityExam, member);

String resultUrl = cloudFrontService.createPreSignedGetUrl(EXAM_RESULT_FOLDER_NAME,
universityExamRecord.getExamRecordResultFileName());
universityExamRecord.getExamRecordResultFileName(), universityExam.getExamTimeLimit());

return UniversityExamRecordResultResponseDTO.of(resultUrl);
}
Expand All @@ -61,8 +61,8 @@ public UniversityExamRecordResultResponseDTO getUniversityExamRecordResult(Long
public UniversityExamRecordIdResponse createUniversityExamRecord(
CreateUniversityExamRequestDTO request, Member member) {
UniversityExam universityExam = getUniversityExam(request.universityExamId());
String fileName = s3Service.validateURL(EXAM_SHEET_FOLDER_NAME, request.memberSheetFileName());
try {
String fileName = s3Service.validateURL(EXAM_SHEET_FOLDER_NAME, request.memberSheetFileName());
UniversityExamRecord universityexamRecord = createUniversityExamRecord(universityExam, member,
request.memberTakeTimeExam(),
fileName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum AWSExceptionType implements BusinessExceptionType {
DELETE_FILE_AWS_S3_FAIL(HttpStatus.BAD_REQUEST, "S3 파일 삭제에 실패했습니다"),
NOT_FOUND_FILE_AWS_S3(HttpStatus.BAD_REQUEST, "S3에서 파일을 찾을 수 없습니다"),
GET_PRESIGNED_URL_AWS_CLOUDFRONT_FAIL(HttpStatus.BAD_REQUEST, "Cloud PresignedUrl 발급에 실패했습니다"),
NOT_FOUND_CLOUD_PRIVATE_KEY_FAIL(HttpStatus.NOT_FOUND, "Cloud Private Key 조회에 실패했습니다"),
INVALID_KEY_SPEC_FAIL(HttpStatus.BAD_REQUEST, "Cloud Private Key Spec이 잘못되었습니다");
NOT_FOUND_FILE_AWS_S3(HttpStatus.NOT_FOUND, "S3에서 파일을 찾을 수 없습니다"),
GET_PRESIGNED_URL_AWS_CLOUDFRONT_FAIL(HttpStatus.BAD_REQUEST, "Cloud PresignedUrl 발급에 실패했습니다");

private final HttpStatus status;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package com.nonsoolmate.nonsoolmateServer.external.aws.service;

import com.amazonaws.services.cloudfront.CloudFrontUrlSigner;
import com.amazonaws.services.cloudfront.util.SignerUtils;
import com.nonsoolmate.nonsoolmateServer.external.aws.error.AWSException;
import com.nonsoolmate.nonsoolmateServer.external.aws.error.AWSExceptionType;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.spec.InvalidKeySpecException;
import java.time.Duration;
import java.util.Date;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;
import software.amazon.awssdk.services.cloudfront.CloudFrontUtilities;
import software.amazon.awssdk.services.cloudfront.model.CannedSignerRequest;
import software.amazon.awssdk.services.cloudfront.url.SignedUrl;


@Component
Expand All @@ -30,29 +28,23 @@ public class CloudFrontService {
@Value("${aws-property.key-pair-id}")
private String keyPairId;

public String createPreSignedGetUrl(String path, String fileName) {
String s3ObjectKey = path + fileName; // S3 객체 키
Duration duration = Duration.ofMinutes(1);
Date expirationTime = new Date(System.currentTimeMillis() + duration.toMillis());
SignerUtils.Protocol protocol = SignerUtils.Protocol.https;
String signedUrl = null;
public String createPreSignedGetUrl(String path, String fileName, int expireTime) {
String resourcePath = path + fileName;
String cloudFrontUrl = "https://" + distributionDomain + "/" + resourcePath;
Instant expirationTime = Instant.now().plus(expireTime, ChronoUnit.MINUTES);
Path keyPath = Paths.get(privateKeyFilePath);
try {
File privateKeyFile = ResourceUtils.getFile(privateKeyFilePath);
signedUrl = CloudFrontUrlSigner.getSignedURLWithCannedPolicy(
protocol,
distributionDomain,
privateKeyFile,
s3ObjectKey,
keyPairId,
expirationTime
);
} catch (FileNotFoundException e) {
throw new AWSException(AWSExceptionType.NOT_FOUND_CLOUD_PRIVATE_KEY_FAIL);
} catch (InvalidKeySpecException e) {
throw new AWSException(AWSExceptionType.INVALID_KEY_SPEC_FAIL);
} catch (IOException e) {
CloudFrontUtilities cloudFrontUtilities = CloudFrontUtilities.create();
CannedSignerRequest cannedSignerRequest = CannedSignerRequest.builder()
.resourceUrl(cloudFrontUrl)
.privateKey(keyPath)
.keyPairId(keyPairId)
.expirationDate(expirationTime)
.build();
SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCannedPolicy(cannedSignerRequest);
return signedUrl.url();
} catch (Exception e) {
throw new AWSException(AWSExceptionType.GET_PRESIGNED_URL_AWS_CLOUDFRONT_FAIL);
}
return signedUrl;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
import software.amazon.awssdk.services.s3.model.GetUrlRequest;
import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
import software.amazon.awssdk.services.s3.model.S3Exception;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
Expand Down Expand Up @@ -56,16 +58,18 @@ private String generateZipFileName() {
public String validateURL(final String prefix, final String fileName) {
try {
String zipUrl = prefix + fileName;
GetUrlRequest request = GetUrlRequest.builder()
S3Client s3Client = awsConfig.getS3Client();

HeadObjectRequest request = HeadObjectRequest.builder()
.bucket(bucketName)
.key(zipUrl)
.build();
S3Client s3Client = awsConfig.getS3Client();
URL url = s3Client.utilities().getUrl(request);
if (zipUrl.equals(url.getPath().substring(1))) {
return fileName;

HeadObjectResponse response = s3Client.headObject(request);
if (response == null) {
throw new AWSException(AWSExceptionType.NOT_FOUND_FILE_AWS_S3);
}
throw new AWSException(AWSExceptionType.NOT_FOUND_FILE_AWS_S3);
return fileName;
} catch (S3Exception e) {
throw new AWSException(AWSExceptionType.NOT_FOUND_FILE_AWS_S3);
}
Expand Down
Loading