
https://www.boannews.com/media/view.asp?idx=78058&page=1&kind=1
์ด์ฒ๋ผ ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํํ์ง ์๊ณ ๊ทธ๋๋ก ์ ์ฅํ๋ ํ์๋ ํดํน์ด๋ ๋ด๋ถ ์ ์ถ ์ ์ฌ์ฉ์ ๊ณ์ ํ์ทจ ์ํ์ ๊ทน๋จ์ ์ผ๋ก ๋์ผ ๋ฟ๋ง ์๋๋ผ, ์๋น์ค ์ ๋ขฐ๋์๋ ๋์ดํฌ ์ ์๋ ํ๊ฒฉ์ ์ค ์ ์๋ค.
๋ฐ๋ผ์ ์คํ๋ง ์ํ๋ฆฌํฐ(Spring Security)๋ PasswordEncoder ์ธํฐํ์ด์ค๋ฅผ ํตํด ์์ ํ๊ฒ ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํ ํ ์ ์๋๋ก ์ง์ํ๋ค.

์คํ๋ง ์ํ๋ฆฌํฐ์์ AuthenticationProvider๋ ์ธ์ฆ ๋ก์ง์ ๋ด๋นํ๋ฉฐ, ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ๋น๋ฐ๋ฒํธ(ํ๋ฌธ)์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ ๋น๋ฐ๋ฒํธ(์ํธํ/ํด์๋ ๊ฐ)๋ฅผ ๋น๊ตํด์ผ ํ๋ค. ์ด๋ ๋จ์ ๋ฌธ์์ด ๋น๊ต๊ฐ ์๋๋ผ, ์ ๋ ฅ๋ ๋น๋ฐ๋ฒํธ๋ฅผ ๋์ผํ ๋ฐฉ์์ผ๋ก ์ํธํ(ํด์ฑ)ํ์ฌ ์ ์ฅ๋ ๊ฐ๊ณผ ๋น๊ตํด์ผ ํ๋ฏ๋ก PasswordEncoder๊ฐ ๋ฐ๋์ ํ์ํ๋ค.
์คํ๋ง ์ํ๋ฆฌํฐ
5.x์ด์์์๋PasswordEncoder๊ฐ ๋ฑ๋ก๋์ด ์์ง ์์ผ๋ฉด
There is no PasswordEncoder mapped for the id "null"
์ด๋ผ๋ ๋ฐํ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
์ด์ ์คํ๋ง ์ํ๋ฆฌํฐ ๋ฒ์ (5.0 ๋ฏธ๋ง)์์๋
NoOpPasswordEncoder๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํด ํ๋ฌธ ๋น๋ฐ๋ฒํธ๋ฅผ ๊ทธ๋๋ก ์ฒ๋ฆฌํ๋ค.
DB์ ๋น๋ฐ๋ฒํธ๊ฐ ํ๋ฌธ์ผ๋ก ์ ์ฅ๋์ด ์๊ณ
PasswordEncoder๊ฐ BCrypt ๋ฑ์ผ๋ก ์ค์ ๋์ด ์๋ค๋ฉด, ํ๋ฌธ๊ณผ ์ํธํ๋ ๊ฐ์ ๋น๊ตํ๋ ค๋ค"Encoded password does not look like BCrypt"์ ๊ฐ์ ์์ธ ๋๋ ์ธ์ฆ ์คํจ๊ฐ ๋ฐ์
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
String encode(CharSequence rawPassword) : ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ํ๋ฌธ ๋น๋ฐ๋ฒํธ๋ฅผ ์์ ํ๊ฒ ์ํธํ(ํด์ฑ)ํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฑ์ ์ ์ฅboolean matches(CharSequence rawPassword, String encodedPassword) : ๋ก๊ทธ์ธ ์ ์
๋ ฅํ ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํํ์ฌ, DB์ ์ ์ฅ๋ ์ํธํ๋ ๋น๋ฐ๋ฒํธ์ ์ผ์นํ๋์ง ํ์ธdefault boolean upgradeEncoding(String encodedPassword : ์ ์ฅ๋ ์ํธํ๋ ๋น๋ฐ๋ฒํธ(encodedPassword)๊ฐ ๋ ๊ฐ๋ ฅํ ์ํธํ ๋ฐฉ์์ผ๋ก ๋ค์ ์ํธํ๋์ด์ผ ํ๋์ง ํ๋จํ๋ ์ญํ "์ฌ์ํธํ๊ฐ ํ์ ์๋ค"๊ณ ๊ฐ์ฃผArgon2PasswordEncoder Pbkdf2PasswordEncoder SCryptPasswordEncoderBcryptPasswordEncoder์คํ๋ง ์ํ๋ฆฌํฐ(Spring Security)์์ ์ ๊ณตํ๋ ๋น๋ฐ๋ฒํธ ์ํธํ(ํด์ฑ) ํด๋์ค@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
PasswordEncoder๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด Bean์ผ๋ก ๋ฑ๋กํด์ผํ๋ค.BCryptPasswordEncoder๋ ๋น๋ฐ๋ฒํธ๋ฅผ ๋จ๋ฐฉํฅ ํด์ ์๊ณ ๋ฆฌ์ฆ์ธ BCrypt๋ก ์ํธํํ๋ค.๐ค
๋จ๋ฐฉํฅ ์ํธํ: ์๋ณธ ๋ฉ์์ง๋ฅผ ์๋ฉด ์ํธํ ๋ฉ์์ง๋ฅผ ์ ์ ์์ง๋ง, ์ํธํ ๋ฉ์์ง๋ก๋ ์๋ณธ ๋ฉ์์ง๋ฅผ ๊ตฌํ ์ ์๋ ๊ฒ(๋ณตํธํ ๋ถ๊ฐ)์ด
์๋ฐฉํฅ ์ํธํ: ์ํธํ ๋ฉ์์ง๋ก๋ ์๋ณธ ๋ฉ์์ง๋ฅผ ๊ตฌํ ์ ์๋ ๊ฒ(๋ณตํธํ ๊ฐ๋ฅ)์ด ์๋ฐฉํฅ
๋ง์ฝ DB๊ฐ ์ ์ถ๋๋๋ผ๋, DB ๋ด๋ถ์ ์๋ณธ ๋น๋ฐ๋ฒํธ ๋์ ์ํธํ๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ์ฅํด๋๋ฉด ๋ณตํธํ๊ฐ ๋ถ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ์์ ํ๋ค.
BCrypt๋ ๊ฐ์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํํ๋๋ผ๋ ํด์ ๊ฐ์ ๋งค๋ฒ ๋ค๋ฅธ ๊ฐ์ด ๋์ถ๋๋ค. ->Salt๋๋ฌธ!!
๋ก๊ทธ์ธ์
Rainbow table๊ณต๊ฒฉ์ ์ทจ์ฝํ๋ค.Rainbow table์ ์ ๋ ฅ ๊ฐ๋ฅํ ๋ฌธ์์ด ์กฐํฉ์ ํด์ํจ์์ ๋ฃ์ด์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ํ ์ด๋ธ์ด๋ค. ์ด ํ ์ด๋ธ๋ก ์ผ์ผ์ด ๋์กฐํ์ฌ ๋ธ๋ฃจํธ ํฌ์ค ๋ฐฉ์์ผ๋ก ๊ณต๊ฒฉ์ด ๊ฐ๋ฅ ->ํ๋๋ง ๊ฑธ๋ ค๋ผ->Salt๋ก ํด๊ฒฐ
BCryptPasswordEncoder์์ ๊ฐ๋(strength, log rounds)๋ ํด์ ์ฐ์ฐ์ ๋ฐ๋ณต ํ์๋ฅผ ๊ฒฐ์ ํ๋ฉฐ, ๊ฐ์ด ํด์๋ก ์ํธํ์ ๋๋ ์๊ฐ์ด ๊ธฐํ๊ธ์์ ์ผ๋ก ์ฆ๊ฐํด ๋ณด์์ด ๋์ฑ ๊ฐํํ๋ค.
๊ธฐ๋ณธ๊ฐ์ 10์ด๋ฉฐ 4 ~ 31 ์ฌ์ด์ ๊ฐ์ ์ค์
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(5);
}
}
$2a$10$VZQap7FCOxI7WZpsxBMEHuG2f..VjPk3Vaj5441s.Ud0YrgwCKwh6
$2a$ : BCrypt ์๊ณ ๋ฆฌ์ฆ ๋ฒ์ ์ ๋ณด, $2a$๋ ๊ฐ์ฅ ๋๋ฆฌ ์ฐ์ด๋ ํ์ค ๋ฒ์ 10 : ๋ก๊ทธ๋ผ์ด๋(log rounds) -> ์ด ๊ฐ์ด ์ปค์ง์๋ก ํด์๊ฐ์ ๊ตฌํ๋ ์๋๊ฐ ๋๋ ค์ง๋ค.VZQap7FCOxI7WZpsxBMEHu : 22์๋ฆฌ ์ํธ(salt) -> ์ํธ๋ ํด์๊ฐ๊ณผ ํจ๊ป ์ ์ฅ๋๋ฏ๋ก ๋ณ๋๋ก ๊ด๋ฆฌํ ํ์๊ฐ ์๋ค๊ทธ ๋ค ๋ฌธ์์ด๋ค : ์ํธ์ ๋น๋ฐ๋ฒํธ, ๋ก๊ทธ๋ผ์ด๋(log rounds)๋ฅผ ์กฐํฉํด ์์ฑ๋ ์ค์ ํด์๊ฐ์ํธํํ ๋ ๋งค๋ฒ ๋ค๋ฅธ ์ํธ๋ฅผ ์ฌ์ฉํ์ง๋ง, ๊ฒ์ฆํ ๋๋ ์ด๋ฏธ ๋น๋ฐ๋ฒํธ์ ์ ์ฅ๋ ์ํธ๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ์ ํํ ๊ฒ์ฆ์ด ๊ฐ๋ฅํ๋ค.