3

I am working on ReactJS project as frontend and Django as backend and having trouble with CSRF protection!

I am using Django CORS headers and I have done all set up correctly. It works as long as I have localhost to access both front and back ends. My frontend is running on localhost:3006 and backend us running on localhost:8899 port. So frontend is setting csrftoken cookie and sending it with post request.

I am using axios.create() with withCredentials = true and it works fine. Now when my co-worker is running same frontend code from his system, trying to connect to backend that is running on my machine, he is getting 403 csrf cookie not found! At this time, he is running his frontend on localhost:3006, his own localhost and connecting to backend of my-ip:8899. So I believe that we would have this problem too on production when we will have www.example.com serving frontend and api.example.com serving backend as cookies of frontend host wont get sent to api host!

My cors header settings in django,

# Origin white list
CORS_ORIGIN_WHITELIST = [
    'http://localhost',
    'http://127.0.0.1',
    'http://192.168.1.165',
    'http://192.168.1.165:3006',
]

CORS_EXPOSE_HEADERS = (
    'Access-Control-Allow-Origin: *',
)

# Allowed methods
CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
)

# Allowed headers
CORS_ALLOW_HEADERS = (
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'X-tz',
    'x-tz',
    'x-requested-with',
)

# # CSRF COOKIE NAME
CSRF_COOKIE_NAME = "csrftoken"

# To allow default credentials
CORS_ALLOW_CREDENTIALS = True

CORS_ORIGIN_ALLOW_ALL = True

and my Axios create code is,

let tz = "UTC";

try {
    tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
} catch (e) {
    consoleError(e);
}

const API = axios.create({
    baseURL: process.env.REACT_APP_API_HOST,
    timeout: 30000,
    withCredentials: true,
    xsrfCookieName: CSRF_COOKIE_NAME,
    xsrfHeaderName: "X-CSRFToken",
    headers: {'X-tz': tz}
});

So as I said, if I am connecting from my machine to my machine using localhost/IP and ports, it works but when my co-worker is trying to connect from his localhost/IP frontend to my ip-backend it doesn't allow him to make POST request without CSRF cookie! I don't want to bypass Django security of CSRF with decorator. So can anyone tell me what am I doing wrong here?

3
  • Set CSRF_COOKIE_DOMAIN to your eTLD+1 domain, so that the cookie is also sent to subdomains. By default the csrf cookie will have just your www.domain.com, but if you set it to domain.com, your axios request will pick it up and send it to api.domain.com. Commented Aug 29, 2019 at 17:14
  • Just to explain: CSRF works by matching the token in the cookie to the token in the X-CSRFToken header (or in the form data). Your axios request must sent both. Since no one but your website can set the cookies for your domain and a browser will never send a cookie cross-domain, this works. Commented Aug 29, 2019 at 17:29
  • Good question by the way, your problem was well explained. Deserves upvotes. Commented Aug 29, 2019 at 17:50

1 Answer 1

3

CSRF works by matching the token in the cookie to the token in the X-CSRFToken header (or in the form data). Your axios request must sent both.

It's sending the token in the X-CSRFToken. But it's not sending the cookie to api.yourhost.com because the cookie was set for the domain www.yourhost.com. That's the default in Django.

Change CSRF_COOKIE_DOMAIN to your eTLD+1 domain preceded by a ., i.e. .yourhost.com, so that it's sent to every of your subdomains, including api.yourhost.com.

Now in your test scenario, this cannot work, because the cookie set by your coworker's frontend is for localhost whereas the axios request is to your ip. There's no solution for this except have your co-worker get the frontend also from your ip.

Sign up to request clarification or add additional context in comments.

2 Comments

very well explained information! Thanks for the answer. I am going to wait a little while to see if someone else answers! I couldn't upvote but I will accept it as answer if no one else adds answer.
thanks for the very clear explanation. Until now I thought the csrf header and the csrf cookie were two names for the same thing. Thanks to you I finally managed to get a 200 response

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.