CSRF (Cross-Site Request Forgery) — это тип атаки, при которой злоумышленник заставляет жертву выполнить нежелательные действия на веб-сайте, где пользователь аутентифицирован. Например, это может быть перевод денег, изменение пароля или отправка сообщения. CSRF-атаки возможны, если веб-приложение не проверяет источник запросов.
Предположим, есть форма перевода денег на сайте банка:
<form action="https://bank.com/transfer" method="POST">
<input type="hidden" name="amount" value="1000">
<input type="hidden" name="toAccount" value="attackerAccount">
<input type="submit" value="Transfer Money">
</form>
Злоумышленник может создать страницу с автоматически отправляемой формой:
<form action="https://bank.com/transfer" method="POST" id="csrfForm">
<input type="hidden" name="amount" value="1000">
<input type="hidden" name="toAccount" value="attackerAccount">
</form>
<script>document.getElementById('csrfForm').submit();</script>
Если пользователь откроет эту страницу, браузер отправит запрос на перевод денег на счет злоумышленника.
CSRF-токен — это уникальное, случайное значение, которое генерируется сервером и добавляется в каждую форму или запрос. Сервер проверяет токен перед выполнением действия.
Пример реализации CSRF-токена в Spring Boot:
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@RestController
public class CsrfController {
@PostMapping("/transfer")
public String transferMoney(@RequestParam String amount,
@RequestParam String toAccount,
HttpServletRequest request) {
// Проверка CSRF-токена
String csrfToken = request.getParameter("csrfToken");
String sessionToken = (String) request.getSession().getAttribute("csrfToken");
if (csrfToken == null || !csrfToken.equals(sessionToken)) {
return "CSRF attack detected!";
}
// Логика перевода денег
return "Money transferred successfully!";
}
}
Атрибут SameSite
для cookies предотвращает отправку cookies в запросах, инициированных с других сайтов. Это эффективно защищает от CSRF-атак.
Пример настройки SameSite в Spring Boot:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
@Configuration
public class CookieConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setSameSite("Strict");
return serializer;
}
}
Сервер может проверять заголовки Origin
или Referer
в запросах, чтобы убедиться, что запрос пришел с ожидаемого домена.
Пример проверки заголовка Origin:
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@RestController
public class CsrfController {
@PostMapping("/transfer")
public String transferMoney(@RequestParam String amount,
@RequestParam String toAccount,
HttpServletRequest request) {
String origin = request.getHeader("Origin");
if (!"https://bank.com".equals(origin)) {
return "CSRF attack detected!";
}
// Логика перевода денег
return "Money transferred successfully!";
}
}
Метод заключается в отправке CSRF-токена как в форме, так и в cookie. Сервер проверяет, что значения токена в форме и cookie совпадают.
Пример реализации:
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
public class CsrfController {
@PostMapping("/transfer")
public String transferMoney(@RequestParam String amount,
@RequestParam String toAccount,
@RequestParam String csrfToken,
HttpServletRequest request,
HttpServletResponse response) {
String cookieToken = request.getCookies()[0].getValue();
if (csrfToken == null || !csrfToken.equals(cookieToken)) {
return "CSRF attack detected!";
}
// Логика перевода денег
return "Money transferred successfully!";
}
}
CAPTCHA может быть использована для подтверждения действий пользователя, что усложняет проведение CSRF-атак.
Пример интеграции CAPTCHA:
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
@RestController
public class CaptchaController {
private final String SECRET_KEY = "your_secret_key";
private final String VERIFY_URL = "https://www.google.com/recaptcha/api/siteverify";
@PostMapping("/transfer")
public String transferMoney(@RequestParam String amount,
@RequestParam String toAccount,
@RequestParam String captchaResponse) {
RestTemplate restTemplate = new RestTemplate();
String url = VERIFY_URL + "?secret=" + SECRET_KEY + "&response=" + captchaResponse;
String response = restTemplate.postForObject(url, null, String.class);
if (!response.contains("\"success\": true")) {
return "CAPTCHA verification failed!";
}
// Логика перевода денег
return "Money transferred successfully!";
}
}
Следование этим рекомендациям поможет вам защитить ваше приложение от CSRF-атак и обеспечить безопасность пользователей.