HTTPS equivalent of Django's HttpResponse - django

For some reason I am in need of a views.py that returns only some text. Normally, i'd use HttpResponse("text") for this. However, In this case I require the text to be send over https, to counter the inevitable mixed content warning.
What is the simplest way of sending pure text via django(1.7.11) over https?

Django in the relevant docs of httprequest.build_absolute_uri reads:
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.
The docs make clear that
the method of communication is entirely the responsibility of the server
as Daniel Roseman commented.
My prefered choice is to force https throughout a site, however it is possible to do it only for a certain page.
The above can be achieved by either:
Upgrading to a secure and supported release of Django where the use of SECURE_SSL_REDIRECT and SecurityMiddleware will redirect all traffic to SSL
Asking your host provider an advice on how could this be implemented in their servers
Using the apache config files.
Using .htaccess to redirect a single page.
There are also other -off the road- hackish solutions like a snippet which can be used with a decorator in urls.py to force https, or a custom middleware that redirects certain urls to https.

I've run into the mixed content problems as well. From my experience, you simply can't use the HttpResponse objects without running into trouble. I was never totally sure though and eventually found a way "around" it.
My solution for it was to use the JsonResponse object instead, to return JSON strings, kind of a work-around with the views returning something like:
mytext = 'stuff blablabla'
return JsonResponse({'response_text': mytext})
Which is super easy to parse, and OK with HTTPS.
Maybe not what you're looking for, but I hope it helps you find your way.

Related

How to safely redirect to HTTPS on Django app not behind a proxy?

essentially, I want to turn SECURE_SSL_REDIRECT to true. but reading through the django docs, I get the impression this can compromise the projects security if it's not behind a proxy.
am I understanding that correctly, and if so, how should I go about doing http->https redirects when not behind a proxy?
thanks!
if anyone finds this, it looks like using Heroku means this is fine, as Heroku writes the X_FORWARDED_PROTO header, regardless of what the incoming header is, so theres no way for it to be set as https maliciously

Redirecting API requests in Django Rest Framework

I have a two-layer backend architecture:
a "front" server, which serves web clients. This server's codebase is shared with a 3rd party developer
a "back" server, which holds top-secret-proprietary-kick-ass-algorithms, and has a single endpoint to do its calculation
When a client sends a request to a specific endpoint in the "front" server, the server should pass the request to the "back" server. The back server then crunches some numbers, and returns the result.
One way of achieving it is to use the requests library. A simpler way would be to have the "front" server simply redirect the request to the "back" server. I'm using DRF throughout both servers.
Is redirecting an ajax request possible using DRF?
You don't even need the DRF to add a redirection to urlconf. All you need to redirect is a simple rule:
urlconf = [
url("^secret-computation/$",
RedirectView.as_view(url=settings.BACKEND_SECRET_COMPUTATION_URL))),
url("^", include(your_drf_router.urls)),
]
Of course, you may extend this to a proper DRF view, register it with the DRF's router (instead of directly adding url to urlconf), etc etc - but there isn't much sense in doing so to just return a redirect response.
However, the code above would only work for GET requests. You may subclass HttpResponseRedirect to return HTTP 307 (replacing RedirectView with your own simple view class or function), and depending on your clients, things may or may not work. If your clients are web browsers and those may include IE9 (or worse) then 307 won't help.
So, unless your clients are known to be all well-behaving (and on non-hostile networks without any weird way-too-smart proxies - you'll never believe what kinds of insanity those may do to HTTP requests), I'd suggest to actually proxy the request.
Proxying can be done either in Django - write a GenericViewSet subclass that uses requests library - or by using something in front of it, e.g. nginx or Caddy (or any other HTTP server/load balancer that you know best).
For production purposes, as you probably have a fronting webserver, I suggest to use that. This would save implementation time and also a little bit of server resources, as your "front" Django project won't even have to handle the request and keep the worker busy as it waits for the response.
For development purposes, your options may vary. If you use bare runserver then a proxy view may be your best option. If you use e.g. Docker, you may just throw in an HTTP server container in front of your Django container.
For example, I currently have a two-project setup (legacy Django 1.6 project and newer Django 1.11 project, sharing the same database) and a Caddy server in front of those, routing on per-URL basis. With a simple 9-line Caddyfile things just work:
:80
tls off
log / stdout "{common}"
proxy /foo project1:8000 {
transparent
}
proxy / project2:8000 {
transparent
}
(This is a development-mode config.) If you can have something similar, then, I guess, that would be the simplest option.

HAProxy and reqrep path rewriting with redirect configuration

With HA Proxy 1.5 I need to rewrite URL from
http://main.domain.com/my-foo
to
http://othersite.com:8081/other-bar
Here is what I tried:
frontend ft_def
bind :80
mode http
acl has_special_uri path_beg /my-foo
use_backend def if has_special_uri
default_backend def
backend def
mode http
option forwardfor
reqirep ^([^\ ]*\ )/my-foo(.*) \1/other-bar\2
server myserver othersite.com:8081
This works:
URL
http://main.domain.com/my-foo/home.html
becomes
http://othersite.com:8081/other-bar/home.html
and in the browser the initial URL http://main.domain.com/my-foo/home.html appears.
It is exactly what I need: it is completely transparent for the user.
But redirect does not work: when I click on a link on the page the URL is then
http://main.domain.com/other-bar/page2.html
I would like to get http://main.domain.com/my-foo/page2.html instead appearing in the browser.
Is it possible with HA Proxy? I tried many configurations without success.
Thanks!
If you're talking about links in HTML (as opposed to, say, Location: headers for redirects)... HAProxy 1.5 won't be able to modify those.
Presumably, based on what you describe, the page /other-bar/page1.html is internally linking to <a href="/other-bar/page2.html"> when it really should link to <a href="page2.html">. You'd need relative links in order for something like this to work transparently... otherwise, component "X" in your chain will have to be able to modify links on the fly in the response body, but only links, of course, since you wouldn't want to blindly regex-replace the page contents as a whole... and HAProxy 1.5 doesn't munge response bodies, so it can't fulfill the role of component "X."
HAProxy 1.6 might be able to do this, with Lua, but that's a maybe... and if it can be made to do it, it isn't likely to be at the level of performance you'd typically expect from HAProxy, because scrubbing the html in Lua is probably going to be a relatively expensive proposition.
Normally any URL changes should be handled by the web app itself, e.g. there is a :path option under :url configuration in Phoenix.Endpoint for the Phoenix framework: https://hexdocs.pm/phoenix/Phoenix.Endpoint.html, which was specifically designed for this purpose. Then the browser will still request the URL appears in the HTML file but HAProxy will always rewrite it.

Qt QDesktopServices::openUrl - launch browser with post values

I'm trying to write a simple application that will launch a browser and send it to a URL based on a user's input.
QDesktopServices::openUrl(QUrl(url));
However, I'd like to pass variables along with whatever URL they submit using POST.
For GET, all I'd need to do is simply embed the values into the URL string, but how would I go about adding POST variables?.
Thanks.
QDesktopServices wasn't designed for this, I'd suggest doing your HTTP POST using QNetworkAccessManager::post instead.
You can then possibly take some information from the HTTP response to open the desktop browser if this is necessary.
From the official documentation:
bool QDesktopServices::openUrl(const QUrl & url) [static]
Opens the given url in the appropriate Web browser for the user's desktop environment, and returns true if successful; otherwise returns false.
If the URL is a reference to a local file (i.e., the URL scheme is "file") then it will be opened with a suitable application instead of a Web browser.
The short answer is that it was not meant to be a network managet. For that purpose, one could already use the QNetworkAccessManager. It was just a convenient way to add support for opening up an URL as that would require quite a bit of work otherwise. There were no further plans to it to replicate QtNetwork more closely.
Thereby, I would suggest to use something like this to achieve working with post methods given your url:
QUrlQuery urlQuery;
urlQuery.addQueryItem("param1", "value1");
urlQuery.addQueryItem("param2", "value2");
QUrl url = QUrl("http://foo.com");
QNetworkRequest networkRequest(url);
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
networkManager->post(networkRequest, urlQuery.toString(QUrl::FullyEncoded).toUtf8());
If you have no issue with maintaining an external web service, you could set up a GET-to-POST redirection service (since QDesktopService::openUrl can pass url query strings to browsers without issue). Two things to keep in mind when going this route are to a) properly validate the requests the service recieves against some sort of whitelist to avoid security issues that stem from open http redirection, and b) to consider URL length limitations of both the user's desktop browser and server handling the redirects.
If we ignore IE and edge, desktop web browsers seem capable of handling URLs 32k-bytes long or better (figure obtained from a quick web search, may be inaccurate). If you're also targeting older android phones, the length limit drops to 8k.
Another way is to use QWebView which doesn't suffer from the same flaws as QDesktopServices: https://doc.qt.io/archives/qt-5.5/qwebview.html#load-1 . The only issue with this is that it will require use of the webkitwidgets module which may or may not be an issue for you.
Side note: I'm also still trying to find a way deal with the QDesktopServices problem. If you found a better way to send a POST request through the user's default browser, please post it here so that others can benifit.
Cheers.

django www vs non-www issue with middleware authentication

I have been having inconsistent behavior with my Django app.
If I login with no www, and then prepend www, it's not authenticated, and all the combinations thereof. (www.mydomain.com and mydomain.com like different sites in terms of auth)
If the authentication code is important, I wrote a middleware based on the tutorial here: http://onecreativeblog.com/post/59051248/django-login-required-middleware
So far I have fixed the issue forcing the appending of www, using PREPEND_WWW = True, but I would still like to understand the issue;)
Does anyone have an idea of what may be going on?
Thanks in advance!
What Zaha Zorg said: Cookies from Django won't work for both a prepended www and non-www domain by default.
However, the deeper issue here is that you're allowing both www and non-www domains of your site to serve identical content. Besides the obvious SEO consequences of having traffic split between the two, you run into issues like these. The proper way to handle this is to redirect all traffic from one to the other (whichever you prefer). The PREPEND_WWW setting you found works perfectly for this. For the opposite (forcing all traffic to non-www), it's recommended to just do a re-write at the server configuration level, such as Apache or Nginx.
You need to look at https://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#session-cookie-domain
SESSION_COOKIE_DOMAIN
Default: None
The domain to use for session cookies. Set this to a string such as ".lawrence.com" for cross-domain cookies, or use None for a standard domain cookie. See the How to use sessions.
Could it be that cookies depend on the hostname of the server ? This could explain why both domain names are considered different.