Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write decorator to ensure request origin is safe when communicating with application #7

Open
therealadityashankar opened this issue Aug 24, 2018 · 3 comments

Comments

@therealadityashankar
Copy link

So I think a security vulnerability would be if a malicious website sent a request to localhost:port, as flask-desktop is connected to python that has a higher amount of user access(such as modifying files) than web applications, that desktop applications usually require.

@Widdershin
Copy link
Owner

Very possibly, you shouldn't use this to open websites that run untrusted code.

@therealadityashankar
Copy link
Author

therealadityashankar commented Aug 27, 2018

ANY website can send a request to localhost, since the app uses localhost:port, a developer might want to send and recieve data from their flask-desktop application to make file-system changes, and might open a malicious website in a browser-tab while doing so.

for example:
try the following flask code:

@app.route("/",methods=["GET","POST"])
def foo():
    print(request.data)

app.run(port=5000)

open the javascript console in any web browser from about:blank or any website with a weak CSP and type

fetch("http://localhost:5000/",{method:"POST",body:"whooooie"})

the request goes through,
b"whoooie" will get printed

but i can do something more vulnerable than print(request.data), like

with open(request.data.encode(), "w") as of:
    of.write("this is a new file")

a malicious website could send like a 1000 requests of this action and fill the users computer with unnecessary files

tl;dr: "you can't open any website with malicious code while your flask-desktop app runs"

@vremes
Copy link

vremes commented Aug 14, 2019

This issue is pretty old already, but i guess it probably won't hurt to give my opinion on this issue.

In my opinion, you should just use CSRF tokens to avoid this situation, here's example code:

import os
import secrets
from flask import Flask, request, session, abort

app = Flask(__name__)
# Set secret key in order to use session
# probably a good idea to use random secret key, for example: secrets.token_urlsafe(32)
app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET')

@app.after_request
def after_request(response):
    token = session.get('token')
    # Generate CSRF token using secrets library if it does not already exist
    if not token:
        token = secrets.token_urlsafe(32)
        session['token'] = token
    # Save CSRF token to cookie so it's easily available on all requests
    response.set_cookie('token', token, httponly=True)
    return response

@app.before_request
def before_request():
    # If incoming request method is PUT, DELETE or POST
    if request.method in ('PUT', 'DELETE', 'POST'):
        # Get CSRF token from session
        token = session.pop('token')
        # Get CSRF token from cookie
        cookie_token = request.cookies.get('token')
        if not token or not cookie_token or token != cookie_token:
            # Abort the request with 403 access denied, if CSRF token does not exist or it is invalid
            abort(403)

The code above will save CSRF token to session and cookie on each request, when request method is PUT, DELETE or POST it'll check if the CSRF token is valid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants