I made Django Backend. and Next.js Frontend. There is cookie which has _ga, csrftoken when I tested on local server 127.0.0.1.
BUT, there is no cookie at all on my production (which has different domain backend and frontend).
I guessed that everything happened because I used different domain when production. Here is some django settings.py I have
ALLOWED_HOSTS = [
"127.0.0.1",
"localhost",
"BACKENDURL",
"FRONTENDURL",
"*.FRONTENDURL",
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = [
"http://127.0.0.1:3000",
"http://localhost:3000",
"https://*.frontendURL",
"https://FRONTENDURL",
]
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
For the future visitors...
I figured out what I was wrong.
In Development Settings,
I use same domain
[127.0.0.1:3000] as frontend (Next.JS)
[127.0.0.1:8000] as backend (Django)
But, In Production Settings,
I use different domain
[frontend.com] as frontend
[backend.com] as backend
Which leads "cross-site" error on request/response.
I also found that there is no cookie in my production
due to I use different domain in production
Different domain cannot use same cookie => No Cookie on the frontend.
Thus, I have to set the domain same on backend and frontend in 'hosting service site'
www -> frontendurl
backend -> backendurl
=> Then I can get the csrftoken and sessionid when login.
Also, I made my settings.py in django project including...
SESSION_COOKIE_DOMAIN = ".mydomain"
CSRF_COOKIE_DOMAIN = ".mydomain"
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_ALL_ORIGINS = True
I recognize that CORS_ALLOW_ALL_ORIGINS leads some danger...
I set it just to confirm that everything is fine.
Later on, In production, change it into
CORS_ALLOWED_ORIGINS = [...]
Hope my answer helped someone.
Happy Hacking my friends. Good Luck!
Related
I am hosting on GAE and want to be able to access different versions without promoting them. Currently, I get a 400 error: Invalid HTTP_HOST header: '1234568-dot-myapp.ey.r.appspot.com'. You may need to add '1234568-dot-myapp.ey.r.appspot.com' to ALLOWED_HOSTS.
How can I add the URL to ALLOWED_HOSTS, so that I can access any version of my app?
Currently, my ALLOWED_HOSTS looks like this:
APPENGINE_URL = env("APPENGINE_URL", default=None)
if APPENGINE_URL:
if not urlparse(APPENGINE_URL).scheme:
APPENGINE_URL = f"https://{APPENGINE_URL}"
ALLOWED_HOSTS = [urlparse(APPENGINE_URL).netloc,
'my-personal-domain.com']
CSRF_TRUSTED_ORIGINS = [APPENGINE_URL,
'https://my-personal-domain.com']
SECURE_SSL_REDIRECT = True
else:
ALLOWED_HOSTS = ["*"]
From my understanding, wildcards only work for sub-domains. How can I add something like this to the allowed hosts?
[version-number]-dot-myapp.ey.r.appspot.com
Thanks!
Current Setup: I've got a Django application behind gunicorn running on Cloud Run. Since the region it is deployed in does not support Custom Domains, I have a firebase hosting setup with the following code:
{
"hosting": {
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [{
"source": "/**",
"run": {
"serviceId": "website",
"region": "ap-south1"
}
}]
}
}
The relevant settings in settings.py:
CSRF_TRUSTED_ORIGINS = ['.<domain>.com']
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
The problem: However, the login form on /admin does not work if I access the site using my domain name https://doman.com/admin even though it works fine if I use the Cloud Run endpoint https://endpoint-uw.a.run.app.
Faulty behaviour: When accessing it from my domain, the login page shows up, I enter my credentials and log in, it adds the relevant cookies to my browser but then it redirects me back to the login page.
Could it be that since the URL is being rewritten by firebase django is expecting a cookie from uw.a.run.app? I tried adding the setting SESSION_COOKIE_DOMAIN = '.<domain>.com' but that did not fix it either, it just made the Cloud Run endpoint stop working as well.
Any advice on how to fix this or how to diagnose what is going wrong would be much appreciated, thanks!
The relevant settings in settings.py:
SESSION_COOKIE_NAME = "__session"
as firebase send cookie in the name "__session"
I run a ReactJS front end application and Django REST back end/API both on the same webhost. The application works perfectly fine on localhost, however when you run it from somewhere else it can't seem to connect to the API.
Console of client's browser:
Django REST running on the server:
Am I supposed to connect to it using the external IP of the server instead of localhost? Localhost should work right, since both the frontend and Django API are hosted on the same server?
before fetch the django rest_api, make sure you setup django-cors-headers in your backend settings.py. for more information take a look at this link.
pip install django-cors-headers
settings.py :
INSTALLED_APPS = [
...
'corsheaders',
...
]
MIDDLEWARE = [ # Or MIDDLEWARE_CLASSES on Django < 1.10
...
'corsheaders.middleware.CorsMiddleware',
'corsheaders.middleware.CorsPostCsrfMiddleware',
...
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = [
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
]
In case someone is looking for an answer, I've learned a few things since posting:
The Django API has to be accessed by the IP, not localhost.
Since my website is on HTTPS, Django has to be accessed by HTTPS as well or it won't work.
Since Django runserver doesn't support HTTPS you need to host it with a webserver (you should do this anyway in production), I used Apache for this.
Thanks to xxnora for giving me tips and steering me in the right direction.
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?
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.
I have just pushed a web app into production and requests to my nodejs no longer contain the user cookie that Django has been setting by default on my localhost (where it was working).
my nodejs looks for the cookie like this
io.configure(function(){
io.set('authorization', function(data, accept){
if (data.headers.cookie) {
data.cookie = cookie_reader.parse(data.headers.cookie);
return accept(null, true);
}
return accept('error',false);
});
io.set('log level',1);
});
and on localhost has been getting this
cookie: 'username="name:1V7yRg:n_Blpzr2HtxmlBOzCipxX9ZlJ9U"; password="root:1V7yRg:Dos81LjpauTABHrN01L1aim-EGA"; csrftoken=UwYBgHUWFIEEKleM8et1GS9FuUPEmgKF; sessionid=6qmyso9qkbxet4isdb6gg9nxmcnw4rp3' },
in the request header.
But in production, the header is the same but except no more cookie. Does Django only set this on localhost? How can I get it working in production?
I've tried setting these in my settings.py
CSRF_COOKIE_DOMAIN = '.example.com'
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = False
But so far no good.
Any insight would be great.
I just figured it out. I was making a request to nodejs on the client like this
Message.socket = io.connect('http://123.456.789.10:5000');
Where I used my respective IP address and port that my nodejs was listening on. This is considered cross domain so browsers won't include cookies in the request. Easy fix by changing it to
Message.socket = io.connect('http://www.mydomain.com:5000');