Как получить доступ к cookie с CSRF токеном с помощью JavaScript?

У меня возникла следующая проблема: <br/> При попытке обращения к серверу за получением csrf токена, он устанавливается в cookie. Однако я не могу получить к нему доступ из JavaScript, несмотря на то, что параметр httponly=False. <br/> <br/> Вот запрос: <br/> <pre><code class="javascript">export const getCsrf = createAsyncThunk('user/get-csrf', async () =&gt; {
    const response = await axios.get(`${host}/api_users/csrf/`, 
            { withCredentials: true }
        );

    return response.data
})</code></pre> <br/> <br/> А вот ендпоинт: <br/> <pre><code class="django">@api_view(http_method_names=['GET'])
def csrf(request): 
    response = Response({'status': 'ok'})
    response.set_cookie(
        'csrftoken',
        get_token(request),
        samesite='None',
        httponly=False,
        secure=True
    )
    return JsonResponse({'csrftoken': get_token(request)})</code></pre> <br/> <br/> Я подозреваю, что проблема может заключаться в параметре samesite='None', так как при попытке изменить его на 'Lax' возникает следующая ошибка: <br/> <br/> <blockquote><br/>
This attempt to set a cookie via a Set-Cookie header was blocked because it had the "SameSite-Lax" attribute but came<br/>
from a cross-site response which was not the response to a top-level navigation.<br/>
</blockquote>
  • 30 января 2025 г. 23:14
Ответы на вопрос 2
Давайте разберемся с вашей ситуацией по порядку.

1. **Проблема с получением cookie**: Вы правильно заметили, что если cookie имеет атрибут `HttpOnly`, то доступ к нему из JavaScript невозможен. Однако, поскольку вы установили `httponly=False`, то доступ к нему должен быть возможен. Важно отметить, что если cookie установлен с флагом `Secure`, он будет передаваться только по HTTPS соединению. Убедитесь, что ваше приложение работает по HTTPS, иначе cookie не будет доступна.

2. **Параметр SameSite**: Когда вы устанавливаете cookie с `SameSite=None`, он может быть доступен для кросс-доменных запросов, но необходимо, чтобы передавался флаг `Secure`. Если ваш сервер работает по HTTP, браузер может заблокировать эту cookie. 

   Если вы хотите использовать `SameSite=Lax`, то это будет работать в большинстве случаев, но типичный сценарий для этого — это когда вы не делаете кросс-доменные запросы. Чтобы избежать ошибки, рассмотрите возможность корректировать настройки вашего приложения и использовать `SameSite` согласно вашим требованиям.

3. **Проверка доступности cookie**: Чтобы убедиться, что cookie была установлена, вы можете использовать следующее JavaScript:

   ```javascript
   console.log(document.cookie);
   ```

   Это позволит вам увидеть все доступные cookie. Убедитесь, что `csrftoken` присутствует в выводе.

4. **Примеры настройки cookie**: Измените ваш Django код на следующий, чтобы использовать `SameSite='Lax'`, и старайтесь запрашивать CSRF токен только с одного и того же домена (если это возможно):

   ```python
   response.set_cookie(
       'csrftoken',
       get_token(request),
       samesite='Lax',  # или 'None', если используете Secure
       httponly=False,
       secure=True  # Убедитесь, что ваше приложение работает по HTTPS
   )
   ```

5. **Проверка междоменных запросов**: Если ваша клиентская часть и сервер находятся на разных доменах (например, localhost для клиента и другой адрес для сервера), можете попробовать добавить хедеры CORS для разрешения кросс-доменных запросов.

6. **Решение проблем с кросс-доменными запросами**: Если ваш клиент и сервер находятся на разных доменах, убедитесь, что у вас настроены CORS заголовки на сервере, чтобы разрешить запросы:

   ```python
   from corsheaders.defaults import default_methods, default_headers
   from corsheaders.middleware import CorsMiddleware

   CORS_ALLOW_ALL_ORIGINS = True  # Или настройте конкретные домены
   ```

Убедитесь, что вы правильно настроили все параметры, и попробуйте снова получить доступ к куки из JavaScript.
To access the CSRF token from a cookie in JavaScript, ensure the following conditions are met: 

1. Ensure httponly=False
Your CSRF cookie is already set with httponly=False, which means it should be accessible from JavaScript.

2. Check the samesite Attribute
If you’re making requests from a different origin (e.g., frontend on localhost:3000 and backend on localhost:8000), setting samesite='None' is correct, but it requires secure=True, which you have. However, some browsers may block cross-site cookies.

Try switching samesite='Lax' if your frontend and backend share the same domain:
response.set_cookie(
    'csrftoken',
    get_token(request),
    samesite='Lax',  # Change from None to Lax
    httponly=False,
    secure=True
)


3. Read the CSRF Cookie in JavaScript
You can access the CSRF token using document.cookie like this:
function getCsrfToken() {
    const cookies = document.cookie.split('; ');
    for (const cookie of cookies) {
        const [name, value] = cookie.split('=');
        if (name === 'csrftoken') {
            return value;
        }
    }
    return null;
}

const csrfToken = getCsrfToken();
console.log('CSRF Token:', csrfToken);


4. Attach CSRF Token to Requests
axios.defaults.headers.common['X-CSRFToken'] = getCsrfToken();


5. Troubleshooting
Похожие вопросы