SpringBoot Security

์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š”๋Œ€๋กœ ์œ ์—ฐํ•˜๊ฒŒ ์ปค์Šคํ…€ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค!

์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” pom.xml์—์„œ spring-boot-starter-security ๋ผ๋Š” ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ค˜์•ผํ•œ๋‹ค

  • AuthenticationManager bean์„ ๋“ฑ๋กํ•ด์ค€๋‹ค. ๊ทธ๋Ÿฌ๋ฉด default๋กœ ๋ฉ”๋ชจ๋ฆฌ์— ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๋ฅผ ๋“ฑ๋ก์‹œ์ผœ์ค€๋‹ค(user๋ผ๋Š” ์ด๋ฆ„, pw๋Š” ์ฝ˜์†”์ฐฝ์— ๋œจ๊ฒŒ ๋œ๋‹ค)

  • static resource์€ ์ž๋™์œผ๋กœ ๋ฌด์‹œํ•œ๋‹ค = ๋ณด์•ˆ์ด ํ•„์š” ์—†๋‹ค

  • ๋‹ค์–‘ํ•œ ํŠน์ง•๋“ค์„ ํ™œ์„ฑํ™”์‹œ์ผœ์ค€๋‹ค. - XSS, CSRF ๋“ฑ๋“ฑ

์ €๋ ‡๊ฒŒ pom.xml์— ์ถ”๊ฐ€๋งŒ ํ•ด์ค˜๋„ ์ž๋™์œผ๋กœ ์ธ์ฆ์ ˆ์ฐจ๋ฅผ ๋ฐŸ์•„์•ผ๋งŒ ์›นํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฐ”๋€Œ๊ฒŒ๋œ๋‹ค โ‡’ default๋กœ ๋งŒ๋“ค์–ด์ง„ user/์ฝ˜์†”์—์žˆ๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ ์ด๊ฑธ ๊ฐ€์ง€๊ณ  ๋กœ๊ทธ์ธ์„ ํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ ์ ‘์†ํ•˜๋Š”๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค

๋งŒ์•ฝ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด application.properties์—์„œ

spring.security.user.name = ์‚ฌ์šฉ์ž์ด๋ฆ„

spring.security.user.password = ์‚ฌ์šฉ์ž๋น„๋ฐ€๋ฒˆํ˜ธ

spring.security.user.roles = USER, ADMIN

  • ์ด๊ฑฐ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” ๊ตณ์ด ROLE_USER์ด๋ ‡๊ฒŒ ์•ˆํ•ด๋„ ๊ดœ์ฐฎ์€๊ฒŒ ์–ด์งœํ”ผ ์ž๋™์ ์œผ๋กœ ์•ž์— ROLE_ ์ด ๋ถ™๊ฒŒ ๋˜์–ด์žˆ๋‹ค!

ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ์„ค์ •๋“ค์€ ๋”ฐ๋กœ db์— ์„ค์ •ํ•ด์ฃผ์ง€ ์•Š์•˜์„๊ฒฝ์šฐ์— ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์ค€ ๊ฒฝ์šฐ์ด๋‹ค

WebMvcConfigure๋ผ๋Š” interface๋ฅผ implementsํ•œ WebConfig๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ , addViewControllers์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•ด์ค˜์•ผํ•œ๋‹ค. ์•ˆ์—๋Š” ViewControllerRegistry registry.addViewController("/").setViewName("home");

Spring Security with thymeleaf

pox.xml์— thymleaf-extras-springsecurity5 ์ถ”๊ฐ€!

์ด๋ ‡๊ฒŒ ํ•ด์ฃผ๋ฉด ์ผ๋ฐ˜ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ RequestMapping("/")์—๋‹ค๊ฐ€ return "home"ํ•˜๋Š” ํ•จ์ˆ˜์™€ ๊ฐ™์€ ์—ญํ• ์„ ํ•ด์ค€๋‹ค = ์ฝ”๋“œ๊ฐ€ ์ค„์–ด๋“ ๋‹ค!

SpringSecurityDialect์„ bean์œผ๋กœ ๋“ฑ๋ก์‹œ์ผœ์ค˜์•ผํ•จ

  • SpringSecurityDialect๋ž€? thymeleaf์˜ extra module์ด๊ณ , Spring MVC์™€ thymeleaf์„ ํ†ตํ•ฉํ•ด์ฃผ๋Š”์—ญํ• ์„ ํ•œ๋‹ค.

  • thymeleaf์—์„œ ๊ถŒํ•œ์ด ์žˆ์„๋•Œ๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์€

    • sec:authorize = "hasRole('USER')" : ๊ถŒํ•œ์ด ํ†ต๊ณผ๋˜๋ฉด ์ถœ๋ ฅํ•ด์ฃผ๋Š”

    • sec:authentication="์ด๋ฆ„์ด๋‚˜ ๊ถŒํ•œ" : ์ด๋ฆ„์ด๋‚˜ ๊ถŒํ•œ์„ ์ถœ๋ ฅํ•ด์ฃผ๋Š”

Configure Spring Security

  1. Role-based access control using a database

  2. UserDetailsService to get UserDetails from database โ†’ loadUserByUsername()์„ ํ†ตํ•ด์„œ service์— ์žˆ๋Š” ๊ฐ’๋“ค์„ UserDetails์—๋‹ค๊ฐ€ ๋„ฃ์–ด์ค€๋‹ค!

  3. Customized Spring Security Configuration

pom.xml์—๋‹ค๊ฐ€ spring-boot-starter-data-jpa์„ ๋„ฃ์–ด์ฃผ๊ณ , mysql-connector-java ์„ ๋„ฃ์–ด์ค˜์•ผํ•จ

application.properties์—๋‹ค๊ฐ€ DataSource์— ๋Œ€ํ•œ ์„ธํŒ…์„ ํ•ด์ฃผ๊ณ , JPA์— ๋Œ€ํ•œ ์„ธํŒ…์„ ํ•ด์ฃผ๊ณ , ๋กœ๊น…๋„ ํ•ด์ฃผ๊ณ 

UserDetailsService

  1. ์‚ฌ์šฉ์ž์˜ request๊ฐ€ ์˜ค๊ฒŒ๋˜๋ฉด AuthenticationFilter๋ฅผ ๊ฑฐ์นœ๋‹ค

  2. AuthenticationFilter๋ฅผ ๊ฑฐ์น˜๋ฉด์„œ ์ƒ๊ธด ํ† ํฐ์„ AuthenticationManager์—๊ฒŒ ๊ฑด๋‚ด์ฃผ๊ณ 

  3. AuthenticationManager๋Š” AuthenticationProvider(db์™€ ์—ฐ๊ด€๋˜์–ด์žˆ๋Š”)์—๊ฒŒ ๊ฑด๋‚ด๊ฒŒ๋œ๋‹ค.

  4. AuthenticationProvider๋Š” PasswordEncoder์™€ UserDetailsService์™€ ์—ฐ๊ด€์ด ๋˜์–ด์žˆ๋‹ค.

    • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ–ˆ์„๋•Œ PasswordEncoder๋ฅผ ๊ฑฐ์น˜๋ฉด, ํ•ด์‰ฌ๋œ ๊ฐ’์„ ๋‚˜์˜ค๊ฒŒ๋œ๋‹ค

      • ์—ฌ๊ธฐ์„œ PasswordEncoder๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋ก์„ ํ•ด์ฃผ๊ณ , ๊ทธ ์•ˆ์—์„œ BCryptPasswordEncoder()์„ ์‚ฌ์šฉํ•œ๋‹ค! โ‡’ ๋ฐ‘์— Spring Security Configuration ์„ค์ •์‹œ

    • UserDetailService์—๋Š” loadUserByUserName()์ด ์žˆ์–ด์„œ loadUserByUserName()์ด DB๋ฅผ ๊ฑฐ์ณ์„œ UserDetails๋ฅผ ๊ฐ€์ง€๊ณ  ์˜จ๋‹ค

  • AuthenticationProvider๊ฐ€ UserDetailService๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ณ , UserDetailsService๊ฐ€ loadUserByUserName()์„ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ด์˜จ๋‹ค.

  • ์—ฌ๊ธฐ์„œ UserDetailService๋ฅผ ๋งˆ์Œ๋Œ€๋กœ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆํ•ด์„œ ํ™œ์šฉํ•˜๋ฉด ๋œ๋‹ค!

Spring Security Configuration

@Configuration, @EnableWebSecurity์ด ๋“ค์–ด๊ฐ€๊ณ 

WebSecurityConfigurerAdapter๋ฅผ ์ƒ์†๋ฐ›๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋‹ค.

๋งŒ๋“  ํด๋ž˜์Šค๋Š” Spring Security์— ๊ด€ํ•œ ์„ค์ •๋“ค์ด ๋“ค์–ด๊ฐ€๋Š” ํด๋ž˜์Šค์ด๋‹ค

์ „์— ๋งŒ๋“ค์—ˆ๋˜ ์ปค์Šคํ…€ UserDetailsService๋ฅผ @Autowired๋กœ ๊ฐ€์ ธ์™€์ฃผ๊ณ , PasswordEncoder(BCryptPasswordEncoder)์„ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด์ฃผ๊ณ ,

configureGlobal(AuthenticationManagerBuilder auth)๋กœ ์œ„์˜ UserDetailsService์™€ PasswordEncoder๋ฅผ ๋“ฑ๋กํ•ด์ค€๋‹ค

BCryptPasswordEncoder

random number์ธ salt์„ ์ด์šฉํ•ด์„œ hash password์„ ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค.

$๊ธฐ์ค€์œผ๋กœ ๋‚˜๋ˆ„๊ณ 

2a : BCrypt ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฒ„์ „

10 : ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ฐ•๋„

16๊ธ€์ž : ๋žœ๋ค์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ 16it์˜ salt๋ฒˆํ˜ธ

๋‚จ์€๊ฒƒ : plain text(31๊ธ€์ž)

plaintext๋Š” PasswordEncoder encoder.encode("์›ํ•˜๋Š”๋ฌธ์ž")

์ด๋ ‡๊ฒŒ ๋„ฃ์–ด์„œ ๋งŒ๋“œ๋Ÿฌ๋ƒ„

Other Authorization

configure๋ผ๋Š” ํด๋ž˜์Šค์•ˆ์— ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ HttpSecurity http๋กœ ์„ ์–ธํ•˜๊ณ 

  • http.authorizeRequests()

    • .antMatchers("url").permitAll()

    • .antMatchers("url").hasRole("ROLE")

    • .anyRequest().authenticated()

    • .and()๋กœ ๋‹ค์Œ๊ป„๋กœ ์ด์–ด์คŒ

  • http.formLogin()

    • .loginPage("")

    • .defaultSuccessUrl("")

    • .failureUrl("")

    • .permitAll()

    • .and()๋กœ ๋‹ค์Œ๊ป„๋กœ ์ด์–ด์คŒ

  • logout()

    • logoutRequestMatcher()

    • .logoutSuccessUrl()

    • .permitAll()

    • .and()

Create View Thymeleaf

sec:authorize = "isAuthenticated()"

  • ๋งŒ์•ฝ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผ์‹œ, ํ‘œ์‹œํ•ด์คŒ

sec:authorize = "isAnonymous()"

  • ์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผ์‹œ ํ‘œ์‹œ

sec:authorize = "hasRole('ROLE_USER')"

  • ROLE_USER๋ผ๋Š” ๊ถŒํ•œ์„ ๊ฐ€์ง„ ์‚ฌ๋žŒ์—๊ฒŒ ํ‘œ์‹œ

CSRF

CSRF์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ธฐ๋ณธ์œผ๋กœ enable()๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งŒ์•ฝ์— ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด์„œ ์—ด์–ด๋ณด๊ณ ์‹ถ๋‹ค๋ฉด HttpSecurity http.csrf().disable(); ์„ ํ†ตํ•ด์„œ ์—ด์ˆ˜ ์ž‡์Œ

CSRF token์„ request์‹œ ํ•จ๊ป˜ ๋ณด๋‚ด์„œ ์•…์˜์ ์ธ ๊ณต๊ฒฉ์ด ์•„๋‹˜์„ ์•Œ๋ ค์•ผํ•˜๋Š”๋ฐ, ์›๋ž˜ ์ž๋™์œผ๋กœ formํƒœ๊ทธ์— ๋“ค์–ด๊ฐ€์žˆ๊ฒŒ๋œ๋‹ค

SignUp Page์„ ๋งŒ๋“ค์–ด๋ณด์ž

๋งŒ๋“ค์–ด์•ผํ•˜๋Š” ๊ฒƒ๋“ค

  • RegistrationService Interface

  • RegistrationServiceImpl Class

  • RegistrationController Class

  • Signup.html

Last updated

Was this helpful?