์ผ๋ง ์ ํ์๊ณผ ๋ณด์ ๊ด๋ จ ์ด์ผ๊ธฐ๋ฅผ ๋๋๋ค๊ฐ CSRF(Cross-Site Request Forgery, ํฌ๋ก์ค ์ฌ์ดํธ ์์ฒญ ์์กฐ) ๊ณต๊ฒฉ์ ๋ํ ํฅ๋ฏธ๋ก์ด ์ฌ๋ก๋ฅผ ๋ค์์ต๋๋ค. ํนํ, ์ด๋ฉ์ผ์ ์ด์ฉํ CSRF ๊ณต๊ฒฉ์ด ์ผ๋ง๋ ์ํ์ ์ธ์ง ์๊ฒ ๋์์ฃ .
"์ฌ์ฉ์๊ฐ ์ด๋ฉ์ผ๋ก ๋ฐ์ '๊ธด๊ธ ๊ณ์ ์ ๋ฐ์ดํธ ํ์!'๋ผ๋ ๋งํฌ๋ฅผ ํด๋ฆญํ๋. ๊ทธ๋ฐ๋ฐ ๊ทธ ์๊ฐ ๋น๋ฐ๋ฒํธ๊ฐ ๋ณ๊ฒฝ๋์๊ณ , ๋ณธ์ธ์ ์๋ฌด ์กฐ์๋ ์ ํ๋ค๊ณ ํ๋๋ผ."
์ด ๋ง์ ๋ฃ๊ณ ์ ๋ '์ด๊ฒ ๊ฐ๋ฅํด?' ์ถ์๋๋ฐ, ์๊ณ ๋ณด๋ CSRF ๊ณต๊ฒฉ์ด ๋ฑ ์ด๋ฐ ๋ฐฉ์์ด๋๊ตฐ์. ์ฌ์ค ์ด ๊ณต๊ฒฉ์ ์ค๋์ ๋ถํฐ ์๋ ค์ง ์ ๋ช ํ ๊ณต๊ฒฉ์ด์ง๋ง, ์๊ฐํด๋ณด๋ฉด ์ ๋ง ๋๋ํ ๋ฐฉ๋ฒ์ด๋ผ๋ ์๊ฐ์ด ๋ค์์ต๋๋ค. ์ฌ์ฉ์์ ์ ๋ขฐ๋ฅผ ์ด์ฉํด ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์์ฒญ์ ๋ณด๋ด๋๋ก ์ค๊ณ๋๋ค๋ ์ ์ด ์ฐธ ๊ต๋ฌํ์ฃ .
์ค๋์ CSRF๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ๋ง๋ ๋ฐฉ๋ฒ๊น์ง ์ ๋ฆฌํด ๋ณด๊ฒ ์ต๋๋ค. ๐
CSRF ๊ณต๊ฒฉ์ ์ฌ์ฉ์๊ฐ ์๋ํ์ง ์์ ์์ฒญ์ ํน์ ์น์ฌ์ดํธ์ ๋ณด๋ด๋๋ก ์ ๋ํ๋ ๊ณต๊ฒฉ ๋ฐฉ์์ ๋๋ค. ๋ณดํต ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ๋ ์ํ์์ ์ ์ฑ ์ฌ์ดํธ๋ฅผ ๋ฐฉ๋ฌธํ๋ฉด, ๊ณต๊ฒฉ์๊ฐ ๋ชฐ๋ ์ฌ์ฉ์ ๊ณ์ ์ผ๋ก ์กฐ์๋ ์์ฒญ์ ๋ณด๋ด๋ ๋ฐฉ์์ผ๋ก ์ด๋ฃจ์ด์ง๋๋ค.
google.com
์ ๋ก๊ทธ์ธํ ์ํ์ฌ์ฉ์๊ฐ maeil-mail.com
์ ๋ก๊ทธ์ธํ๋ฉด, ์๋ฒ๋ ์ธ์
์ฟ ํค(Session Cookie)๋ฅผ ์ด์ฉํด ์ฌ์ฉ์๋ฅผ ์ธ์ฆํฉ๋๋ค.
๊ณต๊ฒฉ์๋ ์ฌ์ฉ์๋ฅผ ์ ์ฑ ์ฌ์ดํธ๋ก ์ ๋ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, "๊ธด๊ธ: ๊ทํ์ ๊ณ์ ์ด ํดํน ์ํ์ ์ฒํด ์์ต๋๋ค! ์ฆ์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ณ๊ฒฝํ์ธ์."๋ผ๋ ์ด๋ฉ์ผ์ ๋ณด๋ ๋๋ค. ์ฌ์ฉ์๊ฐ ์ด๋ฉ์ผ ๋ด ๋งํฌ๋ฅผ ํด๋ฆญํ๋ฉด, ์ ์ฑ ์ฌ์ดํธ๋ก ์ด๋ํ๊ฒ ๋๊ณ ๊ทธ ์๊ฐ CSRF ๊ณต๊ฒฉ์ด ์์๋ฉ๋๋ค.
์ ์ฑ ์ฌ์ดํธ์๋ ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๊ฐ ํฌํจ๋์ด ์์ ์ ์์ต๋๋ค:
<img src="https://google.com/member/changePassword?newValue=Hacked123" />
์ฌ์ฉ์๊ฐ ์ด ํ์ด์ง๋ฅผ ๋ฐฉ๋ฌธํ๋ ์๊ฐ, ๋ธ๋ผ์ฐ์ ๋ ์๋์ผ๋ก ์ด URL์ ์์ฒญํ๊ฒ ๋ฉ๋๋ค.
๋ธ๋ผ์ฐ์ ๋ ์์ฒญ์ ๋ณด๋ผ ๋ ์ธ์ ์ฟ ํค๋ฅผ ์๋์ผ๋ก ํฌํจํ๋ฏ๋ก, ์๋ฒ๋ "์ด ์์ฒญ์ด ์ ์์ ์ธ ์ฌ์ฉ์ ์์ฒญ์ด๊ตฌ๋"๋ผ๊ณ ์ฐฉ๊ฐํ๊ฒ ๋ฉ๋๋ค.
โ
๊ฒฐ๊ณผ: ํผํด์์ ๋น๋ฐ๋ฒํธ๊ฐ ์๋์ผ๋ก  Hacked123
์ผ๋ก ๋ณ๊ฒฝ๋จ ๐ฑ
์ด์ ์ด ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ๋ง์ ์ ์์์ง ์ดํด๋ณผ๊น์?
์๋ฒ๊ฐ ๋ชจ๋ ์์ฒญ์ ๋ํด CSRF ํ ํฐ์ ํฌํจํ๋๋ก ๊ฐ์ ํ๋ฉด ๊ณต๊ฒฉ์๋ ์ด๋ฅผ ์ฐํํ๊ธฐ ์ด๋ ค์์ง๋๋ค.
โ CSRF ํ ํฐ ์ ์ฉ ๋ฐฉ์:
๐ CSRF ํ ํฐ์ ํ์ฉํ HTML ์์
<form action="/update-profile" method="POST">
<input type="hidden" name="csrf_token" value="randomToken1234" />
<input type="text" name="username" />
<button type="submit">Update</button>
</form>
๐ ์๋ฒ์์ CSRF ํ ํฐ ๊ฒ์ฆ (Java Spring ์์ )
@PostMapping("/update-profile")
public ResponseEntity<?> updateProfile(@RequestParam String username,
@RequestParam String csrfToken,
HttpSession session) {
String sessionToken = (String) session.getAttribute("csrf_token");
if (!csrfToken.equals(sessionToken)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Invalid CSRF Token");
}
// ์ ์ ์ฒ๋ฆฌ
return ResponseEntity.ok("Profile updated");
}
์ต๊ทผ ๋ธ๋ผ์ฐ์ ์์๋ ์ฟ ํค์ SameSite ์์ฑ์ ์ด์ฉํด CSRF ๊ณต๊ฒฉ์ ๋ง์ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค. ์ด๋ฅผ ์ค์ ํ๋ฉด ํฌ๋ก์ค ์ฌ์ดํธ ์์ฒญ์์๋ ์ฟ ํค๊ฐ ์ ์ก๋์ง ์๋๋ก ์ ํํ ์ ์์ต๋๋ค.
๐ SameSite ์ค์ ์์ (Spring Boot)
Cookie sessionCookie = new Cookie("SESSION_ID", sessionId);
sessionCookie.setHttpOnly(true);
sessionCookie.setSecure(true);
sessionCookie.setPath("/");
sessionCookie.setAttribute("SameSite", "Strict");
โ Strict
: ํฌ๋ก์ค ์ฌ์ดํธ ์์ฒญ์์๋ ์ฟ ํค๊ฐ ์ ๋ ์ ์ก๋์ง ์์ (๊ฐ์ฅ ์์ !)
โ Lax
: ํฌ๋ก์ค ์ฌ์ดํธ ์์ฒญ ์ค GET ์์ฒญ์์๋ ์ฟ ํค๊ฐ ์ ์ก๋จ (๋ณดํต ๊ธฐ๋ณธ๊ฐ)
โ None
: ํฌ๋ก์ค ์ฌ์ดํธ์์๋ ์ฟ ํค ์ ์ก ํ์ฉ (๋ณด์ ์ทจ์ฝ!)
์๋ฒ๊ฐ ์์ฒญ์ ๋ฐ์ ๋ Referer ํค๋๋ฅผ ํ์ธํ์ฌ ์ ๋ขฐํ ์ ์๋ ์ถ์ฒ์์ ์๋์ง ๊ฒ์ฌํ ์๋ ์์ต๋๋ค. ํ์ง๋ง ์ด ๋ฐฉ๋ฒ์ ํค๋ ์กฐ์์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ๋จ๋ ์ผ๋ก ์ฌ์ฉํ๊ธฐ์ ๋ถ์กฑํ ์ ์์ต๋๋ค.
๐ Referer ๊ฒ์ฆ ์์
String referer = request.getHeader("Referer");
if (referer == null || !referer.startsWith("https://maeil-mail.com")) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Invalid Referer");
}
CORS(Cross-Origin Resource Sharing) ์ ์ฑ ์ ์ ์ ํ ์ค์ ํ๋ฉด ์ธ๋ถ ์ฌ์ดํธ์์ ๋ด๋ถ API๋ฅผ ํธ์ถํ์ง ๋ชปํ๋๋ก ์ ํํ ์ ์์ต๋๋ค.
๐ Spring Boot์์ CORS ์ค์ ํ๊ธฐ
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("https://maeil-mail.com");
}
};
}
}
CSRF๋ ๋จ์ํ์ง๋ง ๋ฌด์ญ๊ฒ ์น๋ช ์ ์ธ ๊ณต๊ฒฉ์ด ๋ ์ ์์ต๋๋ค. ํ์ง๋ง ์ ์ ํ ๋ฐฉ์ด ๊ธฐ๋ฒ์ ์ฌ์ฉํ๋ฉด ์ด๋ฅผ ์ถฉ๋ถํ ๋ง์ ์ ์์ต๋๋ค. ์ค์ํ ๊ฑด, ๋ค์ํ ๋ณด์ ๋ฐฉ๋ฒ์ ์กฐํฉํด์ ์ฌ์ฉํ๋ ๊ฒ!
โ CSRF ํ ํฐ์ ํ์ฉํด ์์ฒญ์ ์ ๋น์ฑ์ ํ์ธํ์.
โ SameSite ์ฟ ํค ์์ฑ์ ์ค์ ํด ํฌ๋ก์ค ์ฌ์ดํธ ์ฟ ํค ์ ์ก์ ๋ง์.
โ Referer ๊ฒ์ฆ๊ณผ CORS ์ ์ฑ
์ ๊ฐํํด ๋ถํ์ํ ์์ฒญ์ ์ฐจ๋จํ์.
์ด์ CSRF์ ๋ํด ์กฐ๊ธ ๋ ๋ช ํํ ์ดํดํ์ จ์๊น์? ๋ณด์์ ํ์๊ฐ ๋ฐฉ์ฌํ๋ฉด ํฐ ํผํด๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ๋ฏธ๋ฆฌ ๋๋นํด์ ์์ ํ ์์คํ ์ ๋ง๋ค์ด ๊ฐ์๋ค! ๐ฅ