CSRF verification failed when logging into admin panel - django

In production my app is giving me CSRF verification failed when I log into my admin panel.
I have the following in my settings.py:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
As my site doesn't currently have an SSL certificate I have ignored the following after running python manage.py check --deploy:
?: (security.W004) You have not set a value for the SECURE_HSTS_SECONDS setting. If your entire site is served only over SSL, you may want to consider setting a value and enabling HTTP Strict Transport Security. Be sure to read the documentation first; enabling HSTS carelessly can cause serious, irreversible problems.
?: (security.W008) Your SECURE_SSL_REDIRECT setting is not set to True. Unless your site should be available over both SSL and non-SSL connections, you may want to either set this setting True or configure a load balancer or reverse-proxy server to redirect all connections to HTTPS.

If you use those two settings then you must be using SSL.
See:
SESSION_COOKIE_SECURE
CSRF_COOKIE_SECURE

Related

Angular&Django: No 'Access-Control-Allow-Origin' header is present on the requested resource

I'm learning how to develop a website using Angular and Django. I got this error from my Angular localhost:
Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/user/' from origin
'http://localhost:4200' has been blocked by CORS policy: Response to preflight request
doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
In django's settings.py I have installed a custom users app, rest_framework and corsheaders app
Besides that, I have included this config:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
I've stacked the middleware in this way:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware', #CORS middleware
'users.middleware.AuthenticationMiddleware', #custom middleware for jwt
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
I've got no CORS errors with login and register requests from my angular app but the problem appeared when I used a middleware to check if a jwt header had been supplied (and test if it was valid or if it had expired). I added that middleware to settings.py file and that request worked fine in Postman so I tried to implement it from Angular.
This is the method:
validateToken(): Observable<boolean> {
const url = `${this.baseUrl}/user/`;
const headers = new HttpHeaders().set(
'jwt',
localStorage.getItem('token') || ''
);
return this.http
.get<AuthResponse>(url, {
headers,
})
.pipe(
map((resp) => {
localStorage.setItem('token', resp.jwt);
this._user = resp.user;
return resp.ok;
}),
catchError((err) => of(false))
);
However, I'm getting the error I showed before. Have any of you gone through this same problem with Angular and Django before and know how it could be solved?
PS: I've tried to install 'Allow CORS: Access-Control-Allow-Origin' Chrome extension but when I used it I still got this error:
Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/user/' from origin 'http://localhost:4200'
has been blocked by CORS policy: Response to preflight request doesn't pass access control check:
It does not have HTTP ok status.
There you have a screenshot of preflight request and response from browser's network tab:
On your headers variable you need to set a pair of property:value containing the missing access control property:
'Access-Control-Allow-Origin' : '*'

HTTP to HTTPS with health link on Elastic Beanstalk using Django

I am trying to redirect Http to Https in Django deployed on AWS Beanstalk. Http to Https works fine when I remove the health link from the load balancer. while having link in load balancer the app stops working.
I am using the following config in settings file in the Django project hosted on Aws Beanstalk.
CORS_REPLACE_HTTPS_REFERER = True
HOST_SCHEME = "https://"
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_PRELOAD = True
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
With SECURE_SSL_REDIRECT = True all non-secure requests will be redirected to https. Non-secure requests - ones done via http and with not matched SECURE_PROXY_SSL_HEADER.
Even if your load balancer performs http to https redirect by itself - it is good to have this option enabled in django and simplier (all security options enabled).
AWS ALB Health Checks cannot set custom headers. We can exclude requests to certain endpoints from being redirected to https with SECURE_REDIRECT_EXEMPT - [r'^health/$'].
AWS ALB Health Check requests are done to instance ip. To allow django process them - ip needs to be added to ALLOWED_HOSTS: ["172.16.2.5", "my.example.com"]. This needs to be instance private ip, one that will be used by ALB to reach it.
This can be done with:
Adding instance ip on instance start like in example. It can also be done with custom scripts and environment variables.
using custom middleware which allows adding ip ranges in ALLOWED_HOSTS and add VPC Subnet range or implement custom middleware manually
AWS ALB cannot add HSTS headers. If you want to use Strict Transport Security headers - they should be added on app django side. This can be done with setting SECURE_HSTS_SECONDS other than zero.
HSTS headers are only added on responses to secure requests (https:// or SECURE_PROXY_SSL_HEADER match).
I had the same problem and I fixed it with a middleware (python 3.x):
production settings.py:
MIDDLEWARE = ['market.middleware.ELBHealthChecker_middleware'] + MIDDLEWARE
ELB middleware:
def ELBHealthChecker_middleware(get_response):
def middleware(request):
response = get_response(request)
if "ELB-HealthChecker" in request.META["HTTP_USER_AGENT"]:
from django.http import HttpResponse
return HttpResponse(status=200)
return response
return middleware
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
These have worked for me in the past.

How can I block calls from unknown domains/IP to my REST API?

I want to block calls to my Django REST API (www.backend_django.com) from unknown origins, for example, I have a website under the domain "www.example.com" I want to allow only to this site to be able to do request to my API.
In order to do this, I have configured Django-Cors-Headers in the following way:
DEBUG = False
ALLOWED_HOSTS = ["www.backend_django.com", "backend_django.com"]
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'https://backend_django.com',
'https://www.backend_django.com',
'https://example.com',
'https://www.example.com', )
CSRF_TRUSTED_ORIGINS = [
'backend_django.com',
'example.com']
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'social_django.middleware.SocialAuthExceptionMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
]
In order to test it, I have done a call from Postman using my computer and have successfully done a request still to the API.
Did I set up something bad in the settings? How can I archive this?
CORS restrictions won't prevent other hosts from making direct requests to your API.
If you need granular restrictions then you could use something like django-iprestrict.
If you need to restrict the whole backend app it's easier via web server settings .htaccess or similar.

CORS during development without Access-Control-Allow-Origin

The server answer with a Access-Control-Allow-Origin value set for the production. Is there a way to be permissive when the requests come from my development server ? Is there a Django setting to disable the cross-origin check when DEBUG=True for example ?
I can't modify the Access-Control-Allow-Origin. The request is made with jquery ajax function.
EDIT:
I've installed https://github.com/ottoyiu/django-cors-headers with pip install django-cors-headers, added the following in my settings.py
if DEBUG:
INSTALLED_APPS += ('corsheaders', )
CORS_ORIGIN_ALLOW_ALL = DEBUG
And put the middleware :
MIDDLEWARE_CLASSES = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
...
}
But I still get the error :
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at _request_url_. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
If I inspect the response header, I don't see any Access-Control-Allow-Origin parameter.
Install middleware: https://github.com/ottoyiu/django-cors-headers
In django settings.py add following setting:
DEBUG=True
CORS_ORIGIN_ALLOW_ALL = DEBUG
(if DEBUG is true Access-Control-Allow-Origin will be added to headers in response)
To add CORS headers to your response, install this to your django project:
https://github.com/ottoyiu/django-cors-headers
Since you want to connect from local, you cannot whitelist a particular host alone.
To enable CORS only when you have DEBUG=True, you can add corsheaders to your installed apps only when Debug is True:
if DEBUG is True:
INSTALLED_APPS += ('corsheaders', )

angular2: origin 'http://localhost:3000' is therefore not allowed access

I have a django backend and I have enabled Cross origin requests as follows:
INSTALLED_APPS = [
..
'corsheaders',
]
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
'corsheaders.middleware.CorsMiddleware',
]
CORS_ORIGIN_ALLOW_ALL = True
I haven't implemented any authentication. I simply am trying to hit an API endpoint and trying to fetch data on my Angular2 frontend.
I have implemented a session based cart in Django backend which stores my products (https://github.com/lazybird/django-carton). When I hit http://127.0.0.1:8000/api/shopping-cart/show/ through my browsable api it gives me
{"1":{"product_pk":1,"price":"23000.00000","quantity":3},"2":{"product_pk":2,"price":"34000.00000","quantity":7},"4":{"product_pk":4,"price":"450.00000","quantity":1}}
However when I try to hit the same url from my Angular2 service: it throws me error:
XMLHttpRequest cannot load http://127.0.0.1:8000/api/shopping-cart/show/. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://localhost:3000' is therefore not allowed access. The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.
My service call is as follows:
private myUrl: string = 'http://127.0.0.1:8000/api/shopping-cart/'
showCart(){
return this.http.get(this.myUrl + 'show' + '/', {withCredentials:true})
.toPromise()
.then(response => response.json())
}
Note: If I remove {withCredentials:true} then it does not send sessionid or csrftoken and returns {} but the error vanishes. What am I doing wrong?
In my Django settings I had to add:
CORS_ALLOW_CREDENTIALS= True
AFAIK if you use withCredentials: true you can't use * for Access-Control-Allow-Origin but need http://localhost:3000 instead.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Origin
Access-Control-Allow-Origin: <origin> | *
The origin parameter specifies a URI that may access the resource. The browser must enforce this. For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource.
You middleware order problem. Try this
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
]
Note that CorsMiddleware needs to come before Django's CommonMiddleware
You can use angular2 integrated proxy.
create proxy.conf.json file
in proxy.conf write:
{
"/api/shopping-cart/": {
"target": "http://localhost:8000",
"secure": false
}
}
in your package.json change "start" script to:
"start": "ng serve --proxy-config proxy.conf.json"
run "npm start" in your command line