-
Notifications
You must be signed in to change notification settings - Fork 3
Feature : Github OAuth 구현, OAuth 통합 컨트롤러, AES 암호화, Github access token 저장 #105
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
Changes from all commits
95ad89e
da65f9f
91823f4
76a1783
8913938
f1d943a
449b4a4
6cfda26
edd727c
825de30
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| package org.ezcode.codetest.application.usermanagement.user.dto.response; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
|
|
||
| @Schema(description = "Github OAuth2 응답 처리 클래스") | ||
| public class GithubOAuth2Response implements OAuth2Response{ | ||
| private final Map<String, Object> attributes; | ||
|
|
||
| public GithubOAuth2Response(Map<String, Object> attributes) { | ||
| this.attributes = attributes; | ||
| } | ||
|
|
||
| @Override | ||
| @Schema(description = "OAuth 제공자 이름", example = "github") | ||
| public String getProvider() { | ||
| return "github"; | ||
| } | ||
|
|
||
| @Override | ||
| @Schema(description = "제공자 내부 식별자", example = "109000123456789012345") | ||
| public String getProviderId() { | ||
| return attributes.get("id").toString(); | ||
| } | ||
|
|
||
| @Override | ||
| @Schema(description = "사용자 이메일", example = "[email protected]") | ||
| public String getEmail() { | ||
| if (attributes.get("email") == null && getProvider().equals("github")) { | ||
| return getGithubId()+"@github.com"; | ||
| } else { | ||
| return (String) attributes.get("email"); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| @Schema(description = "사용자 이름", example = "홍길동") | ||
| public String getName() { | ||
| return attributes.get("name").toString(); | ||
| } | ||
|
|
||
| @Override | ||
| @Schema(description = "Github Id", example = "1345932") | ||
| public String getGithubId() { | ||
| return attributes.get("id").toString(); | ||
| } | ||
|
|
||
| @Override | ||
| @Schema(description = "Github URL", example = "https://github.com/id") | ||
| public String getGithubUrl(){ | ||
| return attributes.get("html_url").toString(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,34 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package org.ezcode.codetest.common.security.util; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Base64; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.crypto.Cipher; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.crypto.spec.SecretKeySpec; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.beans.factory.annotation.Value; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Component; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Component | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class AESUtil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static final String ALGORITHM = "AES"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Value("${aes.secret.key}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private String SECRET_KEY; // 반드시 16, 24, 또는 32바이트 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
minjee2758 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public String encrypt(String input) throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Cipher cipher = Cipher.getInstance(ALGORITHM); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cipher.init(Cipher.ENCRYPT_MODE, keySpec); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| byte[] encryptedBytes = cipher.doFinal(input.getBytes()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Base64.getEncoder().encodeToString(encryptedBytes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+18
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 치명적인 보안 취약점: ECB 모드 사용 AES ECB 모드는 보안상 안전하지 않습니다. 같은 평문이 같은 암호문을 생성하므로 패턴 분석이 가능합니다. CBC 또는 GCM 모드를 사용해야 합니다. -public String encrypt(String input) throws Exception {
- SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
- Cipher cipher = Cipher.getInstance(ALGORITHM);
- cipher.init(Cipher.ENCRYPT_MODE, keySpec);
- byte[] encryptedBytes = cipher.doFinal(input.getBytes());
- return Base64.getEncoder().encodeToString(encryptedBytes);
+public String encrypt(String input) throws Exception {
+ if (SECRET_KEY.getBytes().length != 16 && SECRET_KEY.getBytes().length != 24 && SECRET_KEY.getBytes().length != 32) {
+ throw new IllegalArgumentException("AES key must be 16, 24, or 32 bytes");
+ }
+
+ SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec);
+
+ byte[] iv = cipher.getIV();
+ byte[] encryptedBytes = cipher.doFinal(input.getBytes("UTF-8"));
+
+ // IV와 암호문을 함께 저장
+ byte[] combined = new byte[iv.length + encryptedBytes.length];
+ System.arraycopy(iv, 0, combined, 0, iv.length);
+ System.arraycopy(encryptedBytes, 0, combined, iv.length, encryptedBytes.length);
+
+ return Base64.getEncoder().encodeToString(combined);
}📝 Committable suggestion
Suggested change
🧰 Tools🪛 ast-grep (0.38.1)[warning] 19-19: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES. (desede-is-deprecated-java) [warning] 19-19: 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. (use-of-aes-ecb-java) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public String decrypt(String encryptedInput) throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Cipher cipher = Cipher.getInstance(ALGORITHM); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cipher.init(Cipher.DECRYPT_MODE, keySpec); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| byte[] encryptedBytes = Base64.getDecoder().decode(encryptedInput); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| byte[] decryptedBytes = cipher.doFinal(encryptedBytes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new String(decryptedBytes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+26
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 복호화 메서드도 보안 모드로 업데이트 필요 암호화 메서드와 동일하게 CBC 모드를 사용하도록 수정해야 합니다. -public String decrypt(String encryptedInput) throws Exception {
- SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
- Cipher cipher = Cipher.getInstance(ALGORITHM);
- cipher.init(Cipher.DECRYPT_MODE, keySpec);
- byte[] encryptedBytes = Base64.getDecoder().decode(encryptedInput);
- byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
- return new String(decryptedBytes);
+public String decrypt(String encryptedInput) throws Exception {
+ if (SECRET_KEY.getBytes().length != 16 && SECRET_KEY.getBytes().length != 24 && SECRET_KEY.getBytes().length != 32) {
+ throw new IllegalArgumentException("AES key must be 16, 24, or 32 bytes");
+ }
+
+ byte[] combined = Base64.getDecoder().decode(encryptedInput);
+
+ // IV 추출 (처음 16바이트)
+ byte[] iv = new byte[16];
+ byte[] encryptedBytes = new byte[combined.length - 16];
+ System.arraycopy(combined, 0, iv, 0, 16);
+ System.arraycopy(combined, 16, encryptedBytes, 0, encryptedBytes.length);
+
+ SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
+
+ byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
+ return new String(decryptedBytes, "UTF-8");
}필요한 import 추가: +import javax.crypto.spec.IvParameterSpec;
+import java.nio.charset.StandardCharsets;📝 Committable suggestion
Suggested change
🧰 Tools🪛 ast-grep (0.38.1)[warning] 27-27: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES. (desede-is-deprecated-java) [warning] 27-27: 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. (use-of-aes-ecb-java) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.