🛑 1. 크로스사이트스크립트(XSS, Cross-Site Scripting) 취약점
✅ 설명
여러 사용자가 보는 게시판이나 메일 등을 통해 악성 스크립트를 삽입하는 공격 기법이며, 사용자 입력값에 대한 검증 없이 웹페이지에 출력할 경우, 공격자가 악성 스크립트를 삽입할 수 있는 취약점이다. 이 스크립트는 다른 사용자의 브라우저에서 실행되어 세션 탈취, 피싱, 사이트 변조 등이 가능하다.
💥 공격 방법
공격자가 삽입한 악성스크립트가 사용자 측에서 어떻게 동작하는지에 따라 크게 3가지 분류할 수 있다.
- Stored XSS (저장형)
- 게시판, 댓글 등에 <script>document.cookie</script> 삽입
-
더보기
✅ 스크립트(script)란?
웹에서 말하는 스크립트는
브라우저가 이해하고 실행할 수 있는 코드를 말한다.
대표적으로 JavaScript가 있다. - 악성 스크립트가 서버 DB에 저장되고, 다른 사용자가 해당 게시글을 열면 자동 실행
출처 : sk_shieldus 출처 : sk_shieldus
- Reflected XSS (반사형)
- 악성 스크립트를 포함한 링크를 전송
- URL 쿼리값이 웹페이지에 그대로 반영되면 스크립트 실행됨
- 예: http://site.com/?q=<script>alert(1)</script>:
출처 : sk_shieldus
- DOM-based XSS
- JavaScript가 document.location, innerHTML 등을 통해 입력값을 DOM에 직접 삽입할 때 발생
- (*dom이란 브라우저가 HTML을 이해하고, 웹페이지를 구조화해서 다루기 쉽게 만든 형태이다. )
- 서버는 관련 없고 클라이언트 측 코드 문제
- 예: example.com/#<script>alert(1)</script>
출처 : sk_shieldus 출처 : sk_shieldus
🛡 대응방안 - 크로스사이트스크립트(XSS)
XSS 취약점은 악성 스크립트가 삽입되어 사용자 브라우저에서 실행되는 문제이므로, 다음과 같은 입력 검증과 출력 무효화를 통해 대응해야 한다:
1. 입력값 필터링
- 사용자가 입력하는 데이터에 대해 스크립트 관련 특수문자(<, >, ", ', (, ))를 HTML Entity로 치환하여 저장 전 필터링한다.
searchWord = searchWord.replaceAll("<","<");
searchWord = searchWord.replaceAll(">",">");
searchWord = searchWord.replaceAll("\"",""");
searchWord = searchWord.replaceAll("'","'");
searchWord = searchWord.replaceAll("(","(");
searchWord = searchWord.replaceAll(")",")");
- 이 처리를 통해 <script>는 <script>로 변환되어 실행되지 않음.
2. 출력 시 무효화(Escape)
- 출력 시에도 입력값이 HTML로 해석되지 않도록 동일한 방식으로 치환해 스크립트 실행을 막는다.
3. 허용 태그만 예외 처리 (WhiteList Filtering)
- 게시판 등 HTML 태그 사용이 필요한 경우, <p>, <br> 등 필요한 최소한의 태그만 허용한다.
searchWord = searchWord.replaceAll("<p>","<p>");
searchWord = searchWord.replaceAll("<br>","<br>");
4. 차단할 문자열 설정 (BlackList Filtering)
- javascript, alert, onerror, document 등 자주 사용되는 공격 키워드를 필터링해 차단.
- 단, 누락 가능성이나 정교한 우회가 가능하므로 단독으로 쓰는 것은 위험.
5. XSS 필터 라이브러리 활용
- 검증된 외부 라이브러리를 통해 안전하고 효율적으로 방어 가능:
- Lucy-XSS-Filter - Naver에서 제공, Java 기반 WhiteList 필터
- OWASP ESAPI - 다양한 언어 지원, OWASP에서 제공하는 보안 API
✅ CSRF (Cross-Site Request Forgery) 쉽게 설명하기
CSRF는 사용자가 로그인된 상태에서, 악성 웹사이트가 사용자의 권한으로 원하지 않는 작업을 서버에 요청하는 공격이다. 예를 들어, 은행 계좌에 로그인한 상태에서 악성 사이트에 접속하면, 사용자가 모르게 돈을 이체하는 요청이 보내질 수 있다.
✅ XSS와 CSRF 차이점
- XSS: 악성 스크립트를 사용자의 브라우저에서 실행시켜 정보를 탈취하거나 피싱 공격을 한다.
- CSRF: 사용자의 권한을 도용해 서버에 원하지 않는 요청을 보낸다.
둘의 주요 차이점은 공격 대상과 방식이다.
🛑 2. SQL Injection (SQL 인젝션) 취약점
✅ 설명
웹 애플리케이션이 사용자 입력값을 SQL 쿼리에 직접 포함할 경우, 공격자가 쿼리 구조를 조작하여 인증 우회, 데이터 탈취, DB 조작 등을 수행할 수 있는 취약점이다.
💥 공격 유형
1. 인밴디드(기본형) SQL Injection
- 가장 기본적인 형태로, 공격자는 쿼리에 직접 SQL 구문을 삽입하여 인증 우회나 데이터 조회를 시도한다. 이때 SQL 문법에 악성 코드를 삽입하여 의도한 대로 쿼리를 변조한다.
예시
' OR '1'='1
- 공격 과정
- 사용자가 로그인 폼에 username과 password를 입력한다고 가정
- password에 ' OR '1'='1를 입력하면, 쿼리가 다음과 같이 변형됨:
- SELECT * FROM users WHERE username = 'admin' AND password = '' OR '1'='1'
- '1'='1'은 항상 참이므로, 쿼리가 항상 참으로 평가되어 인증을 우회할 수 있음.
2. 블라인드 SQL Injection
- 공격자가 직접적으로 오류 메시지나 데이터베이스 정보를 확인할 수 없고, 참/거짓에 대한 응답만 받을 수 있다. 공격자는 이를 이용해 점차적으로 정보를 추측하고 파악한다.
예시
' AND 1=1--
' AND 1=2--
- 공격 과정
- ' AND 1=1--는 항상 참이므로 응답이 정상적으로 돌아오고,
- ' AND 1=2--는 거짓이므로 응답이 다르게 돌아옵니다.
이를 통해 공격자는 조건문이 참인지 거짓인지 확인하고, 데이터베이스 구조나 값을 추측할 수 있습니다.
3. 타임 기반 블라인드 SQL Injection
- 쿼리 응답 시간의 차이를 통해 데이터베이스의 참/거짓 값을 구분하는 방식입니다. 조건문이 참일 경우 서버가 지연 시간을 발생시켜, 공격자는 응답 지연 시간을 통해 정보를 추측합니다.
예시
' OR IF(1=1, SLEEP(5), 0)--
- 공격 과정
- IF(1=1, SLEEP(5), 0)은 참일 경우 5초 동안 지연이 발생하게 하므로, 공격자는 응답 시간이 지연되는지 여부를 확인할 수 있습니다.
- 예를 들어, IF(1=2, SLEEP(5), 0)을 입력하면 응답 지연 없이 빠르게 돌아오고, IF(1=1, SLEEP(5), 0)을 입력하면 5초 동안 응답이 지연됩니다.
- 공격자는 이를 반복하여 데이터베이스의 정보를 추측합니다.
4. 유니온 기반 SQL Injection
- UNION 연산자를 사용하여 여러 쿼리의 결과를 결합하는 방식입니다. 공격자는 다른 테이블의 데이터를 결과로 가져오는 방식으로 정보를 탈취할 수 있습니다.
' UNION SELECT username, password FROM users--
- 공격 과정
- 기본적으로 로그인 폼에서는 사용자 이름과 비밀번호를 확인하는 쿼리가 실행됩니다.
- 공격자는 UNION 연산자를 사용하여 다른 테이블에서 정보를 가져옵니다.
- 예를 들어, users 테이블에서 username과 password를 가져오면:
SELECT * FROM login WHERE username = 'admin' AND password = '' UNION SELECT username, password FROM users--
- 이렇게 되면 users 테이블의 username과 password 정보가 공격자의 화면에 노출될 수 있습니다.
💡 요약
공격 유형 | 설명 | 예시 | 공격 방식 |
인밴디드(기본형) | 쿼리에 직접 SQL 삽입 | ' OR '1'='1 | 쿼리 변조로 인증 우회 |
블라인드 | 참/거짓 응답만 확인 가능 | ' AND 1=1-- / ' AND 1=2-- | 응답이 참/거짓으로 나누어짐 |
타임 기반 블라인드 | 응답 지연으로 판단 | ' OR IF(1=1, SLEEP(5), 0)-- | 응답 시간 차이로 조건 확인 |
유니온 기반 | 다른 테이블 데이터 출력 | ' UNION SELECT username, password FROM users-- | 다른 테이블 데이터 결합 |
🛡 대응방안
1. Prepared Statement 사용 (권장)
- 입력값을 직접 SQL에 삽입하지 않고 변수로 바인딩
- SQL Injection 공격에 매우 강력함
String sql = "SELECT * FROM MEMBER WHERE ID = ? AND PW = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, userId);
pstmt.setString(2, userPw);
SQL에서 "바인딩(binding)한다"는 것은, 사용자 입력값을 SQL 쿼리문 안에 직접 넣는 대신, 미리 정의된 변수 자리에 따로 값을 할당하는 것을 의미한다.
예시:
SELECT * FROM users WHERE id = ? AND pw = ?
여기서 ?는 자리표시자(placeholder)이고, 이 자리에 실제 입력값을 setString() 같은 메서드로 나중에 "바인딩"하는 것이다.
이렇게 하면 입력값이 SQL 구문으로 해석되지 않기 때문에 SQL Injection 공격이 불가능하다.
쉽게 말해, 쿼리문과 입력값을 분리하여 처리하는 것이라고 보면 된다.
2. 입력값 검증 및 필터링(차선책)
1)화이트리스트(Whitelist) 기반 입력값 검증
- 예를 들어, 주민등록번호 입력란이라면 숫자만 허용
- 전화번호, 아이디, 이메일 등은 정규식을 통해 특정 형식만 허용
- 추가로 길이도 제한을 두어 공격 구문 삽입이 어렵도록 해야 한다.
if (!input.matches("^[a-zA-Z0-9_]+$")) {
throw new IllegalArgumentException("허용되지 않은 입력입니다.");
}
- 장점: 우회 어려움, 보안 강력
- 단점: 허용해야 할 값을 정확히 정의해야 함
2) 입력값 정제(Input Sanitization)✔ 주요 정제 방식
- ', ", --, ; 같은 SQL 구문 기호 제거 또는 이스케이프 처리
- HTML 엔티티 치환: < → <, > → >
- DB 저장 시에는 정제된 값만 저장
input = input.replaceAll("'", "''"); // SQL에서 작은따옴표 이스케이프
- 효과
- 직접적인 SQLi 차단은 어렵지만 2차 방어선으로 사용
- 바인딩, 화이트리스트와 병행해야 실효성 확보
3) 블랙리스트(Blacklist) 기반 예약어 차단
- 예: select, insert, ', --, or 1=1 등
String filtered = input.replaceAll("(?i)(select|union|--|')", "");
- 장점: 빠르게 적용 가능
- 단점: 우회가 쉬움 (공백 추가, 대소문자 조작 등)
3. 에러 메시지 제한
- SQL 오류 상세정보를 사용자에게 노출하지 않도록 설정
- 사용자에게는 단순 메시지, 내부에는 로그 기록
catch(SQLException e) {
log.error(e.getMessage());
out.println("시스템 오류가 발생했습니다.");
}
🛑 3. 권한인증 취약점 (Authentication & Authorization Vulnerability)
✅ 설명
시스템에서 사용자 인증(Authentication) 또는 권한 확인(Authorization) 로직이 부적절하거나 우회 가능할 경우 발생하는 취약점이다. 이로 인해 공격자는 다른 사용자로 가장하거나, 관리자 권한 기능에 접근할 수 있다.
✅ 사용자 인증과 권한 확인이란?
구분 | 설명 | 예시 |
사용자 인증 (Authentication) | 사용자가 누구인지 확인하는 절차 | 로그인, 토큰 검증 등 |
권한 확인 (Authorization) | 사용자가 무엇을 할 수 있는지 확인하는 절차 | 일반 사용자 vs 관리자 기능 접근 제한 |
- 취약점은 인증 우회는 주로 인증(authentication) 미흡으로
권한 상승/역할 검증 미흡은 권한 확인(authorization) 미흡으로부터 발생한다.
💥 공격 방법 및 설명
1. 인증 우회
- 설명: 로그인하지 않은 사용자가 인증 절차를 건너뛰고, 직접 URL이나 요청을 통해 접근하는 방식
- 공격 예시:
로그인 없이 직접 /admin/dashboard 입력하여 관리자 페이지 접근
- 원인:
- 인증 미적용 URL 존재
- 서버에서 인증 상태 확인을 생략함
- 취약 위치:
- 인증(Authentication) 실패 → 로그인 확인 누락
2. 세션 탈취
- 설명: 다른 사용자의 세션 ID를 탈취하여, 해당 사용자인 것처럼 서버를 속이는 공격
- 공격 예시:
GET /mypage?sessionid=abcd1234
- 탈취된 세션 ID로 로그인 상태 위조
- 세션 탈취 경로:
- XSS로 쿠키 탈취
- URL, Referrer에 노출
- HTTPS 미적용으로 패킷 가로채기
- 취약 위치:
- 인증(Authentication) 우회 → 세션 관리 미흡
3. 수정된 요청 재전송 (권한 상승)
- 설명: 클라이언트에서 보내는 요청 내용을 변조하여 높은 권한의 기능을 실행
- 공격 예시:
POST /updateUser { "role": "admin" }
- 일반 사용자가 관리자 권한으로 전환 요청
- 원인:
- 서버에서 사용자의 권한을 검증하지 않음
- 클라이언트에만 의존한 보안 처리
- 취약 위치:
- 권한 확인(Authorization) 실패
4. 불충분한 역할 검증
- 설명: 로그인은 되어 있지만 사용자의 역할(권한)을 확인하지 않아 관리자 기능에 접근 가능
- 공격 예시:
- 원인:
일반 유저가 /admin/userList 접근
- 로그인 이후 역할 체크 로직 누락
- 취약 위치:
- 권한 확인(Authorization) 누락
🧬 주요 유형 요약
유형 | 설명 | 예시 | 발생 위치 |
인증 우회 | 인증 없이 보호된 URL 접근 | /admin 직접 접근 | 인증(Authentication) 실패 |
세션 탈취 | 타인의 세션 ID 사용 | URL 또는 쿠키로 ID 탈취 | 인증(Authentication) 실패 |
권한 상승 | 낮은 권한에서 높은 권한 기능 수행 | 일반 사용자 → 관리자 API 호출 | 권한 확인(Authorization) 실패 |
역할 검증 미흡 | 로그인 후 역할 미확인 | 일반 사용자 → 관리자 메뉴 접근 | 권한 확인(Authorization) 실패 |
🛡 대응 방안
1. 인증 강화
- 세션 토큰은 HTTPS로만 전달, 쿠키에 HttpOnly, Secure 설정
- 세션 ID는 추측 불가한 랜덤 값으로 구성
- 로그인 상태 확인 로직을 모든 민감 기능에 적용
2. 권한 확인 로직 적용
- 기능마다 접근 권한(예: 관리자, 사용자 등) 별로 명확한 검증 로직 구현
- URL 접근 시에도 역할 기반 제어 적용 (RBAC: Role-Based Access Control)
3. API 요청 검증
- 클라이언트가 보낸 요청 내용을 신뢰하지 말고, 서버에서 사용자 권한 재확인
- 중요한 동작에는 추가 인증(2FA, OTP 등) 적용 고려
4. 로그 및 탐지
- 관리자 접근, 권한 변경 요청 등의 로그 남기기
- 이상 행위 발생 시 알림 기능 구축
🛑 4. 에러처리 취약점 (Improper Error Handling Vulnerability)
✅ 설명
애플리케이션이 예외 상황 발생 시 내부 정보(에러 메시지, 스택 트레이스, 경로 등)를 사용자에게 그대로 노출할 경우 발생하는 취약점이다. 공격자는 이를 통해 시스템 구조, DB 쿼리, 파일 경로 등 정보를 얻어 추가 공격의 단서로 활용할 수 있다.
💥 공격 방법
1. 에러 메시지 노출 (ID 존재 여부 노출)
- 로그인 실패 시 에러 메시지를 다르게 보여주면, ID가 존재하는지 여부를 유추할 수 있다.
입력: ID = hacker, PW = 1234
→ "존재하지 않는 사용자입니다"
입력: ID = admin, PW = 1234
→ "비밀번호가 틀렸습니다"
- 문제점
- 공격자는 위 메시지를 비교하여 admin이라는 아이디가 존재함을 확인할 수 있다.
- 대응방안
- 모든 로그인 실패 시 다음과 같이 일괄적인 메시지 사용
→ "아이디 또는 비밀번호가 일치하지 않습니다"
- 모든 로그인 실패 시 다음과 같이 일괄적인 메시지 사용
2. 스택 트레이스 노출 (프로그래밍 오류 정보 노출)
- 입력값이 잘못되었거나 서버 코드에 오류가 있을 때, 내부 코드 경로, 모듈명, 라이브러리 등이 담긴 스택 트레이스가 그대로 출력됨.
java.lang.NullPointerException
at com.example.project.user.UserService.getUser(UserService.java:52)
at ...
- 문제점
- 내부 경로 (com.example.project.user) 노출
- 취약한 메서드 및 라인 식별 가능 (UserService.java:52)
- 대응방안
- 사용자에게는 단순한 에러 메시지만 제공
→ "일시적인 오류가 발생했습니다. 다시 시도해주세요"
- 상세 오류는 서버 로그로만 기록
- 사용자에게는 단순한 에러 메시지만 제공
3. SQL 오류 노출 (SQL Injection 진단 힌트 제공)
- SQL Injection 시 ' 같은 특수 문자를 입력하면 SQL 구문 오류가 발생하고, DB 오류 메시지가 사용자에게 그대로 보여짐
입력: ' OR '1'='1
→ 출력: You have an error in your SQL syntax near '' OR '1'='1'
- 문제점
- 공격자는 SQL 문장 구조를 파악하고, 컬럼명, 테이블명, DB 종류(MySQL/PostgreSQL 등)를 추측할 수 있음
- 대응방안
- 오류 메시지는 사용자에게 숨기고, 서버 로그에만 기록
- PreparedStatement 등 바인딩 쿼리 사용
- WAF 또는 필터링 기능 적용
4. 파일 경로 노출 (서버 구조 유출)
- 요청한 파일이 존재하지 않거나 서버에서 오류가 발생하면 전체 경로가 포함된 메시지를 그대로 노출함
Warning: include(config.php): failed to open stream: No such file or directory in /var/www/html/index.php on line 3
- 문제점
- 서버 디렉터리 구조(/var/www/html/) 노출
- 내부 파일명(config.php) 유출
- 대응방안
- 오류 발생 시 사용자에게는 일반적인 메시지 제공
→ "페이지를 찾을 수 없습니다"
- php.ini 또는 web.xml 등에서 오류 상세 메시지 출력 차단 설정
- PHP 예시: display_errors = Off
- 오류 발생 시 사용자에게는 일반적인 메시지 제공
🔐 요약표
유형 | 설명 | 예시 | 위험 요소 |
에러 메시지 노출 | ID 존재 여부 유추 가능 | "존재하지 않는 사용자입니다" | 사용자 식별 가능 |
스택 트레이스 노출 | 내부 소스/파일 경로 노출 | NullPointerException at UserService.java:52 | 코드 구조 노출 |
SQL 오류 노출 | SQL Injection 가능성 탐지 | SQL syntax error near ' OR '1'='1 | DB 구조 파악 |
파일 경로 노출 | 시스템 경로 유출 | /var/www/html/index.php 오류 | 시스템 구조 노출 |
🛡 에러·예외 정보 노출 최소화 대응 방안
1. 에러 메시지 최소화
- 목표 : 내부 정보 노출 차단, 공격 표면 축소
- 운영 체크리스트
- 사용자 화면엔 “서버에 오류가 발생했습니다” 등 일반 메시지만 표시
- 상세 오류·스택은 권한 제어된 로그에 기록
- 프로덕션에서는 debug / verbose 옵션 OFF
2. 스택 트레이스 숨기기
- 목표 : 파일 경로·라이브러리 정보 차단
- 운영 체크리스트
- try–catch 후 사용자 응답 = 일반 메시지
- exception.printStackTrace() 금지 (스택은 내부 로거로)
- APM·모니터링 도구로 오류 추적
3. SQL 오류 메시지 숨기기
- 목표 : 테이블·쿼리 구조 노출 방지 → SQL Injection 난이도 상승
- 운영 체크리스트
- SQL 예외 시 사용자에게 “데이터 처리 중 오류” 등으로 통일
- 실제 쿼리·바인딩 값은 내부 로그에만 기록(PII 마스킹)
4. 파일 경로 노출 방지
- 목표 : 디렉터리 구조 탐색 차단
- 운영 체크리스트
- 404·403 등 파일 관련 오류 응답에 절대 경로·스택 포함 금지
- 로그에는 상대 경로나 식별자만 기록
5. 사용자 정의 오류 페이지
- 목표 : 기본 서버 오류 페이지로 인한 정보 누출 차단
- 운영 체크리스트
- 404·500·503 등 모든 상태 코드에 커스텀 HTML 적용
- 간단·친절한 문구 + 연락처/재시도 버튼 포함
- 서버 측에서만 상세 오류 기록
'Security > CERT' 카테고리의 다른 글
웹 쉘이란? (1) | 2025.04.10 |
---|---|
웹 보안 취약점(3) (0) | 2025.03.28 |
웹 보안 취약점(2) (0) | 2025.03.20 |
웹 보안 취약점(1) (0) | 2025.03.15 |
Shodan을 통한 IoT 기기 검색과 특징 (0) | 2025.03.01 |