Issue
I have use flask to develop a web app. In the pentesting report, it says, If the download function has a static link, then the download link should be not predictable. So I should change the int in the download link.
html:
<td><a href="{{ url_for('course_chat_export_csv', group_id=g.id) }}"
target="_blank">CSV</a> |
<a href="{{ url_for('course_chat_export_excel', group_id=g.id) }}"
target="_blank">Excel</a></td>
routes.py:
@app.route('/course/download/<int:group_id>/csv', methods=['GET', 'POST'])
def export_csv(group_id):
group = Group.query.get(group_id)
file_name = str.lower(group.title) + ".csv"
messages = Message.query.filter(Message.to_id == group.chat_id).order_by(Message.date.asc()).all()
temp = os.path.join(app.root_path, 'temp')
export_csv(messages, os.path.join(temp, file_name))
return send_from_directory(directory=temp, file_name=file_name, as_attachment=True,
attachment_filename=file_name)
How could I achieve that?
Solution
You can use JWT in exchange for the download link.
@app.route('/course/download/<str:token>/csv', methods=['GET', 'POST'])
def export_csv(token):
try:
data = jwt.decode(token, current_app.secret_key, algorithms=["HS256"])
except jwt.exceptions.InvalidTokenError:
return "invalid token", 401
group_id = data["group_id"]
group = Group.query.get(group_id)
file_name = str.lower(group.title) + ".csv"
messages = Message.query.filter(Message.to_id == group.chat_id).order_by(Message.date.asc()).all()
temp = os.path.join(app.root_path, 'temp')
export_csv(messages, os.path.join(temp, file_name))
return send_from_directory(directory=temp, file_name=file_name, as_attachment=True,
attachment_filename=file_name)
You can generate such tokens using the jwt module.
import jwt
from datetime import datetime, timedelta
JWT_EXP_DELTA_SECONDS = 20000
group_id = 25
token = jwt.encode(
{"group_id": group_id , "exp": datetime.utcnow() + timedelta(seconds=JWT_EXP_DELTA_SECONDS)}, # exp is optional, but you can use it if you want the download link only to work during a certain period of time
current_app.config["INVITES_SECRET"],
algorithm="HS256",
)
In the data section of the jwt you could also include the userId, and then check that the user which is currently logged in corresponds to the url it is using for the download. (in case you have authentication)
An alternative, which requires to make use of a database, is to just change the token for a random long string, and then in a database store the relation between random strings and group ids.
Of course, any kind of encrypted string works; but using JWT gives you a well-established protocol which you can use to also pass the data of the group_id and even user_id. Notice however that anyone with the token will be able to read such data, since the data itself is not encrypted.
Answered By - miquelvir
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.