-
[MSSQL] 프로시저 동적쿼리 작성시 SQL Injection 우회 방법DB 2019. 6. 3. 23:37
팀Slack방에 에러가 올라와서 Kibana에서 trace를 찾아보니
상품명 조회 파라미터에 ' (싱글쿼터)가 들어 온 것이었다.
" 엥? lucy필터를 사용하고 있을탠대??? "
(lucy필터는 네이버에서 만든 XSS 방지 라이브러리이다)
싱글쿼터가 들어오면 오면 치환이 되어야 됬는대 안된 것이다.싱글쿼터가 들어오게되면 SQL Injection에 취약해 질수 있기 때문에 매우 위험한 상황이었다.
(최근에 "여기어*" 라는 숙박 서비스가 SQL Injection으로 약 100만명의 정보가 유출된 사건도 있었다.)
그래서 우리팀의 담당하고 있는 매뉴들에 대해서 a' or 1=1 or 'a'='a와 같은 문자열을 입력하니.
모든 데이터가 촥! ...OTL
이제서야 알게되었지만 lucy필터는 form-data에 대해서만 적용되고
Request Raw Body로 넘어가는 JSON에 대해서는 처리해 주지 않는다
어설프게 그냥 용도 정도만 " lucy필터가 XSS처리해주는 구나~" 하고 대충 넘어 갔던게 후회됬다..
(참고 lucy-xss-servlet-filter의 한계)팀내의 주요 API는 모두 RequestBody를 통해서 데이터를 받고 있었다. 그러니 당연히 필터링이 전혀안될 수 밖에.
이 이슈에대해서 팀원들과 회의를 한 결과 공수가 적게 드는 쪽으로 방향을 맞추기로 했다.
팀내 특성상(?) 쿼리를 프로시저에 작성하고있는대.
프로시저중에서도 문자열을 합쳐서 만든 동적쿼리들에 대해서만 문제가 발생했다.
아래는 검색화면에서 사용하는 SP와 유사하게 만든 것이다.
123456789101112131415161718192021222324252627282930313233343536373839404142434445USE [cm]GO/****** Object: StoredProcedure [dbo].[SQLINJECTION] Script Date: 2019-06-04 오후 9:27:27 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOALTER PROCEDURE [dbo].[SQLINJECTION]@pi_searchKeyword NVARCHAR(MAX),@pi_start_date NVARCHAR(10),@pi_end_date NVARCHAR(10)ASBEGINSET NOCOUNT ON;DECLARE@v_select_sql NVARCHAR(MAX) = '',@v_from_sql NVARCHAR(MAX) = '',@v_where_sql NVARCHAR(MAX) = '',@v_sql NVARCHAR(MAX) =''SET @v_select_sql += 'select top 100 * 'SET @v_from_sql += ' from tb_user with(nolock) 'IF @pi_start_date <> '' and @pi_end_date <> ''BEGINSET @v_where_sql += ' where user_reg_date between ''' + @pi_start_date + ''' and '''+ @pi_end_date + ''''ENDIF @pi_searchKeyword <> ''BEGINSET @v_where_sql += 'and user_name='+ '''' + @pi_searchKeyword + ''''ENDSET @v_sql = @v_select_sql + @v_from_sql + @v_where_sqlPRINT @v_sqlEXECUTE SP_EXECUTESQL @v_sqlENDcs SQL Injection은 바로 35행에서 발생한다.
문자열인 싱글쿼터로 값을 감싸고 있기때문이다
myBatis의 #{}을 쓴다해도, 프로시저 내부에서 싱글쿼터를 붙이기때문에 무용지물이다.
그래서 어떻게 처리했는대?
QUOTENAME()함수를 사용해서 처리했다.
https://docs.microsoft.com/ko-kr/sql/t-sql/functions/quotename-transact-sql?view=sql-server-2017
특정 구분자를 양옆으로 감싸주는 것이다.(문자열에 대해서만 처리하였음)
22행, 35행, 36행이 수정한 내용이다
12345678910111213141516171819202122232425262728293031323334353637383940414243444546USE [cm]GOSET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOALTER PROCEDURE [dbo].[SQLINJECTION]@pi_searchKeyword NVARCHAR(MAX),@pi_start_date NVARCHAR(10),@pi_end_date NVARCHAR(10)ASBEGINSET NOCOUNT ON;DECLARE@v_select_sql NVARCHAR(MAX) = '',@v_from_sql NVARCHAR(MAX) = '',@v_where_sql NVARCHAR(MAX) = '',@v_sql NVARCHAR(MAX) ='',@v_quote NVARCHAR(MAX)SET @v_select_sql += 'select top 100 * 'SET @v_from_sql += ' from tb_user with(nolock) 'IF @pi_start_date <> '' and @pi_end_date <> ''BEGINSET @v_where_sql += ' where user_reg_date between ''' + @pi_start_date + ''' and '''+ @pi_end_date + ''''ENDIF @pi_searchKeyword <> ''BEGINSET @v_quote = QUOTENAME(@pi_searchKeyword,'''')SET @v_where_sql += 'and user_name=' + @v_quoteENDSET @v_sql = @v_select_sql + @v_from_sql + @v_where_sqlPRINT @v_sqlEXECUTE SP_EXECUTESQL @v_sqlENDcs 수정전
' or 1=1 or 'a'='a 입력시 실행되는 SP내용
1select top 100 * from tb_user with(nolock) where user_reg_date between '2018-01-01' and '2019-12-31'and user_name='' or 1=1 or 'a'='a'cs
수정후' or 1=1 or 'a'='a 입력시 실행되는 SP내용
1select top 100 * from tb_user with(nolock) where user_reg_date between '2018-01-01' and '2019-12-31'and user_name=''' or 1=1 or ''a''=''a'cs or 1=1 or 'a'='a 입력시 실행되는 SP내용
1select top 100 * from tb_user with(nolock) where user_reg_date between '2018-01-01' and '2019-12-31'and user_name='or 1=1 or ''a''=''a'cs TO BE 쿼리의 뒤쪽 문자열을 보면 싱글쿼터로 인젝션을 무효화 시키는 것을 볼 수 있다.
처리하긴 하였지만 아쉬운점은 사실이다. 처음에 이 이슈가 발생했을 때 필터를 적용해보고 싶었지만..
그럴수 없는 상황이었기 때문에 이렇게 우회하는 방법으로 처리하였다.
더 좋은 방법이 있으면 댓글 부탁드립니다 ^^
'DB' 카테고리의 다른 글
[MSSQL] 스키마, 데이터 추출 스크립트 생성 방법 (링크) (0) 2020.02.08 [Maria DB & MySQL] 사용자 권한 주기 (0) 2019.10.23 [MSSQL] SCOPE_IDENTITY() (0) 2019.02.24 [MSSQL] 인덱스 만드는 방법 (툴or쿼리) (0) 2019.01.29 [MSSQL] 데이터 저장위치 (0) 2019.01.29