🗂️ Etc

다이나믹 쿼리 사용 시 간과할 수 있는 개인정보 유출 문제(Feat. iBatis, myBatis, QueryDsl)

loose 2022. 9. 8. 16:09
반응형

최근 회사에서 개인정보 유출 이슈가 발생했다.

해당 이슈 사항은 굉장히 큰 부분이라 전사적으로 뒤집어진 사건이었고(자세한건 잡혀갈까봐 말을 못하고)

원인은 너무 사소한 곳에 있던 문제였다.

 

원인은 다이나믹 쿼리 사용 시 개인정보에 관한 컬럼에 조건문을 사용했기 때문이다.

 

iBatis

<isNotEmpty property="custId">
AND CUST_ID = #custId#
</isNotEmpty>

myBatis

<if test="custId != ''">
AND CUST_ID = #{custId}
</if>

 

custId는 고객 ID에 관한 컬럼이다.

iBatis, myBatis를 사용한다면 위와 같은 코드를 많이 마주치게 될 것이다.

위의 코드는 문제가 있는 코드다.

의외로 위와 같은 코드는 아래와 같은 생각으로 쉽게 발생할 수 있다.

매개변수가 매번 달라지니 다이나믹 쿼리를 사용하자.
근데 하나하나 쓰기 귀찮으니 다른데서 복사해서 붙여넣어야지.
조건문도 있으면 null일 때 에러는 안나겠다 갖다 써야지.

그리고 테스트 그리고 운영 환경에서 고객 ID 컬럼은 안들어가는 경우는 없었기 때문에 위의 쿼리는 약 수십개월동안 문제가 없었다.

근데 만약 어떠한 이유에서 custId에 null 값이 들어가버린다면 어떻게 될까?

 

If문 필터링에 통과하지 못해 AND 조건문이 아예 사라지게 된다. 그리고 조건문은 전체 고객을 대상으로 ALL 조회를 실행하게 된다.

 

개인정보를 바탕으로 if문을 사용하려고 할 때는 매개변수가 있는지 없는지가 아니라 무조건 있어야한다 라고 가정하고 쿼리를 작성해야한다. 

 

다시 한번 강조하자면 if문이라는 것은 기본적으로 "해당 매개변수가 있는지 검사하고 있을 경우에만 조건을 넣겠다"라는 아주 기초 상식 수준을 갖고 써야하는 명령어지만 개발자가 안일하게 복붙+생각안함의 습관으로 충분히 간과할 수 있는 부분이다.

 

단순히 아래처럼 적어줬으면 보안 문제는 발생하지 않았을 것이다. null이 들어오면 에러를 뱉고 끝내면 될 문제다.

AND CUST_ID = #{custId}

QueryDsl

private BooleanExpression userIdEq(String custId) {
	if (StringUtils.isEmpty(custId)) {
		return null;
	}
	if (custId == null ) {
		return null;
	}
	if (custId != null ) {
		return customer.userId.eq(custId);
	}
}

 

QueryDsl 사용 역시 마찬가지다.

(물론 JPA를 사용하는 프로젝트 특성상 Controller에서 @Valid 를 걸면 상대적으로 위험이 줄어든다. 하지만 서버 내부에서 값을 Parsing 하는 과정이나 값에 대한 암복호화시 값이 다시 null로 변경될 우려는 충분히 있다.)

 

개발자는 또 역시 where 조건을 걸기 위해 본인이 직접 작성하지 않고 다른데서 사용하는 BooleanExpression 메소드를 복사해올 수 있다.

그리고 자연스럽게 복사해온 메소드에 매개변수 쪽만 custId로 바꿔서 개발할 여지는 충분하다.

그러면 매개변수가 없을 때 null을 리턴해주기 때문에 이 역시 where 조건을 빼버리고 쿼리를 실행할 것이다.

그럼 이것도 위와같이 똑같은 유출 사고로 이어진다.

 

번외로 BooleanExpression에서 자주 사용하는 StringUtils.isEmpty역시 생각을 하고 써야한다. 이 메소드는 아래와 같은 기준을 가진다.

StringUtils.isEmpty(null)      = true
StringUtils.isEmpty("")        = true  

단순히 비어있나 정도로만 검사하지말고 null과 ""인 경우면 어떻게 작동할까하고 생각을 하고 쓰는게 좋다.

생각없이 사용했다면 ""값도 체크해서 null로 리턴하는(위의 조건식에서는 적어도 ""는 if 필터에 안걸려서 조건문이 사용된다.) StringUtils.isEmpty가 더 큰 문제가 발생할 수도 있다.

 

너무 당연한 부분이라고 느낄 사람도 있겠지만 if문 한줄로 대형사고가 생길 수도 있기 때문에 적어보는 글이다.

728x90