Notice
Recent Posts
Recent Comments
Tags
- asp.net core Select
- javascript redirection
- simpe ftp
- 404에러페이지
- ViewData
- javascript 바코드 생성
- php 캐쉬제거
- XSS PHP
- jquery 바코드생성
- asp ftp
- XSS방어
- 강제이동
- ASP.Net Core 404
- 타임피커
- SSD 복사
- swagger 500 error
- TempData
- Mac Oracle
- 하드 마이그레이션
- 하드 윈도우 복사
- django 엑셀불러오기
- asp.net Select
- ViewBag
- 원격ftp
- 바코드 생성하기
- asp.net core swagger
- 맥 오라클설치
- 말줄임표시
- asp.net dropdownlist
- JavaScript
웹개발자의 기지개
[ASP] 파일 다운로드 예제 - SQL injection 방지 본문
[ 기본 소스 ]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
<%
Option Explicit
Dim dir,filename,tb
tb = Request.QueryString("tb")
filename = Request.QueryString("filename")
response.Clear
response.ContentType = "application/unknown"
response.AddHeader "Pragma","no-cache"
response.AddHeader "Expires","0"
response.AddHeader "Content-Transfer-Encoding","binary"
response.AddHeader "Content-Disposition","attachment;filename=" & filename
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Open
Dim TmpPath,strDirectory
TmpPath = "..\pds\" & tb & "\_files"
strDirectory = server.MapPath(TmpPath) & "\" & filename
objStream.Type = 1
objStream.LoadFromFile strDirectory '절대경로
Response.BinaryWrite objStream.Read
Response.Flush
objStream.Close
Set objStream = Nothing
%>
|
cs |
[ SQL 인젝션 소스 보완된 소스 ]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
<%
Folder = Request("dir")
SEQ = Request("SEQ")
FILENAME = Request("file")
'Response.write SEQ & "<br>"
'Response.write FILENAME
'Response.End
seq = Request.QueryString("SEQ")
If Not IsNumeric(seq) Then
Response.Status = "400 Bad Request"
Response.Write "Invalid parameter"
Response.End
End If
' 파일명/디렉터리는 화이트리스트로 매핑하거나 DB에서 id->파일경로로 조회
dir = Request.QueryString("dir")
If InStr(1, dir, "..") > 0 Or dir = "" Then
Response.Status = "400 Bad Request" : Response.End
End If
' 파일명도 허용된 패턴만 허용 (예: 알파넘 + 확장자)
'fileName = Request.QueryString("file")
'If Not (fileName Like "[A-Za-z0-9_%-]*.*") Then
' Response.Status = "400 Bad Request" : Response.End
'End If
'-------------------------------
Dim fileNameDecoded, rawQS, fileEncoded, isOK
Dim re, matches, suspiciousPatternsEncoded, suspiciousPatternsDecoded
' 1) 파라미터 읽기
fileNameDecoded = ""
On Error Resume Next
fileNameDecoded = Request.QueryString("file") ' 대부분의 경우 이 값은 이미 디코딩된 상태
On Error GoTo 0
If Len(Trim(fileNameDecoded)) = 0 Then
Response.Status = "400 Bad Request"
Response.Write "Missing file parameter"
Response.End
End If
' 2) 기본 금지 검사: 경로 횡단, 슬래시, null 바이트 등
If InStr(fileNameDecoded, "..") > 0 Or InStr(fileNameDecoded, "/") > 0 Or InStr(fileNameDecoded, "\") > 0 Then
Call BlockAndLog("Path traversal or slash in decoded filename", fileNameDecoded)
End If
If InStr(fileNameDecoded, Chr(0)) > 0 Then
Call BlockAndLog("Null byte in decoded filename", fileNameDecoded)
End If
' 3) 길이 제한 (필요 시 조정)
If Len(fileNameDecoded) > 255 Then
Call BlockAndLog("Filename too long", fileNameDecoded)
End If
' 4) 정규식으로 디코딩된 파일명 허용 패턴 검사
Set re = New RegExp
re.IgnoreCase = True
re.Global = False
' 허용: 영문숫자, 한글(가-힣), 공백, 밑줄 _, 하이픈 -, 소괄호 ( ), 마침표(.) 구분자, 마지막에 확장자(영숫자 1~10자)
re.Pattern = "^[A-Za-z0-9_\-\s가-힣()]+(\.[A-Za-z0-9_\-\s가-힣()]+)*\.[A-Za-z0-9]{1,10}$"
If Not re.Test(fileNameDecoded) Then
Call BlockAndLog("Decoded filename failed whitelist regex", fileNameDecoded)
End If
' 5) 원본 쿼리(인코딩된 값)에서 file 파라미터의 '원문(인코딩된 문자열)' 추출
rawQS = Request.ServerVariables("QUERY_STRING") ' 예: file=%ED%95%9C%EA%B8%80+file.pdf&SEQ=1
fileEncoded = GetRawQueryParamValue(rawQS, "file") ' 인코딩된 값 그대로 반환 (percent-encoded)
If Len(Trim(fileEncoded)) = 0 Then
' 만약 원본에서 찾지 못하면 로그로 남기고 차단
Call BlockAndLog("Raw encoded file param missing", rawQS)
End If
' 6) 검사: 원본(인코딩된)에서 의심스러운 인코딩 시퀀스 탐지
' - SQLi 관련 인코딩: %27 (') , %3B (;) , %7C (|), %2F (/) , %5C (\) 등
' - 이중 인코딩: %25 (percent) 존재 => 페이로드이중인코딩 의심
suspiciousPatternsEncoded = Array("%27","%3B","%3b","%7C","%7c","%2F","%2f","%5C","%5c","%2E%2E","%2E%2E%2F","%25") ' %25 포함 -> double-encoding
Dim i, patt
For i = 0 To UBound(suspiciousPatternsEncoded)
patt = suspiciousPatternsEncoded(i)
If InStr(LCase(fileEncoded), LCase(patt)) > 0 Then
Call BlockAndLog("Suspicious encoded token in raw file param: " & patt, fileEncoded)
End If
Next
' 7) 검사: 인코딩된 형태로 'update set' 등 SQL 키워드 인코딩 시도 탐지
' 예: 'update' percent-encoding = %75%70%64%61%74%65 — 공격 스캐너가 이렇게 보낼 수 있음
' 간단히 'update'의 인코딩 패턴을 찾아본다 (case-insensitive)
Dim encodedUpdate, encodedSelect
encodedUpdate = "%75%70%64%61%74%65" ' 'update'
encodedSelect = "%73%65%6c%65%63%74" ' 'select' (소문자 hex)
If InStr(LCase(fileEncoded), encodedUpdate) > 0 Or InStr(LCase(fileEncoded), encodedSelect) > 0 Then
Call BlockAndLog("Encoded SQL keyword found (update/select)", fileEncoded)
End If
' 8) 추가 안전장치: 원본에 연속으로 긴 영숫자 기반의 Base64-like 문자열이 있는 경우(난독화 페이로드 의심)
Set re = New RegExp
re.IgnoreCase = True
re.Global = False
' 하나의 라인 안에서 길게 연결된 Base64 패턴(=로 끝남) 탐지
re.Pattern = "[A-Za-z0-9_\-]{120,}=%?|%[A-Za-z0-9]{120,}" ' 단순 탐지, 필요 시 조정
If re.Test(fileEncoded) Then
Call BlockAndLog("Long base64-like string in encoded file param", fileEncoded)
End If
' 9) 통과하면 안전한 파일명으로 정리(공백 연속 정리 등)
fileNameDecoded = Trim(fileNameDecoded)
' 연속 공백을 하나로 (간단 반복)
Do While InStr(fileNameDecoded, " ") > 0
fileNameDecoded = Replace(fileNameDecoded, " ", " ")
Loop
' 이제 fileNameDecoded을 실제로 사용하지 말고(권장) SEQ로 DB에서 안전한 경로를 조회해서 전송하세요.
' 예: safePath = GetPathBySeq(CInt(Request.QueryString("SEQ")))
' Response.TransmitFile safePath
'Response.Write "OK" ' 임시(테스트) 응답
'Response.End
' ============================
' Helper: 원본 쿼리에서 파라미터 값(raw, percent-encoded) 추출
' ============================
Function GetRawQueryParamValue(rawQS, paramName)
' rawQS: Request.ServerVariables("QUERY_STRING")
' paramName: 예: "file"
' 반환: 퍼센트 인코딩 상태의 값 (예: %ED%95%9C%EA%B8%80+file.pdf)
Dim regex, matches, pattern, val
Set regex = New RegExp
regex.IgnoreCase = True
regex.Global = False
' param=... 패턴: 앰퍼샌드 또는 끝까지 캡처, URL 쿼리의 param값은 & 또는 끝으로 끝남
pattern = "(?:^|&)" & paramName & "=([^&]*)"
regex.Pattern = pattern
Set matches = regex.Execute(rawQS)
If matches.Count > 0 Then
val = matches(0).SubMatches(0)
GetRawQueryParamValue = val
Else
GetRawQueryParamValue = ""
End If
End Function
' ============================
' Helper: 차단 및 로깅
' ============================
Sub BlockAndLog(reason, data)
' 로그에 남기기 (간단히 파일에 append)
Dim fso, logPath, logMsg
logPath = Server.MapPath("/file_download_logs/security_block.log") ' 존재하지 않으면 디렉토리/파일 미리 만들어 둘 것
Set fso = Server.CreateObject("Scripting.FileSystemObject")
On Error Resume Next
If Not fso.FolderExists(Server.MapPath("/file_download_logs")) Then
fso.CreateFolder(Server.MapPath("/file_download_logs"))
End If
Dim ts
Set ts = fso.OpenTextFile(logPath, 8, True) ' ForAppending
logMsg = Now() & " | BLOCK | " & Request.ServerVariables("REMOTE_ADDR") & " | Reason: " & reason & " | Data: " & Replace(data, vbCrLf, " ") & vbCrLf
ts.WriteLine logMsg
ts.Close
Set ts = Nothing
Set fso = Nothing
' 응답 차단
Response.Status = "400 Bad Request"
Response.Write "Invalid request"
Response.End
End Sub
'-----------------------------------
If SEQ = "" Or FILENAME = "" Then
Response.Status = "400 Bad Request"
Response.Write "Invalid request"
Response.End
End If
filePath = Server.Mappath("/") & "/data/board/" & Folder & "/" & SEQ & "/" & FILENAME
FolderPath = Server.Mappath("/") & "/data/board/" & Folder & "/" & SEQ
Set fso = Server.CreateObject ("Scripting.FileSystemObject")
If Not fso.FolderExists(FolderPath) Then
Response.Write "<script>location.href='/index.asp';</script>"
Else
Set stream = Server.CreateObject("ADODB.Stream")
Response.Buffer = True
Response.Expires = 0
Response.Clear
stream.Open
stream.Type = 1
Set f = fso.GetFile(filePath)
fileLength = f.size
stream.LoadFromFile(filePath)
With Response
.ContentType = "application/octet-stream name=" & filePath
.AddHeader "Content-Disposition","attachment;filename=" & Trim(SERVER.UrlEncode(FILENAME))
.AddHeader "Content-Length" , fileLength
.CharSet = "utf-8"
.ContentType = "application/octet-stream"
strFile = stream.Read
.BinaryWrite strFile
.Flush
End With
Set f = Nothing
Set stream = Nothing
End If
Set fso = Nothing
%>
|
cs |
소스가 길어서 복잡할 수 있는데, injection 공격에 좀더 보완한 소스이다.
게다기 이상한 접근이 있을때,
/file_download_logs/security_block.log
폴더에 기록 로그가 남도록 해놓았다.
'ASP' 카테고리의 다른 글
| [ASP] SQL injection 방지 - 변수 필터링 추가 작업 (0) | 2025.09.29 |
|---|---|
| [ASP] web.config - SQL injection 필터링 기능 (1) | 2025.09.27 |
| [ASP] 파일다운로드시 빈칸을 처리하기 (0) | 2024.01.26 |
| [ASP] 랜덤색상값 추출함수 (0) | 2024.01.17 |
| [ASP] 3초 정도 임의로 지연시키는 함수만들기 (0) | 2024.01.13 |
Comments
