Backend๐Ÿ–ฅ๏ธ/Javaโ˜•(Spring๐Ÿƒ)

[Spring] Spring Security - application.yml๋กœ URL๊ถŒํ•œ์„ ๋™์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ

JanuDev 2025. 10. 20. 16:28

๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ ์•ˆํ•˜๊ณ  ๋ฐ”๋กœ Spring security๋กœ ํด๋ผ์ด์–ธํŠธ - ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์‹œํ‚ค๋ ค ํ•˜๋‹ˆ ๋‹น์—ฐํžˆ 403์—๋Ÿฌ๊ฐ€ ์ž๊พธ ๋‚˜์„œ ์—ด๋ฐ›๋Š”๋‹ค.

๋นจ๋ฆฌ ๋กœ๊ทธ์ธ์„ ๋จผ์ € ๊ตฌํ˜„ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์€๋ฐ... ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋‹ค ๋งŒ๋“  ํ›„ ์ตœํ›„์— ๋กœ๊ทธ์ธ์„ ๋งŒ๋“ค๊ณ  ์‹ถ์–ด์„œ ๋ฏธ๋ค„๋†จ๋˜ ์ด๋ฆฌ ๊ท€์ฐฎ์€ ๋Œ“๊ฐ€๋ฅผ ๋ฐ›๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ทธ๋ž˜๋„ ๊ณต๋ถ€ํ•œ๋‹ค ์ƒ๊ฐํ•ด์•ผ์ง€....

 

1. ์›๋ž˜๋Š” ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ–ˆ์—ˆ๋Š”๊ฐ€

SecurityConfig๋Š” ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•  ๋ณด์•ˆ ์ •์ฑ…์„ ์„ค์ •ํ•˜๊ณ  ์ ์šฉ์„ ํ•˜๋Š” ํด๋ž˜์Šค์ด๋‹ค. 

์•„๋ฌด ์„ค์ • ์—†์ด ํด๋ผ์ด์–ธํŠธ์™€ ํ†ต์‹ ํ•˜๋ ค๋ฉด 403 forbidden์—๋Ÿฌ๋ฅผ ๋งŒ๋‚˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

๊ทธ๋ž˜์„œ ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์˜ค๋Š” url์„ ํ—ˆ์šฉ์‹œํ‚ค๊ธฐ ์œ„ํ•ด requestMatchers์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ์—ˆ๋‹ค.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(auth -> auth
                    .requestMatchers("/chat/**", "/uploads/**", "/diary/**").permitAll()
                    .requestMatchers(securityProperties.getPermitUrls().toArray(new String[0])).permitAll()
                    .anyRequest().authenticated())
            .csrf(csrf->csrf.disable())
            .headers(headers -> headers.frameOptions(frameOptions -> frameOptions.disable()));
            .headers(headers -> headers.frameOptions(frameOptions -> frameOptions.disable())
            );

    return http.build();
}

๊ทผ๋ฐ ๋ด์„œ ์•Œ๊ฒ ์ง€๋งŒ... ๋‚ด๊ฐ€ ์ƒˆ๋กœ์šด ํ™”๋ฉด๊ณผ url์„ ๋งŒ๋“ค๋•Œ๋งˆ๋‹ค ์ €๋ ‡๊ฒŒ ๋ฌธ์ž์—ด๋กœ ๊ณ„์† ์ถ”๊ฐ€ํ•  ์ˆœ ์—†๋Š” ๋…ธ๋ฆ‡์ด๋‹ค. 

๊ทธ๋ž˜์„œ ๋”ฐ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

2. application.yml ์ƒ์„ฑ

application.yml์€ resource/configํŒŒ์ผ์— ์ž‘์„ฑํ–ˆ๋‹ค.

security:
  permit-urls:
    - /chat/**
    - /uploads/**
    - /diary/**

์ด์ œ ์ €๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด ์œ„ url์„ ํฌํ•จํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์€ ๋ฐ›์•„๋“ค์—ฌ์ง€๊ฒŒ ๋œ๋‹ค.

์ฐธ๊ณ ๋กœ ,๋Š” ์ ˆ๋Œ€ ๊ธˆ๋ฌผ! ,๋Š” ๋ฌด์กฐ๊ฑด ๋บ„๊ฒƒ. ์›๋ž˜๋Š” chat, uploads... ์ด๋ ‡๊ฒŒ ์ผ๋Š”๋ฐ ์ฝค๋งˆ๋ฅผ ๋ถ™์ด๋‹ˆ๊นŒ ํ†ต์‹ ์ด ์•ˆ์ด๋ฃจ์–ด์กŒ๋‹ค. ์•Œ๊ณ ๋ณด๋‹ˆ ๋ฌธ๋ฒ•์˜ค๋ฅ˜๋ผ๊ณ 

 

3. ClientSecurityProperties.java ์ƒ์„ฑ

SecurityConfigํŒŒ์ผ์ด ์žˆ๋Š” ๊ฐ™์€ ํŒŒ์ผ ์•„๋ž˜ ClientSecurityPropertiesํŒŒ์ผ์„ ํ•˜๋‚˜ ์ƒ์„ฑํ•ด์„œ ๋งŒ๋“ ๋‹ค. 

์ด ํŒŒ์ผ์˜ ์šฉ๋„๋Š” application.yml์˜ ์„ค์ •๊ฐ’์„ Java ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ณด๊ด€ํ•˜๋Š” ํด๋ž˜์Šค์ด๋‹ค. 

 

์œ„์—์„œ ๋ณด๋ฉด ์•Œ๊ฒ ์ง€๋งŒ, permit-urls์—๋Š” ๋‹ค์–‘ํ•œ URL์ด ๋‹ด๊ฒจ์žˆ์œผ๋ฏ€๋กœ ๋ฐ˜๋“œ์‹œ List<String>์œผ๋กœ ์ €์žฅํ•ด๋‘ฌ์•ผ ํ•œ๋‹ค. 

๋”ฐ๋ผ์„œ ์ž๋ฃŒํ˜•์€ List<String>์ด๋‹ค.

@Configuration
@ConfigurationProperties(prefix="security")
public class ClientSecurityProperties {

    // private Field
    private List<String> permitUrls;
    
    // getter
    private List<String> getPermitUrls() {
      return permitUrls;
    }
    
    // setter
    private void setPermitUrls() {
      this.permitUrls = permitUrls;
    }   

}

ClientSecurityProperties์˜ ์—ญํ• ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

1๏ธโƒฃ application.yml์˜ ๊ฐ’์„ Java ๊ฐ์ฒด๋กœ ๋ฐ”์ธ๋”ฉ

application.yml ํ˜น์€ application.properties์˜ ๊ฐ’์„ ์ž๋ฐ” ์ฝ”๋“œ ๋‚ด์—์„œ List<String>์ž๋ฃŒ๊ตฌ์กฐ๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํŠน์ • ๊ฐ์ฒด์˜ ํ•„๋“œ์— ๋งคํ•‘ํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค.

  • @Configuration : @Component๋ฅผ ์‚ฌ์šฉํ•ด๋„ ์ƒ๊ด€์€ ์—†์ง€๋งŒ, ์„ค์ •๊ณผ ๊ด€๋ จ๋œ ํŒŒ์ผ์ž„์„ ๋ช…์‹œํ•˜๊ธฐ ์œ„ํ•ด @Configuration์„ ์ž‘์„ฑํ•˜๋Š”๊ฒŒ ๊ด€๋ก€์ด๋‹ค. ์ง€๊ธˆ ์ด ํด๋ž˜์„œ๊ทธ '์„ค์ • ํด๋ž˜์Šค'์ž„์„ ๋ช…์‹œํ•˜์—ฌ Spring ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋˜๊ฒŒ ํ•œ๋‹ค.
  • @ConfigurationProperties(perfix="security") : appication.yml์˜ security: ์•„๋ž˜์˜ ๋ชจ๋“  ์†์„ฑ์„ ์ด ํด๋ž˜์Šค์— ๋งคํ•‘์‹œํ‚จ๋‹ค. 
    • ex) chat, uploads, diary๋ฅผ ๋ชจ๋‘ List<String>์˜ ํ˜•ํƒœ๋กœ permitUrls์— ๋งคํ•‘

 

2๏ธโƒฃ Spring Bean์œผ๋กœ ๋“ฑ๋ก ๋ฐ ์˜์กด์„ฑ ์ฃผ์ž…(DI)

SecurityConfig์—์„œ permitUrls๋ชฉ๋ก์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ClientSecurityProperties์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ Spring IoC ์ปจํ…Œ์ด๋„ˆ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” Bean์œผ๋กœ ๋“ฑ๋ก๋˜์•ผ ํ•œ๋‹ค. 

SecurityConfig์˜ ์ƒ์„ฑ์ž์—์„œ ClientSecurityProperties๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„ ์˜์กด์„ฑ ์ฃผ์ž…(DI)๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. 'ClientSecurityProperties์— ๋Œ€ํ•œ SecurityConfig์˜ ์˜์กด'

๋”ฐ๋ผ์„œ SecurityConfig์—์„ 

// SecurityConfig

public class SecurityConfig { 

... ์ƒ๋žต, 
    private final ClientSecurityProperties securityProperties; // ์˜์กด์„ฑ ์ฃผ์ž…(DI)

์œ„์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

3๏ธโƒฃ๋™์ ์ธ ๋ชฉ๋ก ์‚ฌ์šฉ

๋ชฉ๋ก์ด ์•„๋‹Œ ๋‹จ์ผ ๊ฐ’(String)์ด๋ผ๋ฉด @Value๋ฅผ ์ด์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ง€๊ธˆ๊ณผ ๊ฐ™์ด(chat, upload, diary....) ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ƒํ™ฉ์ผ ๋• @ConfigurationProperties๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๊ถŒ์žฅ๋œ๋‹ค.

 

๊ฒฐ๋ก : SecurityConfig.java์™€ application.yml์˜ '์ค‘๊ฐ„ ๋‹ค๋ฆฌ' ์—ญํ• 

 

โž•๊ธฐ๋ณธ ์ƒ์„ฑ์ž์™€ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ƒ์„ฑ์ž

๊ธฐ๋ณธ ์ƒ์„ฑ์ž์˜ ํ˜•ํƒœ : public ClientSecurityProperties() {}

  1. ๋ฐ˜๋“œ์‹œ public์ด์–ด์•ผ ํ•œ๋‹ค
  2. ํ˜„์žฌ ์ฝ”๋“œ์—์„œ ์—†๋Š” ์ด์œ : Java Compiler๊ฐ€ ์ž๋™์œผ๋กœ ๊ธฐ๋ณธ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“  ์ƒํƒœ์ด๋‹ค
  3. setter ๋ฐฉ์‹ ๋ฐ”์ธ๋”ฉ์„ ์œ„ํ•ด์„œ๋ผ๋„ @ConfigurationProperties๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

๋งค๊ฐœ ๋ณ€์ˆ˜ ์ƒ์„ฑ์ž์˜ ํ˜•ํƒœ : public SecurityConfig(ClientSecurityProperties securityProperty) { }

  1. ํ˜„์žฌ ์ฝ”๋“œ์—์„  Spring Security ์„ค์ •์—์„œ ๊ฐ€์žฅ ๊ถŒ์žฅ๋˜๋Š” ๋ฐฉ์‹์ธ ์ƒ์„ฑ์ž ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.
// ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์˜ ํ˜•ํƒœ
public ClientSecurityProperties(){}

// ๋งค๊ฐœ๋ณ€์ˆ˜ ์ƒ์„ฑ์ž์˜ ํ˜•ํƒœ
public SecurityConfig(ClientSecurityProperties securityProperty) {}

 

โž•Java Compiler VS JVM

  • Java Compiler : .java ์—์„œ .class๋กœ ๋ณ€ํ™˜, ์ปดํŒŒ์ผ ์‹œ์ ์— ์‹คํ–‰๋จ
  • JVM : .class๋ฅผ ์‹คํ–‰, Run ์‹œ์ ์—์„œ ์‹คํ–‰๋จ

โž• Getter, Setter, this ํ‚ค์›Œ๋“œ

// Getter์˜ ํ˜•ํƒœ
public List<String> getPermitUrls() {
  return permitUrls;
}

// Setter์˜ ํ˜•ํƒœ
public void setPermitUrls() {
  this.permitUrls = permitUrls;
}

๊ณ„์† ๋กฌ๋ณต์“ฐ๋‹ค ์ด๊ฑฐ ๋ณด๋‹ˆ๊นŒ ์ข€ ๋ฐ˜๊ฐ‘๊ณ ... ์˜ค๋žœ๋งŒ์ธ๊ฑฐ ๊ฐ™๋‹ค...

ํ•ญ์‹œ ์žŠ์ง€ ๋ง๊ฒƒ

๊ฐ„๋‹จํ•œ ๋ณต์Šต ์ฐจ์›์—์„œ ์ •๋ฆฌํ–ˆ๋‹ค..

  • Getter, Setter์— ๋Œ€ํ•ด ๋” ์ž์„ธํ•˜๊ฒŒ ์ฝ์„๋ ค๋ฉด ์—ฌ๊ธฐ ํด๋ฆญ
  • โญthis : ํ˜„์žฌ ๊ฐ์ฒด(์ธ์Šคํ„ด์Šค) ์ž์‹ , ์—ฌ๊ธฐ์„  ์ฆ‰ ClientSecurityProperties ๊ทธ ์ž์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ด. ๋”ฐ๋ผ์„œ this.permitUrls๋Š” ClientSecurityProperties์˜ permitUrls๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์œผ๋กœ, ํ˜„์žฌ ๊ฐ์ฒด ํ•„๋“œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

4. SecurityConfig ์ž‘์„ฑ

SecurityConfig์˜ ์—ญํ• ์€ 1๏ธโƒฃ๋ณด์•ˆ ํ•„ํ„ฐ ์—†์ด ์ฒด์ธ ๊ตฌ์„ฑ, 2๏ธโƒฃ์ธ์ฆ ์—†์ด ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ URL ์„ค์ •, 3๏ธโƒฃ๋ชจ๋“  HTTP์š”์ฒญ์— ๋Œ€ํ•œ ๋ณด์•ˆ ๊ฒ€์ฆ ์ˆ˜ํ–‰์ด๋‹ค.

@Configuration
@EnableWebSecurity

public class SecurityConfig {
  private final ClientSecurityProperties securityProperties; // DI์ค€๋น„
  
  public SecurityConfig(ClientSecurityProperties securityProperties) {
    this.securityProperties = securityProperties; // DI
  }
  
  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(auth -> auth
      .requestMatchers(securityProperties.getPermitUrls().toArray(new String[0])).permitAll()
      .anyRequest(). authenticated())
      .csrf(csrf -> csrf.disable())
      .headers(headers -> headers.frameOptions(frameOptions -> frameOptions.disable())
      );
    return http.build();
  }

}
  • @Configuration์€ ์•ž๊ณผ ๊ฐ™๋‹ค. ํ•ด๋‹น JavaํŒŒ์ผ์ด 'Spring ์„ค์ • ํด๋ž˜์Šค'์ž„์„ ์„ ์–ธ
  • @EnableWebSecurity : Spring Security์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๊ณ , ์›น ๋ณด์•ˆ ์„ค์ •์„ ์ด ํด๋ž˜์Šค(SecurityConfig)์—์„œ ์„ค์ •ํ•œ๋‹ค๋Š” ๋œป์˜ ์–ด๋…ธํ…Œ์ด์…˜

์—ฌ๊ธฐ์„œ๋„ ์•„๊นŒ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ this์— ๋Œ€ํ•ด์„œ ๋ณต์Šตํ•  ์ˆ˜ ์žˆ๋‹ค.

 

1๏ธโƒฃ ์˜์กด์„ฑ ์ฃผ์ž…(DI)

  • private final ClientSecurityProperties securityProperties 
    • โญ= SecurityConfig์˜ ํ•„๋“œ๋ถ€ โญ
    • ๊ธฐ์กด์— ์ •์˜ํ–ˆ๋˜ ClientSecurityProperties Bean์„ ์ฃผ์ž…๋ฐ›์„ ํ•„๋“œ ์ค€๋น„
    • Spring Boot๋Š” ์ƒ์„ฑ์ž ์ฃผ์ž… ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, Spring ์ปจํ…Œ์ด๋„ˆ๋Š” ClientSecurityProperties Bean์„ ์ฐพ์•„์„œ SecurityConfig ์ƒ์„ฑ ์‹œ ์ƒ์„ฑ์ž ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ClientSecurityProperties๋ฅผ ์ž๋™์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ธํŒ…
  • public SecurityConfig(ClientSecurityProperties securityProperties){}
    • ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” ์ƒ์„ฑ์ž
    • ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด ClientSecurityProperties๋ฅผ ์ฃผ์ž…๋ฐ›์Œ(DI์‹คํ–‰)
    • ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—†๋‹ค. ex) public SecurityConfig() {}์™€ ๊ฐ™์ด
  • this.securityProperties = securityProperties;
    • ํ—ท๊ฐˆ๋ฆฌ์ง€ ๋ง๊ฒƒ! ์—ฌ๊ธฐ์„œ this๋Š” ClientSecurityProperties๊ฐ€ ์•„๋‹Œ SecurityConfig
    • ๋”ฐ๋ผ์„œ private final ClientSecurityProperties securityProperties๋Š” SecurityConfig์˜ ํ•„๋“œ๋ถ€
    • securityProperties : ClientSecurityProperties์—์„œ ๋ฐ›์€ ๊ฐ’๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋Œ€์ž…ํ•จ

2๏ธโƒฃ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ ์„ค์ •

Spring Security ํ•ต์‹ฌ ๋ณด์•ˆ ์ •์ฑ…์„ ์„ค์ •ํ•˜๋Š” ๊ณณ

  • authorizeHttpRequests : ์ ‘๊ทผ ๊ถŒํ•œ ์„ค์ • ์˜์—ญ
    • authorizeHttpRequests(auth -> auth...) : Http ์š”์ฒญ์— ๋Œ€ํ•œ ๊ฒ€์ฆ ์‹œ์ž‘ ์„ ์–ธ
    • .requestMatchers(...).permitAll() : ClientSecurityProperties์—์„œ ๊ฐ€์ ธ์˜จ URL ๋ชฉ๋ก์— ํ•ด๋‹นํ•˜๋Š” ์š”์ฒญ๋“ค์€ ์ธ์ฆ ์—†์ด ์ ‘๊ทผ์„ ํ—ˆ์šฉ
    • .anyRequest().authenticated() : ์•ž์— ๊ทœ์น™์— ํ•ด๋‹น๋˜์ง€ ์•Š๋Š” ๋ชจ๋“  ์š”์ฒญ๋“ค์€ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋„๋ก ๊ฐ•์ œ (ex. ๋กœ๊ทธ์ธ ํ•„์š” etc)
  • .csrf(csrf -> csrf.disable()) : CSRF ๋ณดํ˜ธ ๊ธฐ๋Šฅ์„ ๋น„ํ™œ์„ฑํ™”
  • .headers(headers -> headers.frameOptions(frameOptions -> frameOptions.disable()) : X-Frame-Options ํ—ค๋” ์„ค์ •์„ ๋น„ํ™œ์„ฑํ™”. ์ฃผ๋กœ iFrame ๋‚ด์—์„œ ํŽ˜์ด์ง€ ๋กœ๋“œ๋ฅผ ํ—ˆ์šฉํ•ด์•ผ ํ•  ๊ฒฝ์šฐ์— ์‚ฌ์šฉ๋จ
  • return http.build() : ์„ค์ • ๋ณด์•ˆ์ด ๋ชจ๋‘ ๊ฐ–์ถฐ์ง„ SecurityFilterChain ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜, Spring Bean์œผ๋กœ ๋“ฑ๋ก. ์‹ค์ œ ์›น ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์œผ๋กœ ์‚ฌ์šฉ

5. ๊ฒฐ๊ณผ

์ž˜ ํ†ต์‹ ํ•ด์„œ API ์—ฐ๊ฒฐ๋˜๋Š”๊ฒƒ ํ™•์ธ!