Django Socketio Nginx proxy & session cookie issue - django

I have followed this tutorial: http://www.stephendiehl.com/?p=309 describing how to run a gevent pywsgi server serving Django with socketio behind a nginx front-end.
As this tutorial says, Nginx doesn't support websocket unless using a tcp proxy module. This proxy module doesn't support the use of the same port for socketio and classic serving, from what I understood the configuration look like that:
nginx listen on port 80
nginx tcp proxy listen on port 7000
Everything is forwarded to port 8000
Problem: the resulting socketio request doesn't include the django cookie containing the session id so I have no information on the requesting user in my django view.
I guess it's caused by the fact that the request is made to another port (7000) causing the browser to identify the request as cross-domain ?
What would be the cleanest way to include the django cookie into the request ?

Most answers in this question seem to indicate that port doesn't matter.
Also checked and supposedly WebSockets is regarded as HTTP, so HTTPOnly cookies should still be sent.
SocketIO seems to be using a custom Session manager to track users. Maybe try and link that up?

Related

Flask redirection to https prevents http request to work [duplicate]

This question already has answers here:
Are a WSGI server and HTTP server required to serve a Flask app?
(3 answers)
Closed 4 months ago.
I'm using Flask to deliver maps designed with folium.
I'd like to add a geolocation service, and hence, need to migrate change http to https.
I've found a couple of example pages, and the https page delivery works fine.
But ... my users still try to connect through http requests, and redirection from http to https does not work.
More precisely, i've added this code to handle http to https conversion:
#app.before_request
def before_request():
print ("url", request.url)
if request.url.startswith('http://'):
url = request.url.replace('http://', 'https://', 1)
code = 301
print ("url", request.url)
return redirect(url, code=code)
The server initialization works like that :
context = ssl.SSLContext()
context.load_cert_chain('mycert.pem',
'myprivkey.pem')
app.run(debug=False, host= '0.0.0.0', port=5051, ssl_context=context)
The url gets printed when I call https pages, but never when I call http pages.
Any clue why the https activation prevents http from working ?
Your Flask server is HTTPS only. When a browser sends an HTTP (non-secure) request but server responds with HTTPS related (handshake etc) response, then browsers like Firefox/Chrome will abort the flow and display something like:
The connection was reset
The connection to the server was reset while the page was loading.
Your Flask is SSL enabled, users trying with http:// will not be reach the step you have provisioned to redirect them to https://.
You could put a reverse proxy listening on both HTTP (80) and HTTPS (443) ports, HTTPS listener will be forwarding the requests to Flask, HTTP listener will be doing the redirection to HTTPS.

Connecting localhost to a remote dev server (CORS, same-site, secure and other headaches)

I'm currently working on a React project. The development server (Bottle/Python) for the project is hosted remotely, and my React dev-server is localhost. Part of the authentication process for the application involves setting a cookie on login, but because of same-site and secure rules that cookie is not being set, meaning that my dev frontend can't access any of the data that it needs.
Myself and the server engineer have added SameSite=None to the cookie as well as secure, but because my localhost is not https the cookie is still not being stored properly (I get the error message "this Set-Cookie" was blocked because it had the "Secure" attribute but was not received over a secure connection").
There are no issues when the app is deployed because everything is on the same domain, but for now we're stuck - we've been trying to solve the issue for several hours but can't seem to get it.
My question is - what is the best development practice if you need to access a non-local development server, but can't actually just have your own version of the server running on your local machine?
Do I:
Need to make my localhost https somehow?
Need to make the dev-server domain https?
Need to install the server locally because there's just no way to do this?
Apologies if this is a noob question, it would be great to have some advice.
Many thanks.
The short answer is:
No
Yes
No
You can run your app on http://localhost:port. Assuming response from your dev server has in response headers Set-Cookie of the cookie which has Secure flag, your dev server URL has to be https in order to have the cookie accepted by the browser.
I have this setup and it works just well.
Regarding CORS (as mentioned in the title of the question): you have to have you server configured to accept credentials and to have allowed origins configured. The client app when doing XHR request has to have withCredentials:true. Check the points 2 and 3 in my post for details.
Also note, that if you are using Chrome you can bypass for development purposes the requirement to have SameSite=None and Secure by disabling the flag "Cookies without SameSite must be secure", also detailed here

Daphne server unable to handle http requests

I have a django application that I want to deploy using daphne.
Django application supports both websockets and http requests. I've converted the django to support ASGI.
I'm starting the server using :
daphne <project_name>.asgi:application
The server is able to accept websocket connections but unable to handle the incoming HTTP requests (throws 404).
Where am I going wrong over here?
P.S.: I'm not using django channels.
I had forgotten to instantiate 'get_asgi_application' while creating the django application. Hence, it wasn't able to accept HTTP requests.

Is it possible to make Django send data over tls protocol?

I am currently working on a web project in django and there is a requirement to ensure the safety of transmitting data over a network (passwords, usernames etc.).
I've read on owasp cheat sheet about authenication that for safety reasons all passwords should be sent from a client to a server over tsl protocol.
https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Transmit_Passwords_Only_Over_TLS_or_Other_Strong_Transport
Django framework sends these over http protocol. Is it possible to make django send it over tsl or work around it in another way?
When you run a Django application on the Internet, it's usually looking something like this:
[Django Application] <-> [uWSGI] <-> [nginx] <-> [web browser]
You can use different components, e.g. Gunicorn instead of uWSGI or Apache instead of nginx.
The thing is, you simply configure the webserver (Apache or nginx or whatever) with an SSL certificate and listen for https instead of http.
I think you're using Django runserver command for server your app over HTTP. It is absolutely not made for production and is a really HTTP (only) server for development.
For serve your app across SSL/TLS, you must use a frontend as described in henrikstroem's response

how to set http request timeout in python flask

How can I set a request timeout using Python Flask? I'm trying to compare Flask to some other framework and need to configure the timeouts to be equivalent.
Thanks!
As Martijn Pieters said in their comment on the question, this isn't something you want to do because the Flask development server isn't a good choice for production. It would be better to run your flask application on a server like Gunicorn and set the timeout there instead.
But to answer the question anyway, Flask.run has an options parameter allowing you to pass options through to the underlying Werkzeug server:
run(host=None, port=None, debug=None, load_dotenv=True, **options)
The relevant werkzeug method in turn has a request_handler parameter allowing you to specify what request handler is to be used:
werkzeug.serving.run_simple(hostname,
port,
application,
use_reloader=False,
use_debugger=False,
use_evalex=True,
extra_files=None,
reloader_interval=1,
reloader_type='auto',
threaded=False,
processes=1,
request_handler=None,
static_files=None,
passthrough_errors=False,
ssl_context=None
)
This is your hook for supplying a request handler object that implements the timeout policy you want (a subject explored in this question: How to implement Timeout in BaseHTTPServer.BaseHTTPRequestHandler Python).
WSGI server
WSGI is the protocol, a facade separating your code from the actual web server which runs it.
In the flask, you only create the logic of the server. On run, your Flask application is served by the WSGI server. The most common is uWSGI ( & nGinx proxy to the secure border between the outer world and your server). But you can use whichever WSGI server suits you best without need to change your code (nichol.as/benchmark-of-python-web-servers)*.
Flask itself ships only with the Development WSGI flask server. It means the server uses a lot of features to help the developer debug their application. These features make the server very slow. So when you do a benchmark of your app on the Development WSGI flask server, results have no value for you.
On the other hand, specialized production-ready WSGI servers (including uWSGI) are well optimized, tested and production-proven. Most of the features are usually turned off by default and allow you to fine-tune these powerful beasts for your application.
Deployment tutorials:
flask+wsgi: https://flask.palletsprojects.com/en/1.1.x/tutorial/deploy/
flask+uwsgi+nginx:
http://vladikk.com/2013/09/12/serving-flask-with-nginx-on-ubuntu/
Timeout
Now when I explained the context, back to your original question. I would set requests timeout in your:
test client :
import requests
requests.get('https://api.myapp.com', timeout=3)
<Response [200]>
nGinx proxy cofing:
http
{
server
{
…
location /
{
…
proxy_read_timeout 120s;
…
}
}
}
If the question is related to the Flask timeout while waiting for the completion of the browser data request after a TCP socket connection is set-up by the browser and accepted by Flask (i.e., werkzeug, where each line sent by the browser resets the timer), a trivial solution would be to add this before app.run(...):
import socket
socket.setdefaulttimeout(10) # seconds
Setting it once at the beginning of the program affects all new socket connections.
A timed out request generates the BaseHTTPRequestHandler error Request timed out: TimeoutError('timed out').
This configuration does not appear to control the time Flask takes to process a valid request, which should be implemented inside the function decorated with #app.route(...).