This article mainly introduces the Python Flask framework and Nginx's static file access restriction function. Nginx uses its own XSendfile. For more information, see
Nginx configuration
Ngnix, a high-performance web server, is undoubtedly the current darling. Superior performance, flexible scalability, attacking the city and fighting the world in the server field.
Static files are an indispensable part of most websites. It is also common to use Nginx to process static files. However, some static files are not disclosed to any user in any situation. For example, some files provided for users to download and some images uploaded by users that involve user privacy. We want users to be accessible when they log on. users not logged on are invisible.
Rough processing: the backend program can perform filtering and verify the user logon in the view logic when rendering the page, and then return the corresponding page. For example, the following flask code (pseudo code)
@app.router('/user/idcard'):def user_idcard_page(): if user is login: return '" else: reutrn 'Pemission Denied
', 403
However, there is another problem in this process. static files are handed over to nginx for processing. If hacker finds the absolute address of the file, access http://www.example.com/upload/user/xxx.pngdirectly. These files involve user privacy, such as user-uploaded ID card photos. In this case, coders do not want to report the second day that the well-known website XXX has a vulnerability and Hacker has obtained user ID card and other information.
To make such restrictions, you can use a small feature of Nginx-XSendfile. The principle is also relatively simple, probably because request redirection is used.
We know that if Nginx is used as the reverse proxy of the front-end server and a request comes in, nginx first catches up, then forwards the request to the backend program based on the rules, or directly processes the response. The former processes some dynamic logic, while the latter processes mostly static files. Therefore, in the above example, Nginx directly returns the absolute address for directly accessing the static file without calling the backend user_idcard_page for logical restrictions.
To solve this problem, the XSendfile function provided by nginx simply uses the internal command. This command only accepts internal requests, that is, requests forwarded by the backend. In the backend view logic, you must explicitly write the headers information X-Accel-Redirect.
The pseudocode is as follows:
location /upload/(.*) { alias /vagrant/; internal;}@app.router('upload/
')@login_requireddef upload_file(filename): response = make_response() response['Content-Type'] = 'application/png' response['X-Accel-Redirect'] = '/vagrant/upload/%s' % filename return response
After such processing, you can redirect static resources. This is a common practice. many download servers can use this method to download user permissions.
Flask
Flask is my favorite web framework. Flask even implements a sendfile method, which is simpler than the above method. I used vagrant as a virtual machine and Flask to implement the above requirements. the specific code is as follows:
Project structure
project structproject app.py templates static 0.jpeg upload 0.jpeg
Nginx configuration nginx conf
Web. conf
Server {listen 80 default_server; # server_name localhost; server_name 192.168.33.10; location/{proxy_pass http: // 127.0.0.1: 8888; proxy_redirect off; proxy_set_header Host $ host: 8888; proxy_set_header X-Real-IP $ remote_addr; proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for;} # normal static file location/static /(. *) {root/vagrant/;} # specify the permission to restrict the location/upload /(. *) {alias/vagrant/; internal; # only receive internal request instructions }}
Flask code
App. py
From functools import wrapsfrom flask import Flask, render_template, redirect, url_for, session, send_fileapp = Flask (_ name _) app. config ['secret _ key'] = 'You never guess 'def login_required (f): @ wraps (f) def decorated_function (* args, ** kwargs): if not session. get ('login'): return redirect (url_for ('login', next = request. url) return f (* args, ** kwargs) return decorated_function@app.route ('/') def index (): return 'index' @ app. route ('/user') @ login_requireddef user (): return render_template('upload.html') # process the file view uploaded by the user, where the request is returned to the nginx@app.route ('/upload/
') @ Login_requireddef upload (filename): return send_file ('upload /{}'. format (filename) @ app. route ('/login') def login (): session ['login'] = True return 'log in' @ app. route ('/logout') def logout (): session ['login'] = False return 'Log out' if _ name _ = '_ main _': app. run (debug = True)
Simple Deployment
gunicorn -w4 -b0.0.0.0:8888 app:app --access-logfile access.log --error-logfile error.log