Почему cookie csrf устанавливается при отправке POST запроса на localhost:8000, но не при отправке POST запроса 127.0.0.1:8000?
Почему куки csrf устанавливается при отправке POST запроса на localhost:8000, но не устанавливается при отправке POST запроса 127.0.0.1:8000? Django жалуется, что CSRF cookie не установлен. (Если предположить, что я открываю фронтенд, используя localhost:3000, то такое же явление происходит при открытии скрипта фронтенда, используя 127.0.0.1:3000, но на этот раз POST запросы проходят только на 127.0.0.1:8000). В общем, меня интересует, как настроить все так, чтобы в дальнейшем иметь возможность обслуживать фронтенд (React в моем случае) и бэкенд (Django) с двух разных доменов. На данный момент у меня нет возможности входа в систему и т.д., поэтому защита CSRF не имеет смысла. Однако меня интересует, почему с текущей конфигурацией я не могу делать кросс-запросы (POST) с CSRF-токеном в заголовке.
Вот мой код:
Frontend:
export async function post_request_to_backend_with_csrf(url : string, data: {[key: string] : string}, headers: AxiosRequestHeaders | undefined = undefined) : Promise<AxiosResponse<any, any>> {
// get csrf token
var csrftoken = getCookie('csrftoken');
if (csrftoken === null) {
await getCSRFToken().then(
(response) => {
csrftoken = getCookie('csrftoken');
}
). catch((e) => console.log(e))
}
var headers_arg : AxiosRequestHeaders = {'X-Requested-With': 'XMLHttpRequest', 'X-CSRFToken': csrftoken!, 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'};
for (let key in headers) {
if (!(key in headers_arg)) {
headers_arg[key] = headers[key];
}
}
return axios.post(
url,
data,
{ //
withCredentials: true, // send cookies, authorization headers or TLS client certificates cross -origin.
headers: headers_arg // contains CSRF cookie among others.
});
}
function getCSRFToken() {
return axios.get(CSRF_URL, {withCredentials: true});
}
Бэкэнд:
# settings.py
# ...
######## CORS SETUP ###########
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = [
# defaults
"accept",
"accept-encoding",
"authorization",
"content-type",
"dnt",
"origin",
"user-agent",
"x-csrftoken",
"x-requested-with",
# added
"X-CSRFTOKEN",
'access-control-allow-origin',
]
CORS_EXPOSE_HEADERS = [] + CORS_ALLOW_HEADERS
CORS_ALLOW_METHODS = [
"DELETE",
"GET",
"OPTIONS",
"PATCH",
"POST",
"PUT",
]
######## END of CORS SETUP ####
######## CSRF SETUP ###########
CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'
CSRF_TRUSTED_ORIGINS=["http://localhost:3000", "http://127.0.0.1:3000"]
####### END CSRF SETUP ########
Подводя итог, я попытался реализовать: https://docs.djangoproject.com/en/4.0/ref/csrf/#:~:text=%3C/script%3E-,Setting%20the%20token%20on%20the%20AJAX%20request,-%C2%B6 но для кросс-оригинальных запросов, где последняя часть не работает.
Более точно изучив настройки браузера, я обнаружил следующие вещи.
Для кросс-оригинального запроса: localhost --> 127.0.0.1, cookie (его можно увидеть, нажав на (i) в Chrome слева от URL) был установлен, но недоступен для JavaScript (не в DevTools > Storage > Cookies). Cookies, которые приходят из другого источника, никогда не могут быть прочитаны/доступны для JavaScript.
Теперь CSRF-токен защищает, гарантируя, что токен и куки совпадают и что только действительное происхождение может получить доступ к токену. Поскольку куки другого происхождения не могут быть прочитаны JavaScript, CSRF-токен должен быть получен непосредственно с сервера, например, с помощью шаблона Django {% csrf_token %}. Здесь политика CORS гарантирует, что ни один злоумышленник не сможет получить CSRF-токен, блокируя запросы злоумышленников, т.е. блокируя все запросы, которые приходят не от валидного фронтенда. Эта политика CORS применяется браузером, поэтому вредоносное приложение все еще может получить CSRF-токен, но поскольку CSRF-атаки могут происходить только в браузере, это не является проблемой.