CORS, CSRF가 무엇인지 부터 알아야 하겠지만, 우선 테스트가 목적이므로 간략하게 알아본 뒤 코드를 적용한다.
결론부터 말하자면 CORS는 테스트를 위해서 모든 Origin(출처)에 대해서 허용하도록 수행하고, CSRF는 Disable 상태로 변경한다.
CORS는 Cross Origin Resuorce Sharing의 약자로 교차-출처 리소스 공유로 다른 출처 사이에 정보를 공유하게 되면 발생하는 정책이다.
출처는 Protocol, Host, 포트번호를 의미한다. 따라서 프론트 주소인 localhost:3000와 백엔드 주소인 localhost:8080은 서로 다른 출처가 되게 되어 CORS 정책에 의해 차단된다.
CORS가 없을 경우, CSRF(Cross Site Request Forgery) 문제가 발생한다.
CORS란 무엇인가요? - amazon
https://aws.amazon.com/ko/what-is/cross-origin-resource-sharing/
CORS는 왜 이렇게 우리를 힘들게 하는걸까?
CSRF 공격이란? 그리고 CSRF 방어 방법
CSRF(Cross Site Request Forgery) - 사이트 간 요청 위조. 어떤 서버에서 인증된 브라우저의 정보를 공격자가 만든 악성 페이지를 통해 사용하여 사용자 모르게 공격을 수행한다.
쿠키를 통한 CSRF 공격이 수행되기 때문에 쿠키나 세션에 의존하지 않는 REST API, JWT를 사용하면 비교적 안전하다. 그래도 CSRF를 disable할 경우 보안 취약점이 생길 수 있으므로 주의해야 한다.
CSRF(Cross-Site Request Forgery) 공격과 방어
SecurityFilterChain에 CORS, CSRF 예외 정책을 적용한다.
SecurityConfig.java 파일을 생성하고. Configuration 어노테이션 등을 붙여준다. 이후 Security FilterChain에 cors, csrf 예외 코드를 적용한다.
CorsConfigurationSource를 생성해서 모든 Origin을 허용하도록 적용시키고 csrf.disable()을 통해 csrf를 비활성화 시킨다. (csrf 활성화 되어 있는 경우 403 Error 발생)
이후 실행하면 정상적으로 값을 가져오는 것을 확인할 수 있다.
수정 사항 Git 반영.
SecurityConfig.java
package com.toyproject.toyproject;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(Customizer.withDefaults())
.csrf((csrf) -> csrf.disable());
return http.build();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
tempController.java : RequestBody Parameter 수정
package com.toyproject.toyproject;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/user")
public class tempController {
@PostMapping("/signUp")
public String userSignUp(@RequestBody Map<String, String> userInfo) {
System.out.println("signUp");
System.out.println(userInfo);
return "returnValue";
//return new ResponseEntity<Boolean>(Boolean.TRUE, HttpStatus.OK);
//return new ResponseEntity<Boolean>(Boolean.FALSE, HttpStatus.INTERNAL_SERVER_ERROR);
}
@GetMapping("/test")
public String userSignUp() {
System.out.println("Test");
return "Test";
}
}
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.2'
id 'io.spring.dependency-management' version '1.1.2'
}
group = 'com.toy-project'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.kafka:spring-kafka'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.kafka:spring-kafka-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('test') {
useJUnitPlatform()
}