Loading
2010. 2. 4. 18:12 - 나쁜철군

sql injection 을 해결해보자.

한동안 중국발 injection 이 무진장 유행했다

나도 많이 당했다. 써글.. 그래서 한동안 무진장 골치아프게 알아보면서 이런 방법이 있다는걸 포스팅 해본다.

아래 내용을 파일로 만들어서 모든 파일에 인클루드 시킨다.

그럼 해결 완료.

하지만 이 포스팅을 짱게들이 보면 .. 그 후로는 다른 변칙적인 방법으로 인젝션이 들어오겠지 ㅎㄷㄷ.

이걸로 끝이라 생각하지 말고 더 나은 방법을 생각해보자. (웹나이트를 깔아야 하나 ..젠장.)


<%
' ---------------------------------------------------------------------------------------------------------------------------
 ' - 이 파일은 injection 검사가 필요한 파일의 최 상단에서 include 해야 하며 각 파일로 넘어오는 
' post/get 방식의 문자열 중에서 sql injection이 의심가는 문자열을 검사하여 문제있는 문자열일
' 경우엔 진행을 멈추고 에러로그를 만드는 동시에 에러 메시지를 띄워준다.
'
' - 문제가 없는 문자열일 경우엔 그대로 진행한다.
' 단, multypart/form-data 의 경우엔 검사하지 않는다.
'
' - property 설정에 따라 에러로그를 남길 수 있으며, 드라이브, 폴더명, 파일명을 설정해 주어야 한다.
' 설정을 해주지 않으면 클래스 초기화 함수에 기본 값에 따라서 파일명
' "E:\aspInjectionErrLog\asp_injection_err_log_그날날짜.txt" 로 저장되며 하루에 몇번이라
' 도 에러가 생기면 이 파일에 누적 기록된다.
' - 폼의 데이터중 키와 값중에 값만을 검사한다./
 ' - 인젝션필터 중 '--' 제거했음(결제사이트에서 -----형태의 문자열 때문에 문제가 생김)
' ---------------------------------------------------------------------------------------------------------------------------

Class CAntiInjection

Private injection_Filters ' 받아들이지 말아야 할 문자열들
Private bWritable ' 에러로그를 남길 것 인가
Private drive ' 드라이버명 (ex : "c" , "d" , "e")
Private folderName ' 폴더명
Private fileName ' 파일명

' 생성자
Private Sub Class_Initialize()
' 인젝션 필터 만들기 (더 추가될 문자열은 여기 문자열 끝에 |를 구분자로 하여 추가하면 된다)
injection_Filters = "';|' |union |delete |select |update |drop table|drop column|alter table|alter column|create |insert |;--|declare|exec|set @|<script|</script>|sysobjects|b.xtype|3c736372697074|3c534352495054|3c734372497054|3c536352695074"

' 에러로그가 남겨질 드라이버, 폴더, 파일명
drive = "e"
folderName = "aspInjectionErrLog"
fileName = "asp_injection_err_log"

' 에러로그를 만들지 않는것이 기본값
bWritable = False
End Sub

' 소멸자
Private Sub Class_Terminate()
End Sub


' 쓰기 가능인지 설정하기
Public Property Let SetWriable(value)
bWritable = value
End Property


' 드라이브 설정 (필수아님, 하지만 드라이브와 폴더명이 맞아야 파일이 정상적으로 생성된다)
Public Property Let SetDrive(value)
drive = value
End Property


' 폴더명 설정 (필수아님, 하지만 드라이브와 폴더명이 맞아야 파일이 정상적으로 생성된다)
Public Property Let SetFolderName(value)
folderName = value
End Property


' 파일명 설정 (필수아님)
Public Property Let SetFileName(value)
fileName = value
End Property


' injection 문자열 검사 함수
Private Function CheckSpecialChar(query_string)

Dim tmp_bool : tmp_bool = True

' 소문자로 변화하여 검사한다
query_string = LCase(unescape(query_string))
injection_Filters_arr = split(injection_Filters,"|")
injection_Filters_cnt = Ubound(injection_Filters_arr)

For injection_j = 0 To injection_Filters_cnt
If InStr(1,query_string,injection_Filters_arr(injection_j),1) > 0 Then
tmp_bool = False
Exit For
End If
Next

CheckSpecialChar = tmp_bool

End Function


' injection 검사시작
Public Function Start()

' 멀티타입의 경우엔 검사하지 않는다
Dim isMultyType : isMultyType = False

Dim content_type : content_type = Request.ServerVariables("CONTENT_TYPE")

' multipart type 일 경우엔 검사하지 않는다
If InStr(content_type, "multipart/form-data;") > 0 Then
isMultyType = True
End If

' 멀티 타입이 아닐경우 검사
If isMultyType = False Then

method = Request.ServerVariables("REQUEST_METHOD")

If method = "POST" then
content = Request.Form
Else
content = Request.QueryString
End If

' ---------------------------------------------------------------------------------------------------------------
' content 를 = 로 분류하여 키와 값을 가져온 상태에서 값만을 추출하여 검사한다
' ---------------------------------------------------------------------------------------------------------------

' 각 값들이 통과되었는가 알기위한 bool
Dim bAllPassed : bAllPassed = True

' &으로 분류하여 키와 값 한쌍씩 분류한다 (ex - table=qna )
pContent = Split(content, "&")

' &으로 분류한만큼 루프
For i = 0 To UBound(pContent)

' 키와 값을 분류한다
ppContent = Split(pContent(i), "=")

' 키와 값이 있는경우는 값을 검사한다 (0번째 index는 키, 1번째 index는 값이다)
If UBound(ppContent) > 0 Then

' 값을 검사해서 부적격 판정인 경우엔 루프를 나가 다음 문장에서 erorr처리한다
If CheckSpecialChar(ppContent(1)) = False Then
bAllPassed = False
Exit For
End If
End If
Next
' ---------------------------------------------------------------------------------------------------------------

' ---------------------------------------------------------------------------------------------------------------
' injection filtering 에 통과여부
' ---------------------------------------------------------------------------------------------------------------

' 여러 값들이 모두 통과 된 경우
If bAllPassed Then

' injection filter에 부적격 판정
Else

' injection error log 만들기
Dim errContents : errContents = ""

errContents = errContents & Now
errContents = errContents & " | 도메인 : " & Request.ServerVariables("HTTP_HOST")
errContents = errContents & " | 파일명 : '" & request.ServerVariables("PATH_INFO") & "'"
errContents = errContents & " | 사용자IP : " & Request.ServerVariables("REMOTE_ADDR")
errContents = errContents & " | Method : " & method
errContents = errContents & " | 쿼리문자 : '" & content & "'"
'response.write errContents & "<br>"

' 에러 로그를 파일에 쓰기로 되어있다면
If bWritable Then

' 에러 로그 파일 생성/저장
Dim Fso_log, Log_file, Today_file

' E:\aspInjectionErrLog\asp_injection_err_log_20090105.txt 의 형태로 저장
Today_file = drive & ":\" & folderName & "\" & fileName & "_" & replace(cStr(date),"-","") & ".txt"

Set Fso_log = Server.CreateObject("Scripting.FileSystemObject")

If Fso_log.FileExists(Today_file) Then
Set Log_file = Fso_log.OpenTextFile(Today_file,8, False)
Else
Set Log_file = Fso_log.CreateTextFile(Today_file, True)
End If

Log_file.writeLine(errContents)
Log_file.close

Set Log_file = Nothing
Set Fso_log = Nothing

End If ' If bWritable Then

  response.write "<script type='text/javascript'>alert('잘못된 접근입니다.');location.href='/';</script>"

' 더 이상 진행하지 않는다
response.End

End If ' If bAllPassed Then
' ---------------------------------------------------------------------------------------------------------------

End If ' If isMultyType = False Then

End Function ' Public Function Start()

End Class


' addr = Request.ServerVariables("REMOTE_ADDR")

' 개발자 pc에서만 에러가 나면 그냥 로그안보고 화면에서 볼수 있도록..편의상이다.
' If addr = "111.111.1.11" Then 

Dim antiInjection : Set antiInjection = New CAntiInjection
antiInjection.SetWriable = True ' error log 남기기로 설정
antiInjection.Start
Set antiInjection = Nothing

' End If
%>