핫링킹은 다른 호스팅된 서버에서 파일을 다운로드하지 않고 링크하는 행위이다
해당 파일을 핫링킹하여 사용자의 서버에 호스팅하면서 출처를 제공하지 않는다
쀼에 설정이 필요한 이유
쀼는 추억이 담긴 개인 사진을 업로드할 수 있는 프로젝트이기 때문에 무엇보다 이미지에 대한 보안이 필요하다
1. CloudFront Signed URL + 캐시 유효 시간 설정 혹은 CloudFront Signed Cookie
혹은 CloudFront WAF에서 Referer 헤더 검증
2. 오리진에서 직접 접근 차단 (CloudFront만 거치도록 제한)
3번은 저번 글에서 S3에 CloudFront만 접근할 수 있도록 하였다
2번은 1번을 진행한다면 개선이 되는 부분이기 때문에 1번을 진행하려 한다
(브라우저 개발자 도구에서 Referer를 조작할 수 있고, VPN이나 프록시를 사용하면 우회 가능하다 따라서 1번을 사용하기로 했다)
CloudFront Signed Cookie 방식으로 방지하기로 하였다
방안1) CloudFront Signed URL 적용
Signed URL은 만료 시간, 서명 값 등의 요소 때문에 동적으로 생성되지만, 만료 기간 동안에는 동일한 URL을 제공할 수 있다. 즉, 유효 기간 내에서는 클라이언트 입장에서는 정적 URL처럼 동작하게 된다.
예를 들어, Signed URL을 생성할 때 만료 시간을 1시간으로 설정하면, 그 1시간 동안은 같은 Signed URL을 사용할 수 있으므로, Next.js의 `next/image`가 이를 정적 URL처럼 처리할 수 있다. 다만, 만료 시간이 지나면 URL이 무효화되고, 새로운 Signed URL을 생성해야 하므로 그 시점부터는 URL이 다시 동적으로 변한다.
과정
1. 업로드 : 사용자가 이미지를 업로드하면, 백엔드(Spring Boot)가 S3에 업로드한 후, 파일 경로(또는 키)를 DB에 저장하고
정보를 클라이언트에 반환한다.
2. 조회 : 클라이언트는 이미지가 필요할 때, 저장된 ID를 이용해 CloudFront의 서명된 URL을 받아온다
고려해야할점
핫링크를 방지하는 데 효과적이지만, URL을 계속 서버로부터 받아오기 때문에 서버에 추가적인 부하를 줄 수 있는 단점이 있다.
그렇다고해서 DB에 Signed URL을 저장한 후 조회하는 방식도 갱신 주기 마다 갱신을 하던지 이런 만료 처리를 해야 한다.
방안2) CloudFront Signed Cookie 사용
클라이언트 로그인 후, Signed Cookie를 받아서 모든 이미지 요청시 자동으로 인증하도록 한다
CloudFront에서 Signed Cookie가 없으면 차단한다
과정
로그인이 성공하면 CloudFront Signed Cookie를 만들어서, CloudFront 를 통해 이미지 접근시 헤더에 쿠키를 포함하여 요청을 보낸다
장점
추가적인 요청이 필요없다
공식문서 : Signed URLs vs Signed Cookies
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-choosing-signed-urls-cookies.html
Decide to use signed URLs or signed cookies - Amazon CloudFront
Decide to use signed URLs or signed cookies CloudFront signed URLs and signed cookies provide the same basic functionality: they allow you to control who can access your content. If you want to serve private content through CloudFront and you're trying to
docs.aws.amazon.com
AmazonS3Client > S3Client
AWS SDK v2는 서명된 쿠키를 생성하는 명시적인 방법을 제공하지 않음
(CloudFront Signed Cookie 설정 과정 참고)
1. S3
Maven 저장소
https://mvnrepository.com/artifact/software.amazon.awssdk/s3
공식 문서 (예제)
https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/java_s3_code_examples.html
Amazon S3 examples using SDK for Java 2.x - AWS SDK for Java 2.x
Amazon S3 examples using SDK for Java 2.x The following code examples show you how to perform actions and implement common scenarios by using the AWS SDK for Java 2.x with Amazon S3. Basics are code examples that show you how to perform the essential opera
docs.aws.amazon.com
2. CloudFront
Maven 저장소
https://mvnrepository.com/artifact/software.amazon.awssdk/cloudfront
공식문서 (예제 - 연결)
https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/java_cloudfront_code_examples.html
CloudFront examples using SDK for Java 2.x - AWS SDK for Java 2.x
CloudFront examples using SDK for Java 2.x The following code examples show you how to perform actions and implement common scenarios by using the AWS SDK for Java 2.x with CloudFront. Actions are code excerpts from larger programs and must be run in conte
docs.aws.amazon.com
생성된 키 페어는 Public Key와 Private Key로 제공된다.
Private Key는 서버에서 보관하며, Public Key는 CloudFront에 업로드하여 서명을 검증할 때 사용된다.
공식문서 :서명된 URL과 서명된 쿠키를 생성할 수 있는 서명자를 지정하세요.
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html#private-content-creating-cloudfront-key-pairs
Specify signers that can create signed URLs and signed cookies - Amazon CloudFront
Save the private key for your CloudFront key pair in a secure location, and set permissions on the file so that only the desired administrators can read it. If someone gets your private key, they can generate valid signed URLs and signed cookies and downlo
docs.aws.amazon.com
1. 퍼블릭 키/개인키 생성하기
1) openssl 활용하여 개인키 + 퍼블릭키 생성
# 개인 키 생성 (private.pem)
openssl genrsa -out private_key.pem 2048
# 퍼블릭 키 생성 (public.pem)
openssl rsa -pubout -in private_key.pem -out public_key.pem
윈도우 OpenSSL 설치하기
개인키는 보관하고 퍼블릭키를 이제 CloudFront에 업로드해야 한다
2. CloudFront에 퍼블릭 키 업로드
CloudFront > 퍼블릭 키 > 생성
3. 키 그룹에 퍼블릭 키 추가하기
이 키 그룹은 CloudFront에서 서명된 URL이나 쿠키의 서명을 검증할 때 사용된다.
4. 배포 > 동작편집 : 뷰어 액세스 제한 풀고 키 그룹 추가하기
공식문서 (예제 - Set Signed Cookies Using a Custom Policy)
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html
Set signed cookies using a custom policy - Amazon CloudFront
IP addresses in IPv6 format, such as 2001:0db8:85a3::8a2e:0370:7334, are not supported.
docs.aws.amazon.com
- CloudFront-Signature, CloudFront-Policy, CloudFront-Key-Pair-Id 3가지 쿠키가 필요하다
- Secure : Set-Cookie 요청을 보내기 전에 뷰어가 쿠키를 암호화해야 한다. 쿠키 속성이 중간자 공격으로부터 보호되도록 HTTPS 연결을 통해 헤더를 보내는 것이 좋다.
- HttpOnly : HTTP 또는 HTTPS 요청으로만 쿠키 보내도록 해야 한다.
3-1) CloudFront-Signature, CloudFront-Policy, CloudFront-Key-Pair-Id 3가지 쿠키를 생성하는 방법에 대해 알아보자
(1) CloudFront-Policy 생성
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html#private-content-custom-policy-signature-cookies
Set signed cookies using a custom policy - Amazon CloudFront
IP addresses in IPv6 format, such as 2001:0db8:85a3::8a2e:0370:7334, are not supported.
docs.aws.amazon.com
(2) CloudFront-Signature 생성
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html#private-content-custom-policy-signature-cookies
Set signed cookies using a custom policy - Amazon CloudFront
IP addresses in IPv6 format, such as 2001:0db8:85a3::8a2e:0370:7334, are not supported.
docs.aws.amazon.com
(3) CloudFront-Key-Pair-Id 생성
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html
Specify signers that can create signed URLs and signed cookies - Amazon CloudFront
Save the private key for your CloudFront key pair in a secure location, and set permissions on the file so that only the desired administrators can read it. If someone gets your private key, they can generate valid signed URLs and signed cookies and downlo
docs.aws.amazon.com
2번 CloudFront 설정에서
publickey를 올려서 key pair를 만들었는데 그 ID이다
알파벳대문자여러개로 구성되어 있다
1. 로그인 후 마지막에 Signed Cookie를 생성하여 응답에 추가할 수 있도록 하였다
2. CloudFrontService를 생성했다
- CloudFront에서 뷰어 액세스 제한을 적용하기 위해 아래와 같은 쿠키를 설정하였다
3. Docker-Compose.yml 수정
도커 외부에서 PRIVATE_KEY_PATH에 있는
docker - compose에서 volumes로 도커 컨테이너와 호스트 간에 마운트하고,
environment로 PRIVATE_KEY_PATH를 설정해 두었다
해당 위치에 private_key.pem 을 두었다
제대로 마운트가 되었는지 확인해보자
직접 접근하는 경우 : 접근 안됨
쀼에서 접근하는 경우 : 접근됨
접근 되는 줄 알았다 ... 그런데 안된다 (캐시 무효화 한다음에 다시 확인해보자)
[쀼] 백엔드 서버, 데이터베이스 서버 분리 (MySQL 직접 운영) (4) | 2025.02.21 |
---|---|
[쀼] S3에 업로드한 사진 : 이미지 핫링크 방지 과정 (3) (0) | 2025.02.11 |
[쀼] S3에 업로드한 사진 : S3 퍼블릭 엑세스 차단 활성화(1) (1) | 2025.01.12 |
[쀼] 카카오맵 API 사용하기 (0) | 2025.01.08 |
[쀼] 화면이 실시간으로 바뀌어야 하는 요구사항을 해결해보자 (2) : 프론트앤드 (0) | 2025.01.06 |