[3.24]csrf

Always·2025년 3월 24일
1

매일메일

목록 보기
67/69

csrf

Cross-site Request Forgery의 줄임말로, 사용자는 모르는 사이에 의도하지 않은 요청을 위조하는 공격을 의미한다.
내가 벨로그에 로그인을 하면, 서버에서는 브라우저로 쿠키를 넘겨준다.
이 세션을 통해서 이후에 로그인할 때, 사용자는 새로 로그인하지 않고,로그인 이후의 동작을 처리할 수 있다.

csrf는 이를 이용해서 사용자로 하여금, 의도하지 않은 동작을 하게 한다.
예를 들어서 벨로그가 아닌 특정 사이트에서 이미지를 넣어두고, 이미지의 url을
<img src ="https://velog.com/member/changePassword?newValue=1234" /> 로 설정하면 이미지를 누르면 사용자는 브라우저에 있는 벨로그의 세션을 이용해서, 의도하지 않은 비밀번호의 변경을 수행시킬 수 있다.

이렇게 사용자가 자신의 의지와 상관없이 공격자가 의도한 의도한 행위를 특정 웹사이트에 요청하도록 하는 것을 csrf라고 한다.

csrf 방어 방법

csrf는 위조 되지않은 요청임을 서버에서 확인하는 과정을 통해서 가능하다.

referer

단순하게 현재 요청한 사이트의 경로 즉 origin을 보내준다면, 서버에서 이를 체크해서, 실제 사용자의 사이트인지, 공격자의 사이트에서 보내주는 건지를 확인해서, 예외를 발생시키면 된다.

referer헤더는 클라이언트에서 자동으로 넣어준다.
이를 Spring Secutirty에서는 필더를 이용해서 확인이 가능하다.

public class RefererCheckFilter extends OncePerRequestFilter {

    private static final String TRUSTED_REFERER_PREFIX = "https://yourdomain.com";

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
                                    throws ServletException, IOException {

        String referer = request.getHeader("Referer");

        // 예: POST 요청일 경우만 검사
        if ("POST".equalsIgnoreCase(request.getMethod())) {
            if (referer == null || !referer.startsWith(TRUSTED_REFERER_PREFIX)) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "CSRF suspected: invalid Referer");
                return;
            }
        }

        filterChain.doFilter(request, response);
    }
}

필터를 OncePerRequestFilter를 통해서 구현이 가능하고 이를
securityConfig에서 아래와 같이 필터로 추가해주면 된다.

@Configuration
public class SecurityConfig {

   @Bean
   public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
       return http
           .csrf(csrf -> csrf.disable())  // JWT라면 비활성화 가능
           .addFilterBefore(new RefererCheckFilter(), org.springframework.security.web.csrf.CsrfFilter.class)
           .authorizeHttpRequests(auth -> auth
               .anyRequest().permitAll()
           )
           .build();
   }
}

이를 통해서 referer체크가 가능하다.

jwt를 이용

csrf는 쿠키를 자동으로 요청에 넣어주기 때문에, 문제가 발생하는 경우가 많다.
따라서 jwt를 이용해서 헤더에 담아서 보내주도록 한다면 csrf를 방어할 수 있을 것이다.

CSRF 토큰

로그인 후 서버는 클라이언트에게 CSRF 토큰을 발급하고,
클라이언트는 요청마다 이 토큰을 함께 전송해야 한다.
이는 Referer처럼 요청의 출처를 확인하는 역할을 하지만,
토큰 기반이므로 위조가 어려워 더 높은 신뢰성을 가진다

이 방식도 위처럼 Filter를 통해서 구현하고, 넣기만 하면 될듯하다.

세션에서 Samesite

HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=ABC123DEF456; Path=/; 
HttpOnly; Secure; SameSite=Strict

SameSite의 속성을 통해서 서버와 같은 주소의 요청 일 때만 지정이 가능하다

Cors vs Csrf

✅ CORS와 CSRF

처음에는 CSRF 공격을 CORS로 해결할 수 있을 거라고 생각할 수 있지만,
CORS는 CSRF를 막기 위한 메커니즘이 아니다.

✅ CORS의 목적

CORS는 다른 출처(origin)의 클라이언트가 서버 응답을 읽을 수 있는지 여부를 제어하는 보안 정책이다.

  • 여기서 말하는 origin은
    👉 요청을 보내는 쪽의 URL과 요청을 받는 서버의 URL을 의미한다.

하지만 CSRF는 다르다

CSRF는 사용자가 "현재 있는 페이지의 출처(URL)"와 서버의 출처가 다름에도 불구하고, 인증된 쿠키가 자동으로 요청에 포함되는 현상을 악용하는 공격이다.

다시 말해, 브라우저는 요청을 보낼 때 쿠키를 자동으로 첨부하기 때문에,
외부 사이트에서 요청을 보내도 서버는 그것을 "정상 요청"으로 착각할 수 있다.

profile
🐶개발 블로그

0개의 댓글