Skip to content

refactor: answerNumber , answer 값 AES 대칭키 적용#425

Open
Ksr-ccb wants to merge 4 commits intodevfrom
feat/300
Open

refactor: answerNumber , answer 값 AES 대칭키 적용#425
Ksr-ccb wants to merge 4 commits intodevfrom
feat/300

Conversation

@Ksr-ccb
Copy link
Member

@Ksr-ccb Ksr-ccb commented Sep 26, 2025

🔎 작업 내용

  • 문제 출제 페이지에서 정답、 코멘트가 따로 가려지지않고 노출되던 문제가 있었음。
  • 따라서、 answer/commentary 두 컬럼에는 프론트와 통신 시 aes 대칭키를 적용하도록 함。

🛠️ 변경 사항

- 임시 api 만들어서 적용해봤음。현재는 주석처리 되어있음.

  • 적용한 AES 대칭키는 AES-16-CBC 임.
image 스크린샷 2025-09-26 152610 image 스크린샷 2025-09-26 152711

📌 참고 사항


🙏 코드 리뷰 전 확인 체크리스트

  • 불필요한 콘솔 로그, 주석 제거
  • 커밋 메시지 컨벤션 준수 (type : )
  • 기능 정상 동작 확인

Summary by CodeRabbit

  • 신기능
    • 퀴즈의 정답 및 해설 데이터에 AES 기반 암호화를 적용하여 전송 구간 보안을 강화했습니다. 사용자 경험에는 변화가 없습니다.
  • 기타
    • 암호화 키를 위한 환경설정 항목이 추가되었습니다.
    • 향후 기능 확장을 위한 컨트롤러 구성 정리가 포함되었으나 현재 동작에는 영향이 없습니다.

권새롬 added 3 commits September 9, 2025 16:54
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 26, 2025

Walkthrough

QuizTestController에 QuizPageService 의존성이 추가되고 생성자 시그니처가 변경되었습니다. QuizPageService는 AesUtil을 주입 받아 다중선택·서술형 퀴즈 응답의 정답·해설 필드를 AES/CBC로 암호화하도록 변경되었습니다. 새로운 AesUtil 클래스와 aes.secret.key 설정이 추가되었습니다.

Changes

Cohort / File(s) Summary
Controller wiring
cs25-service/src/main/java/com/example/cs25service/domain/quiz/controller/QuizTestController.java
QuizPageService 주입(필드/생성자) 추가 및 TodayQuiz 관련 import/주석화된 엔드포인트 존재. 런타임 동작의 활성 엔드포인트 변경 없음.
Service encryption integration
cs25-service/src/main/java/com/example/cs25service/domain/quiz/service/QuizPageService.java
AesUtil 주입 추가. getMultipleQuiz/getDescriptiveQuiz 등에서 정답(answer/answerNumber) 및 commentary 필드를 aesUtil.encrypt(...)로 암호화하여 응답 DTO에 설정. 메서드 시그니처는 변경 없음.
Crypto utility addition
cs25-service/src/main/java/com/example/cs25service/domain/quiz/util/AesUtil.java
신규 클래스 추가: AES/CBC/PKCS5Padding 기반 encrypt/decrypt 구현, 랜덤 IV 생성 및 IV+암호문을 Base64로 인코딩/디코딩, Spring @Value로 키 주입.
Configuration
cs25-service/src/main/resources/application.properties
새 설정 추가: aes.secret.key=${AES_KEY}(환경변수/참조). 기존 FRONT_END_URI=https://cs25.co.kr 유지 및 로컬 주석 라인 재추가.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as 클라이언트
  participant QPS as QuizPageService
  participant AES as AesUtil

  C->>QPS: getMultipleQuiz()/getDescriptiveQuiz(...)
  activate QPS
  QPS->>QPS: DTO 필드 구성(정답/해설 포함)
  QPS->>AES: encrypt(answer / answerNumber / commentary)
  activate AES
  AES-->>QPS: Base64(IV + ciphertext)
  deactivate AES
  QPS-->>C: 암호화된 answer/commentary가 포함된 DTO 반환
  deactivate QPS

  Note over QPS,AES: 변경점: 응답 전 민감 필드 암호화 추가
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • Kimyoonbeom
  • jong-0126
  • HeeMang-Lee
  • wannabeing
  • crocusia

Poem

작은 토끼가 열쇠를 들고 와서 속삭였네 🔑
"정답은 살짝 감싸줄게, IV가 곁에 있어" 🐰
바이트 춤추며 Base64로 입혀지고
컨트롤러는 고개 끄덕이고 서비스는 속삭여
오늘 퀴즈, 비밀은 안전히 포장되었네 ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Title Check ✅ Passed 이 PR 제목은 answerNumber와 answer 값에 AES 대칭키를 적용한다는 주요 변경사항을 명확히 요약하고 있으며 간결하고 가독성이 높습니다. 적절한 Conventional commit 스타일을 따르고 불필요한 정보가 없어 스캔 시 변경 목적을 쉽게 파악할 수 있습니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/300

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Ksr-ccb Ksr-ccb self-assigned this Sep 26, 2025
@Ksr-ccb Ksr-ccb linked an issue Sep 26, 2025 that may be closed by this pull request
@Ksr-ccb Ksr-ccb changed the title feat: answerNumber , answer 값 AES 대칭키 적용 /프론트 테스트필요)) refactor: answerNumber , answer 값 AES 대칭키 적용 /프론트 테스트필요)) Sep 26, 2025
@Ksr-ccb Ksr-ccb added refactor upgrade function chore 간단한 수정 labels Sep 26, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
cs25-service/src/main/java/com/example/cs25service/domain/quiz/controller/QuizTestController.java (1)

4-19: 불필요한 서비스 주입 및 import 정리 제안

현재 QuizPageService, TodayQuizResponseDto, PathVariable, RequestParam 모두 주석 처리된 엔드포인트에서만 쓰이며 실제 코드 경로에서는 사용되지 않아 경고(또는 스타일 검사 실패)의 원인이 됩니다. 테스트 엔드포인트를 당장 노출하지 않을 계획이라면, 관련 의존성과 필드를 제거해 두는 편이 안전합니다. 추후 활성화 시 다시 추가하면 됩니다.

적용 가능한 변경 예시는 아래와 같습니다:

-import com.example.cs25service.domain.quiz.dto.TodayQuizResponseDto;
 import com.example.cs25service.domain.quiz.service.QuizAccuracyCalculateService;
-import com.example.cs25service.domain.quiz.service.QuizPageService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
@@
-    private final QuizPageService quizPageService;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7292db0 and ffcc148.

📒 Files selected for processing (4)
  • cs25-service/src/main/java/com/example/cs25service/domain/quiz/controller/QuizTestController.java (2 hunks)
  • cs25-service/src/main/java/com/example/cs25service/domain/quiz/service/QuizPageService.java (4 hunks)
  • cs25-service/src/main/java/com/example/cs25service/domain/quiz/util/AesUtil.java (1 hunks)
  • cs25-service/src/main/resources/application.properties (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cs25-service/src/main/java/com/example/cs25service/domain/quiz/controller/QuizTestController.java (1)
cs25-service/src/main/java/com/example/cs25service/domain/quiz/controller/QuizPageController.java (1)
  • RestController (11-28)
🪛 ast-grep (0.39.5)
cs25-service/src/main/java/com/example/cs25service/domain/quiz/util/AesUtil.java

[warning] 32-32: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: Cipher.getInstance(ALGORITHM)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA

(desede-is-deprecated-java)


[warning] 62-62: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: Cipher.getInstance(ALGORITHM)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA

(desede-is-deprecated-java)


[warning] 32-32: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: Cipher.getInstance(ALGORITHM)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html

(use-of-aes-ecb-java)


[warning] 62-62: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: Cipher.getInstance(ALGORITHM)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html

(use-of-aes-ecb-java)

Comment on lines +61 to 63
.answerNumber(aesUtil.encrypt(answerNumber))
.commentary(aesUtil.encrypt(quiz.getCommentary()))
.quizType(quiz.getType().name())
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

암호화로 인해 기존 응답 스키마가 깨집니다

Line 61과 Line 79에서 바로 암호화된 값을 내려보내면 /todayQuiz 실제 엔드포인트를 소비하는 기존 프런트가 즉시 깨집니다(현재 배포본은 복호화 로직이 없음). 프런트 적용이 완료될 때까지는 최소한 기능 플래그나 엔드포인트 버전 분리로 기존 소비자에게 평문을 유지해야 합니다.

Also applies to: 79-80

Comment on lines +17 to +27
private final String secretKey;

public AesUtil(@Value("${aes.secret.key}") String secretKey) {
this.secretKey = secretKey;
}

private final String ALGORITHM = "AES/CBC/PKCS5Padding";

private SecretKey getKey() {
return new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

비정상 AES 키 길이 허용으로 인한 런타임 실패 위험

현재 secretKey를 그대로 보관했다가 SecretKeySpec을 매번 만들고 있습니다. 프로퍼티 값이 16·24·32바이트가 아니거나 UTF-8 멀티바이트 문자를 포함하면 Cipher.init() 단계에서 InvalidKeyException이 발생해 암·복호화가 모두 실패합니다. PR 설명에도 48바이트 키 사용 가능하다고 적혀 있어 실제로 그렇게 설정하면 바로 장애가 납니다. 생성자에서 키 길이를 검증하고, 한 번 생성한 SecretKey를 재사용하도록 수정해 주세요.

-    private final String secretKey;
-
-    public AesUtil(@Value("${aes.secret.key}") String secretKey) {
-        this.secretKey = secretKey;
-    }
-
-    private SecretKey getKey() {
-        return new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
-    }
+    private final SecretKey secretKey;
+
+    public AesUtil(@Value("${aes.secret.key}") String secretKey) {
+        byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
+        if (keyBytes.length != 16 && keyBytes.length != 24 && keyBytes.length != 32) {
+            throw new IllegalArgumentException("aes.secret.key는 16, 24 또는 32바이트여야 합니다.");
+        }
+        this.secretKey = new SecretKeySpec(keyBytes, "AES");
+    }
+
+    private SecretKey getKey() {
+        return secretKey;
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private final String secretKey;
public AesUtil(@Value("${aes.secret.key}") String secretKey) {
this.secretKey = secretKey;
}
private final String ALGORITHM = "AES/CBC/PKCS5Padding";
private SecretKey getKey() {
return new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
}
// Replace the String-backed key with a pre-validated, cached SecretKey
private final SecretKey secretKey;
public AesUtil(@Value("${aes.secret.key}") String secretKey) {
byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
if (keyBytes.length != 16 && keyBytes.length != 24 && keyBytes.length != 32) {
throw new IllegalArgumentException("aes.secret.key는 16, 24 또는 32바이트여야 합니다.");
}
this.secretKey = new SecretKeySpec(keyBytes, "AES");
}
private final String ALGORITHM = "AES/CBC/PKCS5Padding";
private SecretKey getKey() {
return secretKey;
}

@Ksr-ccb Ksr-ccb changed the title refactor: answerNumber , answer 값 AES 대칭키 적용 /프론트 테스트필요)) refactor: answerNumber , answer 값 AES 대칭키 적용 Sep 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore 간단한 수정 refactor upgrade function

Projects

None yet

Development

Successfully merging this pull request may close these issues.

오늘의 문제 페이지 response 값 가리기

1 participant