본문 바로가기

spring

웹 어플리케이션 보안 취약성

공격자는 공격을 시작하기 전에 애플리케이션의 취약성(Vulnerability)을 파악하고 공략해야 함
≫ 취약성 : 악의적 의도를 가지고 원치 않는 작업을 수행하는 데 이용할 수 있는 약점

 

인증과 권한 부여의 취약성
  • 인증 (Authentication) : 애플리케이션이 이를 이용하려는 사람을 식별하는 프로세스
    어떤 사용자나 존재가 앱을 이용하려고 하면 추가 접근을 허가하기 전에 먼저 이들의 ID를 확인해야 함
    실제 앱에서는 익명 액세스를 지원할 때도 있지만 대부분은 식별된 사용자만 데이터를 이용하거나 특정 작업을 수행할 수 있음
  • 권한부여 또는 인가 (Authorization) : 인증된 호출자가 특정 기능과 데이터에 대한 이용 권리가 있는지 확인하는 프로세스
    예) 대부분의 인증된 사용자는 자금을 이체할 수 있지만 자신의 계좌에서만 가능

 

세션 고정 (Session fixation)
  • 세션 고정 취약성 : 웹 애플리케이션의 더 구체적이고 심각한 약점
  • 이 취약성이 존재하면 공격자는 이미 생성된 세션 ID를 재이용해 유효한 사용자를 가장할 수 있음
  • 이 취약성은 웹 애플리케이션이 인증 프로세스 중에 고유한 세션 ID를 할당하지 않아 기존 세션 ID가 재사용될 가능성이 있을 때 발생함
  • 악용하려면 먼저 유효한 세션 ID를 획득한 후 피해자의 브라우저가 이를 이용하게 해야 함
sequenceDiagram
    participant A as 공격자
    participant W as 웹사이트
    participant V as 피해자
    
    A->>W: 유효한 세션 ID 요청
    W->>A: 세션 ID 발급
    A->>V: 세션 ID 포함된 링크 전송
    Note over V,A: 피싱 이메일, 맬웨어 등 사용
    V->>W: 세션 ID를 사용하여 로그인
    W->>V: 로그인 성공
    Note over V,W: 세션 ID는 이제 피해자의 인증 정보와 연결됨
    A->>W: 알고 있는 세션 ID를 사용하여 접근
   	W->>A: 피해자로 인식, 세션 탈취 성공
    Note over A,W: 공격자는 이제 피해자의 권한으로 행동할 수 있음

 

 

XSS 교차 사이트 스크립팅
  • 서버에 노출된 웹 서비스로 클라이언트 쪽 스크립트를 주입해 다른 사용자가 이를 실행하도록 하는 공격
  • 사용자가 공격에 노출된 웹 페이지를 방문하면 삽입된 악성 스크립트가 사용자의 브라우저에서 실행되어 사용자의 세션 쿠키를 탈취하거나, 개인 정보를 수집하고, 심지어 사용자를 대신하여 악의적인 행동을 수행할 수 있음
  • 원치 않는 외래 스크립트의 실행을 방지하기 위해 이용하기 전이나 심지어 저장하기 전에도 요청을 적절하게 '소독(sanitization)'하는 과정이 필요함
  • 이 취약성이 악용되면 계정 가장(세션 고정과 결합)이나 DDos와 같은 분산 공격 참여 등의 결과가 발생할 수 있음
sequenceDiagram
    participant U as 사용자
    participant A as 공격자
    participant W as 웹 애플리케이션
    
    A->>U: 악성 스크립트 포함 링크 전송
    Note over U,A: 피싱 이메일, 메시지 등을 통해
    U->>W: 링크 클릭 & 요청 전송
    Note over W: 요청에 악성 스크립트 포함
    W->>U: 악성 스크립트 포함 응답
    Note over U: 브라우저에서 스크립트 실행
    U->>A: 스크립트에 의한 정보 유출 (예: 쿠키)

 

 

CSRF (사이트 간 요청 위조)
  • CSRF 공격은 특정 서버에서 작업을 호출하는 URL을 추출해 애플리케이션 외부에서 재사용할 수 있다고 가정
  • 서버가 요청의 출처를 확인하지 않고 무턱대고 실행하면 모든 곳에서 요청이 실행될 수 있음
  • 공격자는 CSRF를 통해 동작을 숨겨서 사용자가 서버에서 원치않는 동작을 실행하도록 할 수 있음
  • 일반적으로 공격자는 CSRF를 이용해 시스템의 데이터를 변경하는 동작을 실행
sequenceDiagram
    participant U as 사용자
    participant B as 브라우저
    participant A as 악의적 사이트
    participant W as 웹 애플리케이션
    
    U->>W: 로그인 & 세션 생성
    Note over U,W: 사용자는 웹 애플리케이션에 로그인함
    U->>A: 악의적 사이트 방문
    A->>B: 악성 요청 포함 웹 페이지 제공
    Note over A,B: 이미지 태그를 이용한 요청 등
    B->>W: 악성 요청 전송 (사용자의 쿠키와 함께)
    Note over W: 웹 애플리케이션은 요청이 사용자로부터 온 것으로 판단
    W->>W: 요청 처리 (예: 비밀번호 변경, 송금 등)

 

CSRF 발생 시나리오

 

"시민뱅크" : 가상의 온라인 은행 서비스

- 이 서비스를 사용하려면 사용자는 사용자의 이름과 비밀번호를 사용하여 로그인해야 하며, 송금과 같은 금융 거래를 수행할 수 있음

- 사용자 "홍길동"은 이 은행의 고객으로, 자주 온라인 뱅킹 서비스를 이용

 

  1. 공격자의 준비 : 공격자 "김해커"는 시민뱅크 사용자들이 로그인한 상태에서 자신의 조작된 웹 페이지를 방문하도록 유도하기 위해 피싱 이메일을 준비
    이 이메일에는 "금융 시장의 최신 동양을 확인하세요!"라는 제목과 함께 김해커가 만든 악성 웹 페이지로 연결되는 링크가 포함되어 있음
  2. 피싱 이메일 발송 : 홍길동은 자신의 이메일에서 김해커가 보낸 메시지를 받고, 궁금증에 링크를 클릭
  3. 악성 요청 실행 : 링크를 클릭하면, 홍길동의 브라우저는 김해커의 악성 웹 페이지로 리다이렉트됨
    이 페이지에는 홍길동이 로그인한 상태에서 시민뱅크에 대한 숨겨진 송금 요청을 자동으로 전송하는 JavaScript 코드가 포함되어 있음
  4. 이 요청은 홍길동의 브라우저에서 시민뱅크의 송금 API를 호출하게 하며, amount와 toAccount 파라미터는 김해커가 지정한 값을 사용
  5. 악성 송금 실행 : 홍길동의 브라우저가 이 요청을 실행할 때, 시민뱅크는 홍길동이 이미 로그인한 상태이고, 브라우저에 저장된 쿠키를 통해 인증된 사용자로부터의 요청으로 간주됨
    따라서, 시민뱅크는 요청된 송금을 처리하고 홍길동의 계좌에서 김해커의 계좌로 1000달러가 이체됨
  6. 공격 발견 : 나중에 홍길동은 자신의 계좌 잔액이 예상치 못하게 감소한 것을 확인하고 은행에 연락하여 이상한 송금 거래를 알게 됨
<img 
    src="https://citizenbank.com/transfer?amount=1000&toAccount=~"
    style="display:none;"
>
  • 악성 웹 페이지에 포함된 JavaScript 코드 (김해커의 계좌로 1000달러를 이체하는 송금 요청 전송)

 

웹 애플리케이션의 주입 (injection) 취약성
  • 주입 공격은 광범위한 공격 방식 !
  • 공격자는 시스템에 특정 데이터를 유입하는 취약성을 이용
  • 공격의 목표는 시스템에 피해를 주고, 원치 않는 방법으로 데이터를 변경하거나 원래는 접근할 수 없는 데이터를 검색하는 것

 

주입 공격의 유형
  • XSS도 주입 취약성의 하나
  • 시스템에 피해를 가할 목적의 클라이언트 쪽 스크립트 주입
  • SQL 주입, Xpath 주입, os 명령 주입 등

주입은 피해 시스템의 데이터 변경, 삭제, 무단 이용을 유발하는 중요한 취약성 유형

 

주입 공격 발생 시나리오

 

웹 애플리케이션에서 사용자의 로그인을 처리하는 곳에, 사용자 이름과 비밀번호를 입력받아 다음과 같은 SQL 쿼리를 실행하는 코드가 있음

 

정상 쿼리 :

SELECT *
FROM users
WHERE username = '[사용자 입력]'
AND password = '[비밀번호 입력]';
  • 정상적인 경우 사용자는 자신의 username과 password를 입력하고, 이 쿼리는 해당 사용자의 정보를 데이터베이스에서 조회하여 로그인을 처리

 

SQL 주입 공격 : 

공격자가 사용자 이름 입력 칸에 ' OR '1'='1 과 같은 값을 입력하고 비밀번호 입력란은 비워둔다면,

위의 SQL 쿼리는 다음과 같이 변형되어 실행됨

SELECT * FROM users WEHRE username = '' OR '1'='1' AND password = '';
  • '1'='1'은 항상 참이 되므로, 데이터베이스 내의 모든 사용자를 선택하게 되어 결과적으로 공격자는 비밀번호를 모르더라도 첫 번째로 조회되는 사용자로 로그인 할 수 있게 됨

 

민감한 데이터의 노출 처리

 

1. 구성 파일

  • 실제 개발된 시스템에서는 모든 환경에서 민감한 데이터 값을 볼 수 없어야 하고, 적어도 운영 환경에서는 소수의 사람만 개인 데이터에 접근할 수 있어야 함
  • 이러한 값을 스프링 프로젝트의 application.properties 또는 application.yml 파일 등의 구성 파일에서 설정하면 소스 코드를 볼 수 있는 모든 사람이 이러한 개인 값에 접근할 수 있음 + 소스 코드의 버전 관리 시스템에서도 이러한 값의 변경 기록이 저장됨

2. 로그

  • 민감한 데이터에 대해 다음과 같은 경우도 발생
    • 애플리케이션에서 콘솔에 기록
    • 스츨렁크(Splunk)나 엘라스틱서치(Elasticsearch) DB에 저장하는 로그 정보
  • 로그에 기록해서는 안 될 정보를 포함하면 안 됨 !!

예)

[오류] 요청의 서명이 잘못되었습니다. 사용할 올바른 키는 X입니다.
[경고] 사용자 이름 X와 암호 Y를 이용하여 로그인하지 못했습니다. 사용자 이름 X의 ~...
[정보] 사용자 X가 올바른 암호 Y를 이용하여 로그인 하였습니다.

 

3. HTTP 상태 코드

{
"상태" : 500,
"오류" : "내부  서버  오류",
"메시지" : "IP 주소 10.2.5.8/8080에  대한  연결이  발견되지  않음", "경로" : "/product/add"
}
  • 예) 500 에러의 메시지에 IP 주소가 공개됨
  • 공격자는 이 주소를 보고 네트워크 구성을 파악하고 최종적으로 인프라의 VM을 통제하는 방법을 찾아낼 수 있음
  • 이 데이터만 가지고 공격을 시작할 수는 없지만, 노출된 다른 정보를 계속 수집/조합하면 결국 시스템 공격을 성공할 수 있음

 

메서드 접근 제어 부족
  • 애플리케이션의 메서드나 API에 대한 접근 제어가 적절히 구현되지 않아 무단으로 중요한 기능을 실행할 수 있는 취약점
  • 스프링 시큐리티를 사용하는 스프링 애플리케이션에서는 @PreAuthorize, @Secured 등의 어노테이션을 이용하여 메서드 수준에서 세밀한 접근 제어를 설정할 수 있음
    ≫ 이러한 접근 제어를 통해 특정 권한을 가진 사용자만이 메서드를 실행할 수 있도록 제한할 수 있음
  • 애플리케이션 수준에도 한 계층에만 권한 부여를 적용해서는 안됨 : 때에 따라서는 특정 기능을 아예 호출할 수 없게 해야 함
    예) 현재 인증된 사용자의 이용 권리에 허용되지 않는 경우

 

메서드 접근 제어 부족 발생 시나리오

 

AccountController, AccountService, AccountRepository를 가진 간단한 계정 관리 애플리케이션 가정

이 애플리케이션에서는 사용자의 계정 정보를 조회하고 수정할 수 있음

  • AccountController는 사용자의 HTTP 요청을 처리하여 AccountService의 메서드를 호출
  • AccountService는 비즈니스 로직을 수행하고, 필요한 경우 AccountRepository를 통해 데이터베이스와의 상호작용을 담당
  • AccountRepository는 Spring Data JPA를 사용하여 데이터베이스에 접근하는 메서드를 제공

 

메서드 접근 제어 부족 문제 : 

예) AccountService의 updateAccountDetails() 메서드

사용자의 계정 정보를 업데이트하는 중요한 기능 메서드 

→ 접근 제어 부족 문제가 발생한다면, 비인가 사용자도 계정 정보를 변경할 수 있게 됨

public class AccountService {
	public void updateAccountDetails(Account account) {
		// 계정  정보  업데이트  로직
	}
}

 

스프링 시큐리티를 이용한 해결 방안 : 

스프링 시큐리티를 사용하여 updateAccountDetails() 메서드를 호출할 수 있는 사용자를 제한

예) @PreAuthorize 어노테이션을 사용하여 해당 메서드를 "ADMIN" 역할을 가진 사용자만 접근할 수 있도록 설정

@PreAuthorize("hasRole('ADMIN')")
public void updateAccountDetails(Account account) { 
	// 계정  정보  업데이트  로직
}

 

sequenceDiagram
    participant U as 사용자
    participant C as AccountController
    participant S as AccountService
    participant R as AccountRepository
    participant Sec as Spring Security
    
    U->>C: 계정 정보 업데이트 요청
    C->>Sec: 접근 권한 확인
    Sec->>C: 권한 부여 (ADMIN)
    C->>S: updateAccountDetails() 호출
    S->>R: 데이터베이스 업데이트
    R->>S: 업데이트 완료
    S->>C: 서비스 처리 완료
    C->>U: 업데이트 응답

 

TransactionController가 추가된 경우

sequenceDiagram
    participant U as 사용자
    participant TC as TransactionController
    participant TS as TransactionService
    participant AR as AccountRepository
    participant Sec as Spring Security
    
    U->>TC: 계좌 이체 요청
    alt 권한이 부족한 경우
    	TC->>Sec: 접근 권한 확인
        Sec->>TC: 권한 거부
        TC->>U: 이체 실패 응답
    else 권한이 충분한 경우
    	TC->>Sec: 접근 권한 확인
        Sec->>TC: 권한 부여
        TC->>TS: executeTransaction() 호출
        TS->>AR: 계좌 정보 업데이트
        AR->>TS: 업데이트 완료
        TS->>TC: 서비스 처리 완료
        TC->>U: 이체 성공 응답
    end

 

 

 

 

'spring' 카테고리의 다른 글

HTTPS vs HTTP  (0) 2024.11.02
로깅(Logging)  (0) 2024.09.20
영속성 전이  (0) 2024.09.15
다대일 단/양방향 매핑  (0) 2024.09.15
연관관계 매핑 종류 / 방향  (0) 2024.09.15