구현단계 보안약점 기준 - Private 배열에 Public 데이터 할당
유형 | 캡슐화 |
보안약점 | Private 배열에 Public 데이터 할당 |
개요 |
public으로 선언된 메소드의 인자가 private으로 선언된 배열에 저장되면, private배열을 외부에서 접근하여 배열 수정과 객체 속성 변경이 가능해진다.
|
보안대책 |
public으로 선언된 메서드의 인자를 private으로 선언된 배열로 저장되지 않도록 한다.
인자로 들어온 배열의 복사본을 생성하고 clone() 메소드로 복사된 원소를 저장하도록 하여 private변수에 할당하여 private으로 선언된 배열과 객체속성에 대한 의도하지 않게 수정되는 것을 방지한다.
만약 배열 객체의 원소가 String 타입 등과 같이 변경이 되지 않는 경우에는 인자로 들어온 배열의 복사본을 생성하여 할당한다.
|
진단방법 |
private 배열이 선언되어 있는지 확인하고, public 메소드의 인자로 받은 배열을 private 배열 필드에 직접 할당할 경우 취약하다고 판단한다.
이때 선언된 private 배열의 원소가 일반 객체일 경우 각 원소별로 객체를 생성하고 객체 내부의 값을 복사하는지 확인한다.
|
연관된 설계단계 기준 | - |
코드예제
● 안전하지 않은 코드 예 (Java) (배열의 원소가 일반객체일 경우)
// userRoles 필드는 private이지만, public인 setUserRoles()로 외부의 배열이 할당되면,
// 사실상 public 필드가 된다.
private UserRole[] userRoles;
public void setUserRoles(UserRole[] userRoles) {
this.userRoles = userRoles;
}
멤버 변수 userRoles는 private로 선언되었지만 public으로 선언된 setUserRoles 메소드로 인자가 할당되어 배열의 원소를 외부에서 변경할 수 있다. 이 경우 의도하지 않은 배열과 원소에 대한 객체속성 수정이 발생할 수 있다.
● 안전한 코드 예 (Java) (배열의 원소가 일반객체일 경우)
// 객체가 클래스의 private member를 수정하지 않도록 한다.
private UserRole[] userRoles;
public void setUserRoles(UserRole[] userRoles) {
this.userRoles = new UserRole[userRoles.length];
for (int i = 0; i < userRoles.length; ++i)
this.userRoles[i] = userRoles[i].clone();
}
인자로 들어온 배열의 복사본을 생성하고 clone() 메소드로 복사된 원소를 저장하도록 하여 private 변수에 할당하면 private으로 할당된 배열과 원소에 대한 의도하지 않은 수정을 방지할 수 있다.
● 안전하지 않은 코드 예 (Java) (배열의 원소가 String 타입 등과 같이 수정이 되지 않는 경우)
// userRoles 필드는 private이지만, public인 setUserRoles()로 외부의 배열이 할당되면,
// 사실상 public 필드가 된다.
private String[] userRoles;
public void setUserRoles(String[] userRoles) {
this.userRoles = userRoles;
}
멤버 변수 userRoles는 private로 선언되었지만 public으로 선언된 setUserRoles 메소드로 인자가 할당되어 배열의 원소를 외부에서 변경할 수 있다. 이 경우 의도하지 않은 배열에 대한 수정이 발생할 수 있다.
● 안전한 코드 예 (Java) (배열의 원소가 String 타입 등과 같이 수정이 되지 않는 경우)
// 객체가 클래스의 private member를 수정하지 않도록 한다.
private String[] userRoles;
public void setUserRoles(String[] userRoles) {
this.userRoles = new String[userRoles.length];
for (int i = 0; i < userRoles.length; ++i)
this.userRoles[i] = userRoles[i];
}
인자로 들어온 배열의 복사본을 생성하여 private변수에 할당하면 private으로 할당된 배열에 대한 의도하지 않은 수정을 수 있다.
● 안전하지 않은 코드 예 (C#)
class Program
{
// userRoles 필드는 private이지만, public인 setUserRoles()로
// 외부의 배열이 할당되면, 사실상 public 필드가 된다.
private String[] userRoles;
public void SetUserRoles(String[] userRoles)
{
this.userRoles = userRoles;
}
}
멤버 변수 userRoles는 private로 선언되었지만 public으로 선언된 setUserRoles 메소드로 인자가 할당되어 배열의 원소를 외부에서 변경할 수 있다. 이 경우 의도하지 않은 배열과 원소에 대한 객체속성 수정이 발생할 수 있다.
● 안전한 코드 예 (C#)
class Program
{
// 객체가 클래스의 private member를 수정하지 않도록 한다.
private String[] userRoles;
public void SetUserRoles(String[] userRoles)
{
int length = userRoles.Length;
this.userRoles = new String[length];
for(int i = 0; i < length; i++) {
this.userRoles[i] = userRoles[i];
}
}
}
객체가 클래스의 private member를 수정하지 않도록 하여야 한다.
진단방법

● 일반적인 진단의 예
public class U496 {
private String[] userRoles; ························①
public void setUserRoles(String[] userRoles) {
this.userRoles = userRoles; ····················②
}
public void print() {
for (int i = 0; i < userRoles.length; i++)
System.out.println(userRoles[i]);
}
}
● 정탐코드
private UserRole[] userRoles;
…
public void setUserRoles(UserRole[] userRoles) {
this.userRoles = new UserRole[userRoles.length];
for(int i =0; i < userRoles.length; i++) {
this.userRoles[i] = userRoles[i]; // 일반 객체일 경우 주소값만 복사된다.
}
}
새로운 배열을 새로 생성하고 for문을 이용하여 복사하였으나, 배열의 원소가 일반객체이기 때문에 원본(userRoles)의 주소값만 복사되어 취약하다.