- 잘못된 세션에 의한 정보 노출
멤버 변수 - 클래스 수준에서 정의된 변수 (객체가 살아있는 동안 계속 유지)(힙 영역)
지역 변수 - 메서드 안에서만 사용되고, 메서드가 끝나면 메모리에서 사라짐(스택 영역)
- currentUser가 클래스의 멤버 변수로 선언되어 있다. 따라서 이 클래스가 여러 사용자 요청을 처리한다면, 다른 사용자가 currentUser 정보에 접근할 수 있는 것이다.public class UserHandler { private User currentUser; // 멤버 변수 public void handleRequest(HttpServletRequest request) { HttpSession session = request.getSession(); this.currentUser = (User) session.getAttribute("user"); } }
개선코드
public class UserHandler {
public void handleRequest(HttpServletRequest request) {
HttpSession session = request.getSession();
User currentUser = (User) session.getAttribute("user"); // 지역 변수
// 이후 로직 처리
}
}
2️⃣ Public 메서드로부터 반환된 Private 배열
🔍 개념 설명:
Private 필드는 외부에서 직접 접근 못하게 막지만, public 메서드를 통해 내부 배열을 반환하면 외부에서도 해당 배열을 수정할 수 있어 캡슐화가 깨지고 보안이 약해집니다.
🧨 문제 예시:
public class User {
private String[] roles = {"user", "admin"};
public String[] getRoles() {
return roles; // 내부 배열을 직접 반환
}
}
// 외부 코드에서:
user.getRoles()[0] = "hacker"; // 내부 배열이 바뀜!
🛡️ 해결 방법:
1.깊은 복사본 반환
public String[] getRoles() {
return Arrays.copyOf(roles, roles.length);
}
2.불변 컬렉션 반환
public List<String> getRoles() {
return Collections.unmodifiableList(Arrays.asList(roles));
}
3️⃣ Private 배열에 Public 데이터 할당
🔍 개념 설명:
외부(public) 데이터를 private 배열에 그대로 참조로 저장하면, 외부에서 해당 배열을 변경할 수 있어 객체의 내부 상태가 예상치 않게 바뀝니다.
🧨 문제 예시:
public class User {
private String[] roles;
public void setRoles(String[] inputRoles) {
this.roles = inputRoles; // 참조를 직접 저장
}
}
String[] roles = {"user"};
User user = new User();
user.setRoles(roles);
// 외부 배열을 변경하면 내부 상태도 같이 바뀜
roles[0] = "admin"; // user 객체 내부도 변경됨
🛡️ 해결 방법:
- 입력 값 복사해서 저장 (Defensive Copying)
public void setRoles(String[] inputRoles) {
this.roles = Arrays.copyOf(inputRoles, inputRoles.length);
}
🧾 1. 얕은 복사 (Shallow Copy)
📌 개념:
객체를 복사할 때 겉모습만 복사하고, 내부 참조 객체는 원본과 같은 주소를 공유하는 방식입니다.
📦 특징:
- 필드가 기본 타입(int, boolean 등)인 경우 → 값 자체 복사
- 필드가 참조 타입(배열, 객체 등)인 경우 → 참조 주소만 복사 (공유됨)
🧨 문제점:
복사본을 수정하면 원본 객체에도 영향을 줄 수 있음
✅ 예제 (Java):
class Person {
String name;
int[] scores;
Person(String name, int[] scores) {
this.name = name;
this.scores = scores;
}
}
int[] scores = {90, 80};
Person original = new Person("Alice", scores);
Person copy = original; // 얕은 복사
copy.scores[0] = 100;
System.out.println(original.scores[0]); // 100 → 원본도 바뀜!
🧾 2. 깊은 복사 (Deep Copy)
📌 개념:
객체뿐만 아니라 그 내부에 포함된 모든 참조 객체까지 새롭게 복사하는 방식입니다.
📦 특징:
- 원본과 복사본이 완전히 독립된 구조
- 복사본을 수정해도 원본에는 영향 없음
class Person {
String name;
int[] scores;
Person(String name, int[] scores) {
this.name = name;
// 깊은 복사: 배열도 새로 복사
this.scores = Arrays.copyOf(scores, scores.length);
}
}
이렇게 하면 scores 배열을 변경해도 원본에는 영향을 주지 않는다.
🧾 3. 불변 컬렉션 (Immutable Collection)
📌 개념:
수정이 불가능한 컬렉션입니다. 생성 후에는 add, remove, set 같은 변경 작업이 전혀 불가능합니다.
📦 특징:
- 안전하게 외부에 반환 가능 (내부 상태 보호)
- 멀티스레드 환경에서도 안정성 ↑
- 변경하려면 새 인스턴스를 만들어야 함
List<String> roles = Collections.unmodifiableList(Arrays.asList("user", "admin"));
roles.add("hacker"); // UnsupportedOperationException 발생
List<String> roles = List.of("user", "admin");
📊 비교 요약
항목얕은 복사깊은 복사불변 컬렉션
내부 참조 공유 | ✅ (공유함) | ❌ (새로 생성) | ✅ (참조 가능하지만 수정 불가) |
원본 영향 가능성 | 높음 | 없음 | 없음 |
안전성 | 낮음 | 높음 | 매우 높음 |
성능 | 빠름 | 느릴 수 있음 | 빠름 (단, 변경 불가) |
copyOf() – 보통 "복사" (깊은 or 얕은)
📌 의미:
copyOf()는 기존 컬렉션(또는 배열)을 복사해서 새 객체를 만든다는 의미입니다.
하지만 깊은 복사인지 얕은 복사인지는 요소의 타입에 따라 다릅니다.
📍 예: Arrays.copyOf()
int[] original = {1, 2, 3};
int[] copied = Arrays.copyOf(original, original.length);
- 이 경우는 int 배열이므로 진짜 깊은 복사 (값 자체 복사)
- 하지만 객체 배열일 경우 내부 객체까지 복사하지는 않음 → 얕은 복사
String[] original = {"a", "b"};
String[] copied = Arrays.copyOf(original, original.length);
copied[0] = "x"; // 이건 값이니까 OK
// 하지만 만약 원소가 mutable 객체라면 내부는 공유됨 (얕은 복사)
✔️ 핵심:
- copyOf()는 "새로운 객체를 만든다" (✅)
- 하지만 "항상 깊은 복사"는 아니다 (⚠️)
- 내부 객체까지 완전히 복사하려면 개별적으로 clone()하거나 새로 생성해야 함
✅ of() – 보통 "새로운 불변 객체 생성"
📌 의미:
Java 9+의 List.of(), Set.of() 등은 새로운 컬렉션 객체를 만들되, 불변(immutable)한 형태로 생성합니다.
List<String> names = List.of("Alice", "Bob");
names.add("Charlie"); // ❌ UnsupportedOperationException
✔️ 핵심:
- of()는 항상 새 객체를 만든다 (✅)
- 그리고 **불변(immutable)**이다 (✅)
- 하지만 내부 요소가 참조 타입이면, 여전히 내부 내용은 수정 가능할 수도 있음 (⚠️)
List<List<String>> list = List.of(new ArrayList<>(List.of("a")));
list.get(0).add("b"); // 내부는 바뀔 수 있음
🔁 정리 비교
메서드새 객체 생성깊은 복사불변
copyOf() | ✅ 대부분 | ❌ (얕은 복사 가능성 있음) | ❌ |
of() | ✅ 항상 | ❌ (복사 X, 그냥 새 객체 생성) | ✅ |
그럼 객체의 깊은 복사의 경우 직접 구현 or 라이브러리 사용
이유 1: 깊은 복사의 정의는 상황에 따라 다름
- 어떤 필드는 복사하고, 어떤 필드는 공유해도 되는지 비즈니스 로직마다 달라요
- 예: 비밀번호 필드는 복사 안 함 / 리스트는 복사하되 ID는 그대로 유지 등
📌 이유 2: 자바의 기본 clone()은 얕은 복사
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 얕은 복사
}
내부에 참조 타입(객체, 배열 등)이 있으면 그 참조 주소만 복사됨
✅ 직접 깊은 복사 구현 방법
예: 사용자 정의 클래스에서 deep copy 만들기
public class Address {
String city;
public Address(String city) {
this.city = city;
}
public Address deepCopy() {
return new Address(this.city);
}
}
public class User {
String name;
Address address;
public User(String name, Address address) {
this.name = name;
this.address = address;
}
public User deepCopy() {
return new User(this.name, this.address.deepCopy());
}
}
➡️ 이렇게 하면 User와 Address 객체 모두 독립적으로 존재하게 돼요.
'CS' 카테고리의 다른 글
디자인 패턴 (0) | 2025.04.15 |
---|---|
객체의 응집도 정리 (1) | 2025.04.15 |
SQL 집계 함수, 그룹 함수, 윈도우 함수 (0) | 2025.04.07 |
Mysql 사용 시 조언 (0) | 2025.02.25 |
TCP/IP 이해 (0) | 2024.11.11 |