๊ฐ์
ํ์ฌ `Access` ํ ํฐ์ `๋ก์ปฌ ์คํ ๋ฆฌ์ง`์, `Refresh` ํ ํฐ์ `์ฟ ํค`์ ์ ์ฅํ๊ณ ์์ต๋๋ค. ์ด ๊ตฌ์กฐ์์ ๋ฐ์ํ ์ ์๋ `XSS` ๋ฐ `CSRF` ๊ณต๊ฒฉ์ ์ํ ํผํด๋ฅผ ์ต์ํํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ๊ณ ๋ฏผํ๊ณ , ์ ์ฉํด ๋ณด์์ต๋๋ค.
์ฐธ๊ณ ) XSS์ CSRF ๊ณต๊ฒฉ
XSS (Cross-Site Scripting) ๊ณต๊ฒฉ
- ์ ์ฑ ์คํฌ๋ฆฝํธ๋ฅผ ์ด์ฉํด ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ํ ํฐ์ ํ์ทจํ๋ ๊ณต๊ฒฉ์ ๋๋ค.
- ์ด๋ฅผ ๋ฐฉ์ดํ๊ธฐ ์ํด `Http-Only` ์ฟ ํค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ํจ๊ณผ์ ์ ๋๋ค.
- Http-Only ์ฟ ํค๋ ์คํฌ๋ฆฝํธ์ ์ ๊ทผ์ ์ฐจ๋จํฉ๋๋ค.
CSRF (Cross-Site Request Forgery) ๊ณต๊ฒฉ
- ๊ณต๊ฒฉ์๊ฐ ์ธ์ฆ๋ ์ฌ์ฉ์๋ฅผ ์ ๋ํ์ฌ ์ฌ์ฉ์๊ฐ ์๋ํ์ง ์์ ์์ฒญ์ ์๋ฒ์ ๋ณด๋ด๋๋ก ๋ง๋๋ ๊ณต๊ฒฉ์ ๋๋ค.
- ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅ๋ ํ ํฐ์ ํด๋ผ์ด์ธํธ ์ธก์์ ๋ช ์์ ์ผ๋ก ์คํฌ๋ฆฝํธ๋ฅผ ํตํด ์ ๊ทผํด์ผ ํ๋ฏ๋ก, ๊ณต๊ฒฉ์๊ฐ ์ด๋ฅผ ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๋ฐ๋ฉด, ์ฟ ํค๋ ๋ธ๋ผ์ฐ์ ์์ ์๋์ผ๋ก ํฌํจ๋๊ธฐ ๋๋ฌธ์, CSRF ๊ณต๊ฒฉ์ ์ฃผ๋ก ์ฟ ํค ๊ธฐ๋ฐ ์ธ์ฆ์ ๋์์ผ๋ก ํฉ๋๋ค.
ํ ํฐ ๊ด๋ฆฌ ๋ฐฉ์
Access ํ ํฐ
- Access ํ ํฐ์ ๋ณดํต ์ค์ํ ๋ก์ง์ ์ฒ๋ฆฌํ๋ ์์ฒญ์ ์ฌ์ฉ๋๋ฏ๋ก CSRF ๊ณต๊ฒฉ์ ์๋์ ์ผ๋ก ์ทจ์ฝํฉ๋๋ค.
- ์ด๋ฅผ ๋ฐฉ์ดํ๊ธฐ ์ํด, Access ํ ํฐ์ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅํ๋ ๊ฒ์ด ์๋์ ์ผ๋ก ์์ ํฉ๋๋ค.
- ๋ง์ฝ XSS ๊ณต๊ฒฉ์ผ๋ก ํ ํฐ์ด ํ์ทจ๋๋๋ผ๋ ์๋ช ์ฃผ๊ธฐ๊ฐ ์งง์ ์ฌ์ฉ ๊ฐ๋ฅ ์๊ฐ์ด ์ ํ์ ์ด๋ฏ๋ก, ์๋์ ์ผ๋ก ์ํ์ด ์ ์ต๋๋ค.
Refresh ํ ํฐ
- Refresh ํ ํฐ์ ์๋ช ์ฃผ๊ธฐ๊ฐ ๊ธธ์ด ์ง์ ์ ์ธ ํ์ทจ์ ๋์ฑ ์ทจ์ฝํฉ๋๋ค.
- ๋ฐ๋ผ์ Http-Only ์ฟ ํค์ ์ ์ฅํ์ฌ XSS ๊ณต๊ฒฉ์ ์ฐจ๋จํฉ๋๋ค.
public Cookie createRefreshTokenCookie(String refreshToken) {
Cookie refreshTokenCookie = new Cookie(REFRESH_TOKEN_COOKIE_NAME, refreshToken);
refreshTokenCookie.setHttpOnly(true);
refreshTokenCookie.setSecure(true);
refreshTokenCookie.setPath("/");
refreshTokenCookie.setMaxAge(REFRESH_TOKEN_COOKIE_EXPIRATION_TIME);
return refreshTokenCookie;
}
ํ์ง๋ง CSRF ๊ณต๊ฒฉ์ ๋ํ ๊ณ ๋ ค๋ ํ์ํ๊ธฐ ๋๋ฌธ์, ์ด์ ๋ํ ๋์ ๋ฐฉ์๋ ๊ณ ๋ฏผํด์ผ ํฉ๋๋ค.
Refresh ํ ํฐ CSRF ๊ณต๊ฒฉ ๋์ ๋ฐฉ์
- `Referer` ํค๋ ๊ฒ์ฆ์ ํตํ ๋๋ฉ์ธ ์ผ์น ์ฌ๋ถ ํ์ธ (โ)
- Referer ํค๋๋ฅผ ์ฌ์ฉํด ์์ฒญ ์ถ์ฒ๋ฅผ ํ์ธํ๋ ๋ฐฉ๋ฒ์ ํด๋น ํค๋๊ฐ ํญ์ ์กด์ฌํ๋ค๋ ๋ณด์ฅ์ด ์๋ค๋ ์ ์์ ๊ฒ์ฆ ๋ฐฉ๋ฒ์ผ๋ก ์ ํฉํ์ง ์์ต๋๋ค.
- `CSRF Random UUID`๋ฅผ ํ์ฉํ ํค๋ ๊ฒ์ฆ (โญ)
- Refresh ํ ํฐ์ด ํ์ํ ์์ฒญ๋ง๋ค ํด๋ผ์ด์ธํธ๋ ๊ณ ์ ํ CSRF UUID๋ฅผ ํค๋์ ํฌํจํด ๋ณด๋ ๋๋ค.
- ์๋ฒ๋ ์์ฒญ์ ์ฒ๋ฆฌํ๊ธฐ ์ ์ ํด๋น CSRF UUID๊ฐ ์ฌ๋ฐ๋ฅธ์ง ๊ฒ์ฆํ์ฌ CSRF ๊ณต๊ฒฉ ๊ฐ๋ฅ์ฑ์ ์ค์ ๋๋ค.
- ์ด ๋ฐฉ๋ฒ์ ๊ฐ๋จํ๊ฒ CSRF ๊ณต๊ฒฉ์ ํผํด๋ฅผ ์ต์ํํ๋ฉด์๋ ์ถ๊ฐ์ ์ธ ๋ณต์ก์ฑ์ ์ค์ผ ์ ์์ต๋๋ค.
๊ตฌํ
- `yml` ํ์ผ์์ CSRF UUID ๊ฐ์ ๊ด๋ฆฌ
spring:
csrf:
protection:
uuid: ${CSRF_PROTECTION_UUID}
- CSRF UUID ๊ฒ์ฆ ๋ก์ง
@Value("${spring.csrf.protection.uuid}")
private String csrfProtectionUuid;
public void verifyCsrfProtectionUuid(String csrfProtectionUuid) {
if (!this.csrfProtectionUuid.equals(csrfProtectionUuid)) {
throw new ApiException(INVALID_CSRF_PROTECTION_UUID);
}
}
๊ฒฐ๊ณผ
Access ํ ํฐ์ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ๊ด๋ฆฌํ์ฌ CSRF ๊ณต๊ฒฉ ์ํ์ ์ค์๊ณ , Refresh ํ ํฐ์ Http-Only ์ฟ ํค๋ฅผ ์ฌ์ฉํด XSS ๊ณต๊ฒฉ์ ๋ฐฉ์ดํ๋๋ก ํ์ต๋๋ค. ๋ํ Refresh ํ ํฐ์ด ํ์ํ ์์ฒญ์๋ CSRF Random UUID๋ฅผ ์ฌ์ฉํ์ฌ CSRF ๊ณต๊ฒฉ์ ํผํด๋ฅผ ์ต์ํํ ์ ์๋๋ก ์ค์ ํ์ต๋๋ค.
'ํ๋ก์ ํธ > NolGoat' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์์ ๋ก๊ทธ์ธ ํ์ ํํด ๊ตฌํ (0) | 2024.12.01 |
---|---|
ํจ์จ์ ์ธ ํ ํฐ ๊ด๋ฆฌ๋ฅผ ์ํ Redis ๋์ (1) | 2024.11.29 |
์ธ์ฆ์ด ํ์ํ URL ๊ณตํต ๊ด๋ฆฌ (0) | 2024.11.27 |
Spring Security ์ธ์ฆ ํํฐ ์์ธ ์ฒ๋ฆฌํ๊ธฐ (0) | 2024.11.27 |
์กฐํ ๋ฐฉ์ ๊ฐ์ ๋ฐ ์ธ๋ฑ์ค ์์ (0) | 2024.11.26 |