如何在 Flask 中提供临时下载 url?
How to provide temporary download url in Flask?
目前,我的 index.html
文件包含
<a href="static/file.ext">Download</a>
我想更改此设置,以便下载 url 仅在特定时间内有效。例如,我如何将其更改为
<a href="get_file?file=file.ext&token=TEMPORARYTOKEN">Download</a>
在我的 Flask 文件中,我可以
@app.route('/get_file')
def get_file():
filename = request.args.get('file')
token = request.args.get('token')
if token is valid: # what can be done here
return send_from_directory('static', filename)
如何生成和处理令牌?还是我的做法完全错误?
有几种方法可以做到这一点。
为您的令牌生成一个 UUID 并将其与所需的到期日期时间一起存储在数据库 table 中。然后,当有人使用令牌调用 URL 时,您可以根据数据库检查它的有效性和过期时间。
如果您不想使用数据库来存储令牌,您可以使用 GPG 来加密包含到期日期时间的字符串,并将生成的加密字符串用作您的令牌。这意味着您的令牌将比 UUID 长很多,但您将避免使用 db。
我建议使用 UUID 和数据库 table。
另一种方法是使用 base64 对来自数据库的主键进行编码。这通常是整个网络上的短 url-服务如何获得短 url 的。数据库确保唯一性,因为它是 base64,所以在 url 变长之前需要相当多的文件。
然后在每次请求时检查您的数据库以查看 link 是否仍然有效。如果不是,请对请求做一些有意义的事情。
也许你应该使用 hmac。
生成link
import hashlib
import hmac
import time
secret = "anything you like" # such as generate from os.urandom(length)
def generate(filename):
current_time = str(int(time.time()))
token = hmac.new(secret, current_time, hashlib.sha256).hexdigest()
return "get_file?file=%(filename)s&time=%(current_time)s&token=%(token)s" % {
"filename": filename,
"current_time": current_time,
"token": token
}
验证link
import hashlib
import hmac
import time
secret = "anything you like" # same as in generate function
def verify(time_in_link, token_in_link):
time_limit = 15 * 60 # maximum time in sec(such as: 15(mins) * 60 (convert them to sec)`enter code here`) that you want them to start download after the link has been generated.
if (time.time() - int(time_in_link)) > time_limit: #timeout, return False
return False
if hmac.new(secret, str(time_in_link), hashlib.sha256).hexdigest() == token_in_link: # Check the token is available or not
return True
else:
return False
最好的方法是使用 itsdangerous
包。您可以生成一个持续任意时间的 URL。此外,您可以秘密编码 URL 中的任何信息。这样做的好处是不需要将时间戳处理或存储到数据库中
生成持续 30 分钟的 URL 并在令牌中编码用户 ID
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
s = Serializer('WEBSITE_SECRET_KEY', 60*30) # 60 secs by 30 mins
token = s.dumps({'user_id': currentuser.id}).decode('utf-8') # encode user id
使用以下生成你想要的URL
url_for('get_file', token=token)
验证 URL
@app.route('/get_file/<token>')
def get_file(token):
s = Serializer('WEBSITE_SECRET_KEY')
try:
user_id = s.loads(token)['user_id']
except:
return None
user = User.query.get(user_id)
if not user:
flash('This is an invalid or expired URL, please generate a new one!', 'warning')
return redirect(url_for('another_route'))
return send_from_directory('static', filename, as_attachment=True)
我在淋浴时想到的东西:
from flask import Flask
import datetime as dt
import hashlib
app = Flask(__name__)
time_lock = dt.datetime.now().strftime("%m/%d/%Y")
@app.route('/')
def home():
security_code = hashlib.sha256(time_lock.encode())
return f"<a href='/test/{security_code.hexdigest()}'>Click Here</a>"
@app.route('/test/<security_code>')
def test(security_code):
master_code = hashlib.sha256(time_lock.encode())
if security_code == master_code.digest():
return "Access granted!"
这是在使用当前日期的哈希值作为临时 URL。显然存在安全漏洞,但它确实是一个疯狂的想法,并且可以进一步提高安全性。它与选择的答案非常相似,但不使用持久存储。这可能适用于保护链接不被添加书签?
目前,我的 index.html
文件包含
<a href="static/file.ext">Download</a>
我想更改此设置,以便下载 url 仅在特定时间内有效。例如,我如何将其更改为
<a href="get_file?file=file.ext&token=TEMPORARYTOKEN">Download</a>
在我的 Flask 文件中,我可以
@app.route('/get_file')
def get_file():
filename = request.args.get('file')
token = request.args.get('token')
if token is valid: # what can be done here
return send_from_directory('static', filename)
如何生成和处理令牌?还是我的做法完全错误?
有几种方法可以做到这一点。
为您的令牌生成一个 UUID 并将其与所需的到期日期时间一起存储在数据库 table 中。然后,当有人使用令牌调用 URL 时,您可以根据数据库检查它的有效性和过期时间。
如果您不想使用数据库来存储令牌,您可以使用 GPG 来加密包含到期日期时间的字符串,并将生成的加密字符串用作您的令牌。这意味着您的令牌将比 UUID 长很多,但您将避免使用 db。
我建议使用 UUID 和数据库 table。
另一种方法是使用 base64 对来自数据库的主键进行编码。这通常是整个网络上的短 url-服务如何获得短 url 的。数据库确保唯一性,因为它是 base64,所以在 url 变长之前需要相当多的文件。
然后在每次请求时检查您的数据库以查看 link 是否仍然有效。如果不是,请对请求做一些有意义的事情。
也许你应该使用 hmac。
生成link
import hashlib
import hmac
import time
secret = "anything you like" # such as generate from os.urandom(length)
def generate(filename):
current_time = str(int(time.time()))
token = hmac.new(secret, current_time, hashlib.sha256).hexdigest()
return "get_file?file=%(filename)s&time=%(current_time)s&token=%(token)s" % {
"filename": filename,
"current_time": current_time,
"token": token
}
验证link
import hashlib
import hmac
import time
secret = "anything you like" # same as in generate function
def verify(time_in_link, token_in_link):
time_limit = 15 * 60 # maximum time in sec(such as: 15(mins) * 60 (convert them to sec)`enter code here`) that you want them to start download after the link has been generated.
if (time.time() - int(time_in_link)) > time_limit: #timeout, return False
return False
if hmac.new(secret, str(time_in_link), hashlib.sha256).hexdigest() == token_in_link: # Check the token is available or not
return True
else:
return False
最好的方法是使用 itsdangerous
包。您可以生成一个持续任意时间的 URL。此外,您可以秘密编码 URL 中的任何信息。这样做的好处是不需要将时间戳处理或存储到数据库中
生成持续 30 分钟的 URL 并在令牌中编码用户 ID
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
s = Serializer('WEBSITE_SECRET_KEY', 60*30) # 60 secs by 30 mins
token = s.dumps({'user_id': currentuser.id}).decode('utf-8') # encode user id
使用以下生成你想要的URL
url_for('get_file', token=token)
验证 URL
@app.route('/get_file/<token>')
def get_file(token):
s = Serializer('WEBSITE_SECRET_KEY')
try:
user_id = s.loads(token)['user_id']
except:
return None
user = User.query.get(user_id)
if not user:
flash('This is an invalid or expired URL, please generate a new one!', 'warning')
return redirect(url_for('another_route'))
return send_from_directory('static', filename, as_attachment=True)
我在淋浴时想到的东西:
from flask import Flask
import datetime as dt
import hashlib
app = Flask(__name__)
time_lock = dt.datetime.now().strftime("%m/%d/%Y")
@app.route('/')
def home():
security_code = hashlib.sha256(time_lock.encode())
return f"<a href='/test/{security_code.hexdigest()}'>Click Here</a>"
@app.route('/test/<security_code>')
def test(security_code):
master_code = hashlib.sha256(time_lock.encode())
if security_code == master_code.digest():
return "Access granted!"
这是在使用当前日期的哈希值作为临时 URL。显然存在安全漏洞,但它确实是一个疯狂的想法,并且可以进一步提高安全性。它与选择的答案非常相似,但不使用持久存储。这可能适用于保护链接不被添加书签?