2015. 3. 4. 13:15
이번에 다이나믹 쿼리를 이용하여 간단히 데이터 배치작업을 하려고 만든 프로그램에서 에러가 발생했다.
평소엔 SQL-MAP 파일에 SQL Injection이 발생할 수 있는 코드는 사용하지 않았기 때문에 이런 문제가 발생하지 않았는데 배치작업을 위해 여러 테이블에서 두루 사용하기 위한 쿼리문을 등록하려다 보니 자연히 SQL Injection이 발생될 수 있는(보안상 안좋은) 쿼리를 등록해서 사용하게 되었다.

문제의 쿼리는 아래와 같았다.
<select id="getList" parameterClass="map" resultClass="java.util.HashMap">
SELECT
<iterate property="fieldName" prepend=",">
$fieldName[]$
</iterate>
FROM
$tableName$
WHERE
$condition$
</select>
여러 테이블을 조회하기 때문에 파라미터로 입력되는 모든 값들이 변경될 수 있다.
호출은 아래와 같이 했다.
List fieldList = new ArrayList();
fieldList.add("foo");
fieldList.add("bar");
Map map = new HashMap();
map.put("tabeName", "Hello");
map.put("condition", "idx > 0");
map.put("fieldName", fieldList);
List<Map> result = sqlMapClient.queryForList("map-id.getList", map);
위의 코드가 한번만 호출이 된다면 아무런 문제가 없이 해결이 된다.
하지만 아래와 같이 fieldList와 tableName이 변경하여 다시 조회하면 에러가 발생한다.

List fieldList = new ArrayList();
fieldList.add("foo2");
fieldList.add("bar2");
Map map = new HashMap();
map.put("tabeName", "Hello2");
map.put("condition", "idx > 0");
map.put("fieldName", fieldList);
List<Map> result = sqlMapClient.queryForList("map-id.getList", map);
이는 iBatis에서 SQL-ID가 한번 실행되면 쿼리의 Meta Data를 캐쉬하고 있기 때문으로 다음번에 호출되었을 때 이미 캐쉬에 저장된 foo, bar 필드를 쿼리결과에서 찾는데 필드가 없기 때문(foo2, bar2가 존재할 뿐)에 에러를 리턴하게 된다. MetaData의 캐쉬를 하지 않으려면 쿼리를 다음과 같이 변경해야 한다.

<select id="getList" parameterClass="map" resultClass="java.util.HashMap" remapResults="true">
SELECT
<iterate property="fieldName" prepend=",">
$fieldName[]$
</iterate>
FROM
$tableName$
WHERE
$condition$
< /select>

http://kamkami.tistory.com/102

Posted by 물색없는세상