Force Django to use HTTPS URLs when reversing - python

I am running my Django application in Cloud9 for development purposes using the usual ./manage.py runserver. But to the outside world, the app is accessible via a https:// URL.
The problem is that when I use the URL reverse function, the URLs that come back start with http:// (at least some of the time). When I try redirecting to one of those URLs, I get an error like this one in the console:
Mixed Content: The page at 'https://apps.facebook.com/xxxx/'
was loaded over HTTPS, but requested an insecure form action
'http://xxxx.c9users.io/facebook_app/gift_shop/'.
This request has been blocked; the content must be served over HTTPS.
My question: is there a way to force reverse to generate HTTPS URLs instead of HTTP?
Here is a snippet of code, which has problems with redirection from HTTPS URLs to HTTP ones:
class IndexRedirectView(RedirectView, CSRFExemptMixin):
permanent = False
def get_redirect_url(self, *args, **kwargs):
if self.request.user.visit_count >= 5:
return reverse('gift-shop')
if len(BaseGiftableInstance.objects.filter(giving_user=self.request.user)) > 0:
# has won something
return reverse('gift-shop')
return reverse('spinner')

If you are on Django 1.8 or greater, you can force SSL with the setting SECURE_SSL_REDIRECT = True - see this answer on a similar question

You should check out django-sslify, you just install it and add it to your MIDDLEWARE_CLASSES.

Related

Django CORS headers whitelist doesn't work

I'm working on an existing code base which consists of a Django backend and a ReactJS frontend.
Everything is dockerized so I'm running the backend on localhost:8001 and the frontend on localhost:3000.
Because I got CORS errors in the browser, I added django-cors-headers to Django. When I add CORS_ORIGIN_ALLOW_ALL = True however, I get an error saying
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ‘http://127.0.0.1:8001/devices/’. (Reason: Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’).
So then I added the following settings:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'http//:127.0.0.1:3000',
'http//:127.0.0.1:8001',
)
But than I get an error saying
CORS header ‘Access-Control-Allow-Origin’ missing
Why is the whitelist not working? Am I doing something wrong here?
Install any cross origin browser extension in Your browser when you run front end code locally,it will helpful.
and change the whitelist url as below (//: should be ://):
CORS_ORIGIN_WHITELIST = (
'http://127.0.0.1:3000',
'http://127.0.0.1:8001',
)
When you have CORS_ORIGIN_ALLOW_ALL = True, this will set the Access-Control-Allow-Origin: * and as the error suggests while allowing all the domains for cross-origin requests, you can't pass credentials flag with the request. So if you want to keep the header as Access-Control-Allow-Origin: *, the easiest fix would be to not use the credentials flag while sending the CORS request from the frontend.
If you want to allow only a certain domains (which is preferable), you need to find the valid domains first. Remember these domains are the originating domains from where requests are coming to Django. You can find them by looking at request.META.REMOTE_HOST. request.META is the environment seen and passed on by WSGI, and if you have some proxies in between that will give you the last host in the proxy chain.
If you have a web server that talks WSGI e.g. nginx, it will pass on the REMOTE_HOST to your Django application or to any intermediate WSGI server you have (e.g. uWSGI/gunicorn) and they will in turn pass that to your app.
Also, in your settings, the URLs in CORS_ORIGIN_WHITELIST are in wrong format; the separator between scheme and netloc is ://, not //: e.g.:
http://127.0.0.1:3000

Using https as standard with django project

I am learning django and trying to complete my first webapp.
I am using shopify api & boilder plate (starter code) and am having an issue with the final step of auth.
Specifically, the redirect URL -- it's using HTTP:// when it should NOT and I don't know how to change it..
#in my view
def authenticate(request):
shop = request.GET.get('shop')
print('shop:', shop)
if shop:
scope = settings.SHOPIFY_API_SCOPE
redirect_uri = request.build_absolute_uri(reverse('shopify_app_finalize')) #try this with new store url?
print('redirect url', redirect_uri) # this equals http://myherokuapp.com/login/finalize/
permission_url = shopify.Session(shop.strip()).create_permission_url(scope, redirect_uri)
return redirect(permission_url)
return redirect(_return_address(request))
Which is a problem because my app uses the Embedded Shopify SDK which causes this error to occur at the point of this request
Refused to frame 'http://my.herokuapp.com/' because it violates the following Content Security Policy directive: "child-src 'self' https://* shopify-pos://*". Note that 'frame-src' was not explicitly set, so 'child-src' is used as a fallback.
How do i change the URL to use HTTPS?
Thank you so much in advance. Please let me know if I can share any other details but my code is practically identical to that starter code
This is what the Django doc says about build_absolute_uri:
Mixing HTTP and HTTPS on the same site is discouraged, therefore
build_absolute_uri() will always generate an absolute URI with the
same scheme the current request has. If you need to redirect users to
HTTPS, it’s best to let your Web server redirect all HTTP traffic to
HTTPS.
So you can do two things:
Make sure your site runs entirely on HTTPS (preferred option): Setup your web server to use HTTPS, see the Heroku documentation on how to do this. Django will automatically use HTTPS for request.build_absolute_uri if the incoming request is on HTTPS.
I'm not sure what gets passed in the shop parameter but if it contains personal data I'd suggest to use HTTPS anyway.
Create the URL yourself:
url = "https://{host}{path}".format(
host = request.get_host(),
path = reverse('shopify_app_finalize'))
But you will still need to configure your server to accept incoming HTTPS requests.

Django links and is_secure()

I am in the process of adding ssl to a django app and am running into some problems with my links redirecting from https to http.
Eventually I will have nginx redirect all http requests to https, but for now I am allowing both.
So if you go to https://www.mysite.com all is well. However, clicking on the "About link": href='/about' redirects you to http://www.mysite.com/about.
About is a super basic (static) page. Here's the entry in urls.py:
(r'^about/$', 'search.views.about'),
And here's the view function:
def about(request):
return render_to_response('search/about.html')
Shouldn't django direct my users to https://www.mysite.com/about/ ? I believe this has something to do with the request.is_secure() method. Which always returns false for me. I have read that I need to set the os.environ['HTTPS'] = "on" for it to return true. How can I go about doing this? Is there something else I need to do? Should I just hardcode https into all my links?
Thanks for all the help.
Turns out the nginx code I was using was screwing everything up. Instead of:
if ($http_x_forwarded_port != 443) { rewrite ^ https://$http_host/; }
use:
if ($http_x_forwarded_port != 443) { rewrite ^(.*) https://$host$1 permanent;
to do the redirection. As the first one drops all everything but the host.

Empty reply from Django web service

I have created a web service in django and its hosted on a shared server.The django web service respond to request from a game made in unity. But whenever game tries to request a django Web service url the server send empty resonse.Response is always:
WWW Error: server return empty string
The Unity webplayer expects a http served policy file named "crossdomain.xml" to be available on the domain you want to access with the WWW class, (although this is not needed if it is the same domain that is hosting the unity3d file).So I placed a file "crossdomain.xml" at the root of my domain ,but still i am getting same empty reply.Help plz...
EDIT:
I tried it through browser my service works fine and reply with proper response.And you know what My game can communicate to django web service when both are running on local machine.But now the django project is hosted on actual server and when game tried accessing service it never get response :(
url.py
urlpatterns = patterns('',
url(r'^crossdomain.xml$',views.CrossDomain),
url(r'^ReadFile/$',views.ReadFile),
)
views.py
def CrossDomain(request):
f = open(settings.MEDIA_ROOT+'jsondata/crossdomain.xml', 'r')
data = f.read()
f.close()
return HttpResponse(data, mimetype="application/xml")
def ReadFile(request):
f = open(settings.MEDIA_ROOT+'jsondata/some_file.json', 'r')
data = f.read()
f.close()
return HttpResponse(data, mimetype="application/javascript")
def Test(request):
return HttpResponse("Hello", mimetype="text/plain")
As I said using django for this is slight overkill because you could just serve them. Point aside though. If your serving on a different server it could be
A) Connection problems mean that your response is lost
B) Firewall issues mean that the request mean something
C) The server isn't setup correctly and therefore it justs get an error.
You need to test the response on the server. so is you access the page on the server through your browser. If so then make the game make a request and check the server error and access logs. In the apache access log you should see something like
GET "/url" 200 each time a request is made.
If you don't see any request getting through then either the request isn't made or its been lost.
If you do then the problem is in the code somewhere.

Allow hop-by-hop headers in Django proxy middleware

I need to implement a HTTP proxy in Django and my Google safari led me to a project called django-webproxy.
Although no longer maintained, it's quite simple. Most of the logic relies on a simple proxy Middleware class that intercepts all requests to the Django WSGI server and handles it.
If the Middleware returns any data, the WSGI server simply passes it back to the client but if it returns nothing, Django simply handles the request by passing to the other Middleware.
Everything works fine, pretty much, but I need to implement proxy authentication which mean i have to send a 407 status code to the client with a Proxy-Authenticate header. This sin't allowed by Django as it is a hop-by-hop header and Django throws an exception. How can i hack/force/kludge Django into allowing me to send hop-by-hop headers?
FYI, ihe code for the middleware class can be found here.
from django.core.servers import basehttp
del basehttp._hop_headers['proxy-authenticate']
del basehttp._hop_headers['proxy-authorization']
This worked for me.
django.core.servers.basehttp._hop_headers is no longer with us present in the basehttp module (since Django 1.10).
I know 2 ways to change it:
Start your server like so:
$ python -O ./manage.py runserver --noreload
Change wsgiref.util._hoppish:
import wsgiref.util
wsgiref.util._hoppish = {
'connection': 1, 'keep-alive':1,
'te':1, 'trailers':1, 'transfer-encoding':1,
'upgrade':1
}.__contains__

Categories