| 점검 항목 |
| ▸사용자 입력값에 대한 필터링 및 유효성 검증이 미흡하여 데이터를 수정하거나 임의 명령을 실행할 수 있는 코드 삽입 및 프로그램 로직 손상 등(LDAP·SQL·SSL·XPath 인젝션, 운영체제 명령실행) |
| ▸사용자 입력값 필터링 미흡으로 사용자 세션 탈취·도용 및 악성코드 유포 사이트로 전환(크로스사이트스크립트 등) |
| ▸입력값의 제한을 두지 않아 장애 발생 취약점 존재 여부 확인(버퍼 오버플로우) |
| ▸로그인 시도·SMS발송 등 웹의 특정 프로세스에 대한 반복 요청 통제기능 미구현으로 자원 고갈 공격 등 가능 여부(자동화공격) |
| ▸웹 관리자페이지 노출로 비인가자의 접근 용이 여부(관리자 페이지 노출) |
| ▸일정 패턴을 가진 단순 방법으로 사용자 세션 ID를 생성하거나 고정된 세션을 사용하여 불법적인 접근 가능 여부 |
| ▸유추 가능한 계정·패스워드, 취약한 패스워드 복구기능 구현으로 사용자 권한 탈취 가능 여부(약한 문자열 강도, 취약한 패스워드 복구) |
| ▸웹사이트에 중요정보 노출 또는 에러 발생시 과도한 정보 안내로 2차 공격 노출 여부 |
| ▸입출력 값 조작으로 메모리 주소를 변조하여 시스템에 접근할 수 잇는 관리자 권한 획득(포멧스트링) |
| ▸중요페이지에 대한 접근제어 기능 누락으로 우회 접근 가능 여부(프로세스검증) |
| ▸시스템 폴더나 파일명 접근 가능으로 상위 디렉토리 및 파일에 접근 가능 여부(경로추적, 디렉토리인덱싱,위치공개) |
| ▸중요페이지 접근 시 인증 절차 및 통제 수단 적용 미흡으로 정보 노출 및 변조 가능 여부(불충분한 인증·인가·세션만료) |
| ▸악성파일 (업)다운로드 가능하도록 파일 확장자 검증 등 누락(악성콘텐츠, 파일 업·다운로드, 불필요한 메소드 허용) |
1. 인젝션 및 로직 손상 (데이터/명령어 삽입)
사용자가 입력한 데이터를 서버가 '단순 정보'가 아닌 '실행 가능한 명령어'로 오인할 때 발생합니다.
- 원리: 프로그램 코드와 사용자 입력값이 섞이는 구조적 결함을 악용합니다.
- 주요 유형:
① SQL 인젝션 (SQL Injection)
- 디테일 원리: 개발자가 SQL 쿼리를 작성할 때, 사용자의 입력값을 SELECT * FROM users WHERE id = ' + userInput + ' 와 같이 문자열을 더하는 방식으로 처리할 때 발생합니다.
- 공격 시나리오 (인증 우회): 아이디 입력창에 ' OR '1'='1을 넣으면 쿼리가 WHERE id = '' OR '1'='1'이 되어 조건문이 항상 참(True)이 됩니다. 결과적으로 비밀번호 없이 로그인이 됩니다.
- 공격 시나리오 (데이터 탈취): UNION 명령어를 사용하여 기존 쿼리에 다른 테이블(예: 관리자 테이블, 계좌 정보)의 데이터를 합쳐서 화면에 출력하게 만듭니다.
② OS 명령 실행 (Command Injection)
- 디테일 원리: 웹 앱이 내부적으로 시스템 명령어를 호출하는 함수(예: PHP의 system(), Python의 os.system())를 사용할 때 발생합니다.
- 상세 사례: 네트워크 상태를 점검하는 페이지에서 IP 주소를 입력받아 ping [IP]를 실행한다고 가정해 봅시다. 공격자가 IP 대신 8.8.8.8 ; cat /etc/passwd를 입력하면, 서버는 핑을 보낸 뒤 서버의 모든 계정 정보 파일을 읽어 사용자에게 보여줍니다.
③ LDAP / XPath 인젝션
- LDAP: 기업의 조직도나 사용자 권한 정보를 담는 디렉토리 서비스입니다. 필터 구문에 특수문자(*, (, &)를 넣어 권한 없이 조직 내부 정보를 조회합니다.
- XPath: XML 데이터를 조회할 때 쓰입니다. 로그인 쿼리를 조작하여 XML에 저장된 사용자 정보를 탈취합니다.
실무적인 방어 전략 (Defense in Depth)
단순히 "필터링하자"를 넘어선 구체적인 방법입니다.
- 간접 참조 사용: 파일 경로, DB ID 등을 사용자가 직접 입력하게 하지 말고, 서버 내부의 매핑 값(숫자 ID 등)을 사용하세요.
- 화이트리스트 검증: "안 되는 것"을 막지 말고, "되는 것"만 허용하세요.
- 라이브러리 활용: 검증 로직을 직접 짜기보다는 프레임워크가 제공하는 보안 기능(ORM, Prepared Statement)을 기본으로 사용하세요.
2. 크로스사이트 스크립트 (XSS)
사용자 입력값에 악성 자바스크립트를 삽입하여, 해당 페이지를 보는 다른 사용자를 공격하는 기법입니다.
- 원리: 게시판, 프로필 등에 <script> 태그를 저장해두면, 다른 사용자가 그 글을 읽을 때 브라우저에서 해당 코드가 실행됩니다.
- 위험성: 사용자의 세션 쿠키를 탈취하여 로그인 없이 계정을 도용하거나, 악성코드 배포 사이트로 강제 이동(리다이렉트)시킵니다.
- 방어: 출력 시 특수문자 치환(HTML 엔티티 코딩), 보안 헤더(CSP) 설정.
저장형 XSS (Stored XSS): 가장 위험함
- 공격 방식: 게시판 글, 댓글, 사용자 프로필 등 DB에 악성 스크립트가 저장됩니다.
- 상황: 공격자가 게시글 제목에 라고 써둡니다. 이 글을 클릭하는 모든 사용자는 본인도 모르게 로그인 쿠키를 공격자에게 전송하게 됩니다.
반사형 XSS (Reflected XSS):
- 공격 방식: 스크립트가 DB에 저장되지 않고, URL 파라미터 등에 포함되어 서버가 즉시 응답 화면에 반사해줄 때 발생합니다.
- 상황: 검색 결과 페이지에서 search.php?query=<script>alert('XSS')</script> 같은 링크를 이메일이나 메신저로 유포하여 클릭을 유도합니다.
DOM 기반 XSS (DOM-based XSS):
- 공격 방식: 서버를 거치지 않고 브라우저(클라이언트) 단에서 자바스크립트가 데이터를 잘못 처리할 때 발생합니다. 최근 프론트엔드 프레임워크(React, Vue 등)에서 주의해야 할 부분입니다.
XSS가 진짜 위험한 이유
단순히 alert('Hi') 창이 뜨는 게 문제가 아닙니다.
- 세션 하이재킹 (Session Hijacking): 가장 흔한 공격입니다. 사용자의 세션 ID(쿠키)를 훔쳐서 공격자가 해당 사용자로 즉시 로그인합니다.
- 피싱 및 정보 탈취: 정상적인 은행 사이트 위에 가짜 로그인 창(레이어)을 띄워 사용자가 직접 아이디와 비밀번호를 입력하게 만듭니다.
- 악성코드 유포: 브라우저의 취약점을 이용해 사용자의 PC에 랜섬웨어나 좀비 PC용 악성코드를 강제로 다운로드하게 합니다(Drive-by Download).
- 권한 오용: 사용자의 브라우저에서 관리자 권한으로 특정 동작(글 삭제, 회원 강퇴 등)을 강제로 실행시킵니다.
방어 기법: 어떻게 원천 차단하는가?
인젝션 방어가 "입력"에 집중한다면, XSS 방어는 **"출력"**에 더 집중해야 합니다.
① HTML 엔티티 코딩 (출력 시 필수)
- 웹 브라우저(Chrome, Edge 등)는 HTML 코드를 읽을 때 특수문자 <와 >를 만나면 **"아, 이제부터는 화면에 그릴 글자가 아니라 시스템이 실행할 명령어(태그)가 시작되는구나!"**라고 판단합니다.
- 문제 상황: 사용자가 <script>alert(1)</script>라고 입력했을 때, 서버가 이를 그대로 브라우저에 보내면 브라우저는 이를 실행합니다.
- 엔티티 코딩 적용: 서버가 데이터를 보낼 때 <를 <로 바꿔서 보냅니다. 브라우저는 <를 보는 순간 **"이건 그냥 화면에 '<' 모양으로 그려야 할 단순한 글자(Entity)구나"**라고 인식하고 코드를 실행하지 않습니다.
- 일반적인 프론트앤드 프레임워크는 엔티티코딩이 적용되어있음.
"어디서 변환해야 하는가?"
많은 분이 "데이터를 DB에 저장할 때 변환해서 넣어야 하나요?"라고 묻습니다. 정답은 **"출력 직전(View 단)"**이 가장 권장됩니다.
- DB 저장 시 변환: 데이터 원본이 훼손됩니다. 나중에 이 데이터를 웹이 아닌 엑셀 다운로드나 모바일 앱에서 쓸 때 <라는 글자가 그대로 노출되는 버그가 생길 수 있습니다.
- 출력 시 변환 (권장): DB에는 사용자가 입력한 원본을 그대로 두고, 웹 브라우저로 내보내는 템플릿 엔진(JSP, Thymeleaf, React 등)에서 출력할 때만 변환합니다. 최근 프레임워크들은 기본적으로 이 기능을 내장하고 있어 매우 안전합니다.
② 입력 필터링 (라이브러리 활용)
* 1) DTO 필드에 유효성 검증 규칙 적용 (Validation):
- * 길이 제한: @Size(max=...) 어노테이션 등으로 입력 가능한 문자열의 최대 길이를 제한합니다. (예: name은 50자 이내, mobile은 11자 이내).
- * 형식 제한 (화이트리스트 방식): @Pattern(regexp=...) 어노테이션으로 허용할 문자(화이트리스트)만 정의하여 입력 형식을 엄격하게 제한합니다.
- * `name` 필드: 한글, 영문, 숫자, 공백 등만 허용하는 정규표현식(^[가-힣a-zA-Z0-9\\s]*$)을 적용하여 < , > 같은 특수 문자의 입력을 원천 차단합니다.
- * `mobile` 필드: 전화번호 형식에 맞는 숫자와 하이픈(^01(?:0|1|[6-9])(?:\\d{3}|\\d{4})\\d{4}$ 또는 ^\d{3}-\d{3,4}-\d{4}$)만 허용하도록 합니다.
- * 필수 여부 확인: @NotBlank, @NotNull 등으로 필수 입력 값인지 확인합니다.
* 2) 입력값 살균 (Sanitization) 처리:
- * name, mobile과 같은 단순 텍스트 필드는 위 @Pattern 검증만으로 충분한 경우가 많습니다. 만약 @Pattern으로 모든 위험 요소를 걸러내기 어렵거나, 좀 더 적극적인 방어가 필요하다면 다음 방법을 사용합니다.
- * 위험 문자 제거/변환: 스프링 프레임워크의 경우 web.xml에 XssFilter 등을 설정하거나, 서비스 로직에서 직접 Jsoup (Java 라이브러리) 같은 외부 라이브러리를 사용하여 입력값을 클리닝합니다.
- * Jsoup 예시 (Java):
③ 보안 헤더 활용 (강력 추천)
- CSP (Content Security Policy): 웹 페이지에서 실행할 수 있는 스크립트의 출처를 제한하는 정책입니다. 공격자가 외부에서 가져온 스크립트 실행을 원천 차단합니다.
- HttpOnly 쿠키: 쿠키 설정 시 HttpOnly 옵션을 주면, 자바스크립트(document.cookie)로 쿠키를 읽을 수 없게 됩니다. XSS가 터져도 세션 탈취는 막을 수 있는 가장 현실적인 방어선입니다.
3. 버퍼 오버플로우 (Buffer Overflow)
메모리에 할당된 크기보다 더 큰 데이터를 입력하여 인접한 메모리 영역을 침범하는 공격입니다.
버퍼 오버플로우의 디테일한 원리
컴퓨터 프로그램은 데이터를 저장하기 위해 메모리에 일정한 공간을 예약하는데, 이를 **'버퍼(Buffer)'**라고 합니다.
- 스택(Stack) 구조의 악용: 프로그램은 함수가 끝나고 돌아갈 위치(Return Address)를 메모리에 기록해둡니다.
- 경계선 침범: 만약 10칸짜리 버퍼에 100칸짜리 데이터를 억지로 밀어 넣으면, 넘친 데이터가 옆 칸에 있는 '돌아갈 주소'를 덮어씌우게 됩니다.
- 실행 흐름 조작: 공격자는 이 '돌아갈 주소'를 자신이 미리 심어둔 악성 코드(Shellcode)가 있는 주소로 바꿔치기합니다. 그러면 프로그램은 정상적인 다음 단계를 수행하는 대신 공격자의 명령을 실행하게 됩니다.
왜 위험한가? (위험성 디테일)
- 권한 장악 (Privilege Escalation): 웹 서버는 보통 높은 권한으로 실행되는 경우가 많습니다. 버퍼 오버플로우에 성공하면 공격자는 관리자(Root) 권한으로 서버의 모든 파일을 열람하거나 삭제할 수 있습니다.
- 서비스 거부 (DoS): 메모리가 오염되면 프로그램이 어디로 갈지 몰라 헤매다가 'Segmentation Fault' 같은 에러를 내며 죽어버립니다. 웹사이트 접속이 불가능해지는 것이죠.
- 웜(Worm) 바이러스의 통로: 과거 '코드레드'나 '슬래머' 같은 유명한 웜 바이러스들이 바로 이 버퍼 오버플로우 취약점을 이용해 전 세계 서버를 감염시켰습니다.
② 안전한 함수 사용
C/C++ 같은 언어에서 특히 중요합니다.
- 위험한 함수: strcpy(), gets(), sprintf() (길이를 체크하지 않고 무조건 복사함)
- 안전한 함수: strncpy(), fgets(), snprintf() (복사할 데이터의 최대 길이를 인자로 받음)
③ 최신 컴파일러 및 OS 보호 기능 활용
- ASLR (Address Space Layout Randomization): 메모리 주소를 매번 랜덤하게 바꿔서 공격자가 악성 코드가 어디 있는지 예측하지 못하게 합니다.
- DEP/NX (Data Execution Prevention): 데이터 저장 영역(버퍼)에서는 코드가 실행되지 않도록 설정합니다.
- Stack Canary: 버퍼와 돌아갈 주소 사이에 '카나리아'라는 특정 값을 심어둡니다. 이 값이 변했다면 침범당한 것으로 간주하고 프로그램을 즉시 종료시킵니다.
사실 최근의 Java, Python, Node.js 같은 현대적인 언어들은 언어 차원에서 메모리를 관리해주기 때문에 버퍼 오버플로우가 잘 발생하지 않습니다. 하지만 **웹 서버 자체(Apache, Nginx)**나 이미지 처리 라이브러리, 암호화 모듈(OpenSSL 등) 같이 C/C++로 작성된 핵심 모듈에서는 여전히 치명적인 취약점으로 발견됩니다. (예: 유명한 '하트블리드' 취약점도 일종의 메모리 관련 취약점입니다.)
4. 자동화 공격 (반복 요청 통제 미구현)
사람이 직접 하는 것이 아니라 매크로나 봇을 이용해 짧은 시간 내에 수천, 수만 번의 요청을 보내는 것입니다.
- 원리: 로그인, SMS 발송, 게시글 작성 등 특정 프로세스에 횟수 제한이 없는 점을 이용합니다.
- 위험성:
- 자원 고갈: 서버 부하로 인해 정상적인 사용자가 접속 불가능해짐.
- 비용 발생: SMS 발송 비용 폭탄.
- 무차별 대입: 비밀번호를 맞출 때까지 무한 반복 시도.
- 방어: 캡차(CAPTCHA) 도입, IP/계정별 요청 임계치 설정(Rate Limiting).
5. 관리자 페이지 노출
일반인에게 공개되지 않아야 할 관리자 전용 주소가 외부 검색 엔진에 걸리거나 추측 가능한 경우입니다.
- 원리: /admin, /manager, /test 같은 뻔한 경로를 사용하거나, 구글(Google Dorking)을 통해 주소가 노출됩니다.
- 위험성: 공격자가 로그인 페이지만 찾아내면 브루트포스(무차별 대입) 등을 통해 관리자 권한을 획득할 기회를 얻게 됩니다.
- 방어: 관리자 주소 변경, IP 접속 제한(사내망만 허용), 로봇 배제 표준(robots.txt) 설정.
6. 취약한 세션 관리 (고정된 세션 등)
사용자가 로그인 상태임을 증명하는 '세션 ID'를 공격자가 가로채거나 예측하는 문제입니다.
- 원리: 세션 ID가 101, 102처럼 순차적이어서 다음 사람의 ID를 맞추기 쉽거나, 로그인을 해도 ID가 바뀌지 않고 고정되어 있는 경우입니다.
- 위험성: 공격자가 미리 알아낸 세션 ID를 희생자에게 심어두고, 희생자가 로그인하면 그 세션을 그대로 사용하여 비밀번호 없이 접속합니다.
- 방어: 로그인 시 세션 ID 재발급, 세션 만료 시간 설정, 복잡한 무작위 세션 ID 생성.
7. 약한 문자열 강도 및 취약한 패스워드 복구
계정 정보 자체의 보안성이 낮거나, 비밀번호를 잊었을 때 확인하는 절차가 부실한 경우입니다.
- 원리: 1234 같은 단순 비밀번호 허용, 또는 "내 고향은?" 같은 누구나 알 수 있는 정보로 비밀번호를 찾게 해주는 구조입니다.
- 위험성: 공격자가 사회 공학적 기법(지인 정보 수집)이나 사전 공격(Dictionary Attack)으로 쉽게 계정을 뺏을 수 있습니다.
- 방어: 패스워드 복잡성 규칙(영문/숫자/특수문자 조합), 2단계 인증(2FA), 비밀번호 찾기 시 이메일/휴대폰 일회용 토큰 전송.
8. 중요정보 노출 및 에러 메세지 관리
시스템 내부의 민감한 정보가 에러 화면을 통해 공격자에게 전달되는 문제입니다.
- 원리: 프로그램 에러 발생 시 브라우저에 찍히는 Stack Trace(코드 경로, 라이브러리 버전, 쿼리문 등)를 그대로 노출하는 경우입니다.
- 위험성: 공격자는 에러 메시지를 통해 서버의 운영체제, DB 종류, 사용하는 라이브러리의 취약한 버전을 알아내어 2차 정밀 공격을 설계합니다.
- Spring 대응: application.yml 설정이나 @ControllerAdvice를 사용하여 에러 발생 시 사용자에게는 "알 수 없는 오류가 발생했습니다"라는 공통 에러 페이지만 보여주고, 상세 로그는 서버 내부 파일에만 남깁니다.
9. 포맷 스트링 (Format String)
입력값에 %s, %x 같은 포맷 지정자를 넣어 메모리 구조를 훔쳐보거나 변조하는 공격입니다.
- 원리: C언어의 printf(user_input) 처럼 포맷 스트링을 직접 입력받을 때 발생합니다.
- 위험성: 메모리의 특정 주소에 값을 쓰거나 읽을 수 있어 관리자 권한을 획득할 수 있습니다.
- Spring(Java) 체감: Java에서는 발생하지 않는 취약점입니다. Java는 포맷 스트링을 처리할 때 인자 개수를 엄격히 체크하므로 메모리 주소를 직접 건드릴 수 없습니다. (C 기반 외부 모듈 사용 시에만 주의)
10. 프로세스 검증 누락 (접근제어 우회)
비즈니스 로직의 순서를 지키지 않고 특정 페이지에 직접 접근하는 행위입니다.
- 원리: 결제 완료 페이지(.../pay_success)에 결제도 안 한 사용자가 주소를 직접 입력해서 들어오는 것을 막지 못한 경우입니다.
- 위험성: 유료 콘텐츠를 무료로 이용하거나, 다른 사람의 주문 완료 정보를 훔쳐볼 수 있습니다.
- 방어: 해당 페이지에 진입할 때 **"이전 단계(결제)를 정상적으로 마쳤는가?"**를 세션이나 DB에서 반드시 재검증해야 합니다.
4. 경로 추적 및 디렉토리 인덱싱 (Path Traversal)
서버의 파일 시스템 경로를 조작하여 접근 권한이 없는 파일에 접근하는 공격입니다.
- 경로 추적: ../../etc/passwd 같이 상위 디렉토리 이동 명령어를 파일명에 섞어 넣는 방식입니다.
- 디렉토리 인덱싱: 특정 폴더 주소(예: /images/)를 입력했을 때 그 안의 파일 목록이 쫙 나열되는 현상입니다.
- 위험성: 서버 설정 파일, 소스 코드, 사용자 개인정보 파일을 탈취당할 수 있습니다.
- 방어: 웹 서버(Nginx, Apache) 설정에서 AutoIndex를 끄고, 소스 코드에서는 파일명에서 .., /, \ 문자를 제거(Sanitize)합니다.
5. 불충분한 인증·인가 (Broken Access Control)
사용자가 자신의 권한을 넘어서는 기능을 실행하는 문제입니다.
- 인증 미흡: 로그인 없이 주소창에 주소만 쳐서 마이페이지에 들어가는 경우.
- 인가 미흡: 일반 유저가 주소창의 ID 값을 바꿔서 다른 유저의 정보를 수정하는 경우(IDOR).
- 세션 만료: 로그아웃 후에도 뒤로가기를 하면 이전 페이지가 보이거나 세션이 유지되는 경우.
- 방어: Spring Security를 도입하여 URL 패턴별로 권한(ROLE_USER, ROLE_ADMIN)을 강제하고, 모든 요청마다 현재 로그인한 사용자와 데이터의 주인이 일치하는지 체크합니다.
6. 악성 파일 업로드/다운로드
서버에 실행 가능한 파일(웹쉘)을 올리거나, 서버의 중요 파일을 내려받는 공격입니다.
- 업로드 공격: 이미지 파일인 척 virus.jsp를 올려서 서버 내에서 실행시킵니다. 실행되면 서버 제어권이 공격자에게 넘어갑니다.
- 다운로드 공격: 파일 다운로드 경로를 조작하여 web.xml이나 db_config.php 같은 설정 파일을 내려받습니다.
- 방어: 1. 파일 확장자를 화이트리스트(jpg, png 등)로 엄격히 제한합니다. 2. 업로드된 파일명을 UUID로 변경하여 실행을 방해합니다. 3. 업로드 폴더의 실행 권한을 제거합니다.
'개발기술 > 보안' 카테고리의 다른 글
| JWT Refresh Token Strategy (0) | 2025.03.07 |
|---|---|
| 브라우저 보안정책 (0) | 2025.02.26 |
| 네트워크 접근제어(NAC) ; NAT, 방화벽 (0) | 2025.02.25 |
| 보안의 개념과 기술 (0) | 2025.01.19 |
| HTTPS 의 TLS 동작과정 (0) | 2025.01.18 |