Skip to content

Conversation

@ckdals4600
Copy link
Contributor

@ckdals4600 ckdals4600 commented Dec 22, 2025

관련 이슈

PR 설명

  • 링크 저장 시 수집된 OG 이미지를 외부 URL 그대로 사용하는 대신, AWS S3에 업로드하여 영구 저장하는 기능 구현
  • 동일한 이미지 URL에 대한 중복 업로드를 방지하여 스토리지 및 네트워크 비용 최적화
  • 테스트 용이성을 위해 네트워크 연결 객체 추상화 진행

작업 내용

1. AWS 리소스 및 환경 설정

  • IAM & S3:
    • S3 버킷 생성 및 접근 권한(PutObject, GetObject)을 가진 IAM 사용자 설정 완료.
    • application.yml에 AWS 관련 프로퍼티(AccessKey, SecretKey, Bucket, Region) 추가 및 환경 변수 분리 적용.
  • 의존성 추가
    • spring-cloud-starter-aws
    • spring-cloud-aws-dependencie
    • org.apache.httpcomponents:httpclient: Spring Cloud AWS가 S3와 통신하기 위한 라이브러리

2. UrlConnectionFactory 인터페이스 분리

  • 변경 전: S3ImageUploader 내부에서 new URL(url).openConnection()을 직접 호출.
  • 변경 후: UrlConnectionFactory 인터페이스를 통해 연결 객체를 생성하도록 분리.
  • 목적:
    • 외부 네트워크 통신을 Mocking하여 단위 테스트를 용이하게 만들기 위함.
    • 실제 네트워크 호출 없이 Timeout, Content-Type 불일치, IOException 등의 예외 상황을 시뮬레이션하여 안정적인 테스트 환경을 구축

3. S3 이미지 업로더 구현 (S3ImageUploader)

  • 리소스 최적화와 안정성을 고려하여 로직 설계

  • 고유 키 생성 전략 (generateUniqueKeyFromUrl):

    • Deterministic UUID
      • UUID.randomUUID()대신UUID.nameUUIDFromBytes(url.getBytes())` 사용
      • 원본 URL 바이트를 시드로 사용하므로, 동일한 URL 입력 시 항상 동일한 UUID 생성 보장
    • 확장자 파싱
      • URL에서 쿼리 파라미터를 제거하여 순수 확장자 추출
      • 추출 실패 시 jpg를 기본값으로 적용하여 파일명 안정성 확보
  • S3 URL 구성 (buildS3Url):

    • SDK의 getUrl 메서드 등을 호출하는 대신, https://{bucket}.s3.{region}.amazonaws.com/{key} 형식의 표준 문자열을 직접 포맷팅하여 반환함으로써 불필요한 연산 감소
  • 중복 제거 및 캐싱 (Deduplication):

    • 위에서 생성한 고유 키를 사용하여 s3Template.objectExists()를 호출
    • Cache Hit: 리소스 절약을 위해 이미 저장된 이미지라면 다운로드/업로드를 건너뛰고 생성된 S3 URL을 즉시 반환.
  • 유효성 검사 및 스트리밍:

    • URLConnection에 **Connection/Read Timeout(3초)**을 설정하여 스레드 차단 방지
    • Content-Typeimage/*가 아닌 경우 업로드를 거부하고 기본 이미지 반환
    • InputStream을 사용하여 파일을 메모리에 온전히 적재하지 않고 스트림 방식으로 업로드하여 메모리 효율을 향상 시킴
  • Soft Fail (Fallback):

    • 다운로드 실패(404, Timeout) 또는 접근 거부 시, 링크 저장 트랜잭션 전체가 실패하지 않도록 예외를 잡고 기본 이미지 URL 반환

4. 비즈니스 로직 적용 (LinkFacade)

  • createLink 메서드 내에서 linkService 호출 전 imageUploader.uploadFromUrl(imageUrl)을 수행하도록 흐름 추가

테스트 작성 (Test Coverage)

1. Integration Test (LinkApiIntegrationTest)

  • 시나리오 검증:
    • 링크 생성 시 이미지 업로더 모킹(given(imageUploader...).willReturn(...))을 통해 S3 URL이 DB에 정상 저장되는지 확인.
    • URL 중복 체크, 타 사용자 링크 접근 제한(IDOR), 제목/URL 길이 제한 등 예외 케이스 검증.
    • 메타데이터 크롤링(OG 태그) 및 요약 재생성 API의 정상 동작 확인.

2. Unit Test (S3ImageUploaderTest)

  • Mocking 활용: S3TemplateUrlConnectionFactory를 Mock 객체로 주입받아 테스트 수행.
  • 검증 케이스:
    • 정상 업로드: URL이 유효하고 S3에 파일이 없을 때 업로드 메서드가 호출되는지 검증.
    • Cache Hit: S3에 이미 파일이 존재할 때 업로드 로직이 실행되지 않고 URL만 반환되는지 확인.
    • Not Image Type: Content-Typeapplication/pdf 등일 때 업로드를 거부하고 원본 URL을 반환하는지 확인.
    • Connection Error: 네트워크 예외 발생 시 Fallback(원본 URL 반환) 로직 동작 확인.

3. Facade Test (LinkFacadeTest)

  • 흐름 검증: createLink 호출 시 imageUploader -> linkService 순서로 호출되는지 검증.
  • 데이터 전달: 업로더가 반환한 S3 URL이 서비스 계층으로 올바르게 전달되는지 확인.

@ckdals4600 ckdals4600 linked an issue Dec 22, 2025 that may be closed by this pull request
1 task
@ckdals4600 ckdals4600 self-assigned this Dec 22, 2025
@ckdals4600 ckdals4600 requested review from Goder-0 and minibr December 22, 2025 17:39
@ckdals4600 ckdals4600 force-pushed the feature/#163-og-image-s3-upload-when-link-add branch 2 times, most recently from 5c37e5d to e3d8696 Compare December 22, 2025 18:12
@github-actions
Copy link

github-actions bot commented Dec 22, 2025

📊 코드 커버리지 리포트

Overall Project 88.12% -0.55% 🍏
Files changed 90.27% 🍏

File Coverage
LinkFacade.java 100% 🍏
S3ImageUploader.java 92.59% -7.41% 🍏
DefaultUrlConnectionFactory.java 33.33% -66.67% 🍏

@ckdals4600
Copy link
Contributor Author

#168, #158 PR 이후 머지 진행하겠습니다ㅓ.

Copy link
Contributor

@Goder-0 Goder-0 left a comment

Choose a reason for hiding this comment

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

@ckdals4600 @minibr
지금 현 구조상으로 보면, front로 부터 링크 생성시에 imageUrl을 받는데요.
해당 구조의 경우, SSRF 리스크가 존재합니다.
og 크롤링시에 캐싱을 해두고, 그걸 접근하도록 하는 것은 어떻게 생각하시나요?

추후, 개선사항으로 남겨두는 것 또한 좋다고 생각합니다.
의견 공유 부탁드립니다.

@ckdals4600
Copy link
Contributor Author

ckdals4600 commented Dec 30, 2025

@ckdals4600 @minibr 지금 현 구조상으로 보면, front로 부터 링크 생성시에 imageUrl을 받는데요. 해당 구조의 경우, SSRF 리스크가 존재합니다. og 크롤링시에 캐싱을 해두고, 그걸 접근하도록 하는 것은 어떻게 생각하시나요?

추후, 개선사항으로 남겨두는 것 또한 좋다고 생각합니다. 의견 공유 부탁드립니다.

좋은 지적 감사합니다!

말씀해주신 대로 클라이언트로부터 임의의 URL을 받아 서버에서 요청을 보내게 될 경우 SSRF 보안 취약점이 발생할 수 있고, 원본 사이트의 정책에 따라 이미지 로딩이 차단되거나 원본이 삭제될 위험도 있다고 판단됩니다.

서비스의 안정성과 보안을 위해 구조 개선이 필요할 것 같습니다.
다만, 현재 PR의 범위가 커질 수 있어 해당 내용은 별도 이슈로 등록하여 진행하는 것이 좋아보입니다,

@ckdals4600 ckdals4600 force-pushed the feature/#163-og-image-s3-upload-when-link-add branch from e3d8696 to 6b76ab3 Compare December 30, 2025 16:54
@ckdals4600 ckdals4600 requested review from Goder-0 and minibr December 31, 2025 02:59
@Goder-0
Copy link
Contributor

Goder-0 commented Jan 2, 2026

말씀해주신 대로 클라이언트로부터 임의의 URL을 받아 서버에서 요청을 보내게 될 경우 SSRF 보안 취약점이 발생할 수 있고, 원본 사이트의 정책에 따라 이미지 로딩이 차단되거나 원본이 삭제될 위험도 있다고 판단됩니다.
서비스의 안정성과 보안을 위해 구조 개선이 필요할 것 같습니다.
다만, 현재 PR의 범위가 커질 수 있어 해당 내용은 별도 이슈로 등록하여 진행하는 것이 좋아보입니다,

이슈 생성 부탁드립니다.

리베이스 요청드립니다.

@ckdals4600 ckdals4600 force-pushed the feature/#163-og-image-s3-upload-when-link-add branch 2 times, most recently from 4006eef to 50af5c9 Compare January 2, 2026 14:18
@ckdals4600
Copy link
Contributor Author

@Goder-0 리베이스 완료하였습니다

@ckdals4600 ckdals4600 force-pushed the feature/#163-og-image-s3-upload-when-link-add branch from 50af5c9 to 3f1f7cd Compare January 4, 2026 22:40
@ckdals4600 ckdals4600 merged commit ae3e813 into main Jan 4, 2026
1 check passed
@ckdals4600 ckdals4600 deleted the feature/#163-og-image-s3-upload-when-link-add branch January 4, 2026 23:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

링크 생성 시 OG 이미지 S3 업로드 및 저장소 구축

4 participants