Python Flask and Graphene: Incorrect request causes security issue
up vote
0
down vote
favorite
I'm working on a simple messaging system where two different users can send messages to each other. Right now each user polls the server requesting the newest messages using graphQL.
The issue is that when one user, user A, sends a ton of messages (graphQL mutation queries) while the other user, user B, is polling, the messages sometimes appear to have been sent by user B.
I looked deeper and found that, in the cases where the messages were misattributed, the mutation query was hit with the incorrect request (as populated in the context), and the current_user
from flask_login
is also wrong. The current_user
seems to depend on the request. The request was one of user B's polling requests (which are not mutations.)
I traced it back a bit and found the point where the context is being populated (https://github.com/graphql-python/flask-graphql/blob/master/flask_graphql/graphqlview.py#L42) but it was difficult to figure out why it was getting the incorrect request from Flask.
My best guess is that there's something going on with Flask's request context stack, but it's tough to track down.
I should mention that authentication is done using an Authorization header and that I tried to find a case where a user was being mis-authenticated but couldn't.
This only seems to happen when I'm running flask directly using FLASK_ENV=production flask run
and seems to disappear when I run it using gunicorn
. Even so, it's concerning that the authentication could be so fragile.
Has anyone seen this issue before? Is there something in the Flask documentation explaining this issue, why it happens, and more importantly, why it won't happen when I use gunicorn
?
Relevant code versions:
- Flask 1.0.2
- Flask-GraphQL 2.0.0
- Flask-Login 0.4.1
- Flask-SQLAlchemy 2.3.2
- graphene 2.1.3
- graphene-sqlalchemy 2.1.0
- graphql-core 2.1
- SQLAlchemy 1.2.12
Example code:
import graphene as gr
from graphql import GraphQLError
from flask_login import current_user
from ...models import Message
from .shared import MessageNode
class CreateMessage(gr.Mutation):
""" Send a message to a channel account """
message = gr.Field(MessageNode)
class Arguments:
body = gr.JSONString(required=True)
@login_required
def mutate(self, info, body):
# Make sure that the body is populated with something
if not (body.get("text") and not body.get("image")) and not (
not body.get("text") and body.get("image")
):
raise GraphQLError("Body must contain either text or an image")
new_message = Message(
body=body,
sender_account=current_user, # CURRENT USER IS INCORRECT HERE
)
db.session.add(new_message)
db.session.commit()
return CreateMessage(message=new_message)
flask graphql flask-login graphene-python flask-graphql
add a comment |
up vote
0
down vote
favorite
I'm working on a simple messaging system where two different users can send messages to each other. Right now each user polls the server requesting the newest messages using graphQL.
The issue is that when one user, user A, sends a ton of messages (graphQL mutation queries) while the other user, user B, is polling, the messages sometimes appear to have been sent by user B.
I looked deeper and found that, in the cases where the messages were misattributed, the mutation query was hit with the incorrect request (as populated in the context), and the current_user
from flask_login
is also wrong. The current_user
seems to depend on the request. The request was one of user B's polling requests (which are not mutations.)
I traced it back a bit and found the point where the context is being populated (https://github.com/graphql-python/flask-graphql/blob/master/flask_graphql/graphqlview.py#L42) but it was difficult to figure out why it was getting the incorrect request from Flask.
My best guess is that there's something going on with Flask's request context stack, but it's tough to track down.
I should mention that authentication is done using an Authorization header and that I tried to find a case where a user was being mis-authenticated but couldn't.
This only seems to happen when I'm running flask directly using FLASK_ENV=production flask run
and seems to disappear when I run it using gunicorn
. Even so, it's concerning that the authentication could be so fragile.
Has anyone seen this issue before? Is there something in the Flask documentation explaining this issue, why it happens, and more importantly, why it won't happen when I use gunicorn
?
Relevant code versions:
- Flask 1.0.2
- Flask-GraphQL 2.0.0
- Flask-Login 0.4.1
- Flask-SQLAlchemy 2.3.2
- graphene 2.1.3
- graphene-sqlalchemy 2.1.0
- graphql-core 2.1
- SQLAlchemy 1.2.12
Example code:
import graphene as gr
from graphql import GraphQLError
from flask_login import current_user
from ...models import Message
from .shared import MessageNode
class CreateMessage(gr.Mutation):
""" Send a message to a channel account """
message = gr.Field(MessageNode)
class Arguments:
body = gr.JSONString(required=True)
@login_required
def mutate(self, info, body):
# Make sure that the body is populated with something
if not (body.get("text") and not body.get("image")) and not (
not body.get("text") and body.get("image")
):
raise GraphQLError("Body must contain either text or an image")
new_message = Message(
body=body,
sender_account=current_user, # CURRENT USER IS INCORRECT HERE
)
db.session.add(new_message)
db.session.commit()
return CreateMessage(message=new_message)
flask graphql flask-login graphene-python flask-graphql
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I'm working on a simple messaging system where two different users can send messages to each other. Right now each user polls the server requesting the newest messages using graphQL.
The issue is that when one user, user A, sends a ton of messages (graphQL mutation queries) while the other user, user B, is polling, the messages sometimes appear to have been sent by user B.
I looked deeper and found that, in the cases where the messages were misattributed, the mutation query was hit with the incorrect request (as populated in the context), and the current_user
from flask_login
is also wrong. The current_user
seems to depend on the request. The request was one of user B's polling requests (which are not mutations.)
I traced it back a bit and found the point where the context is being populated (https://github.com/graphql-python/flask-graphql/blob/master/flask_graphql/graphqlview.py#L42) but it was difficult to figure out why it was getting the incorrect request from Flask.
My best guess is that there's something going on with Flask's request context stack, but it's tough to track down.
I should mention that authentication is done using an Authorization header and that I tried to find a case where a user was being mis-authenticated but couldn't.
This only seems to happen when I'm running flask directly using FLASK_ENV=production flask run
and seems to disappear when I run it using gunicorn
. Even so, it's concerning that the authentication could be so fragile.
Has anyone seen this issue before? Is there something in the Flask documentation explaining this issue, why it happens, and more importantly, why it won't happen when I use gunicorn
?
Relevant code versions:
- Flask 1.0.2
- Flask-GraphQL 2.0.0
- Flask-Login 0.4.1
- Flask-SQLAlchemy 2.3.2
- graphene 2.1.3
- graphene-sqlalchemy 2.1.0
- graphql-core 2.1
- SQLAlchemy 1.2.12
Example code:
import graphene as gr
from graphql import GraphQLError
from flask_login import current_user
from ...models import Message
from .shared import MessageNode
class CreateMessage(gr.Mutation):
""" Send a message to a channel account """
message = gr.Field(MessageNode)
class Arguments:
body = gr.JSONString(required=True)
@login_required
def mutate(self, info, body):
# Make sure that the body is populated with something
if not (body.get("text") and not body.get("image")) and not (
not body.get("text") and body.get("image")
):
raise GraphQLError("Body must contain either text or an image")
new_message = Message(
body=body,
sender_account=current_user, # CURRENT USER IS INCORRECT HERE
)
db.session.add(new_message)
db.session.commit()
return CreateMessage(message=new_message)
flask graphql flask-login graphene-python flask-graphql
I'm working on a simple messaging system where two different users can send messages to each other. Right now each user polls the server requesting the newest messages using graphQL.
The issue is that when one user, user A, sends a ton of messages (graphQL mutation queries) while the other user, user B, is polling, the messages sometimes appear to have been sent by user B.
I looked deeper and found that, in the cases where the messages were misattributed, the mutation query was hit with the incorrect request (as populated in the context), and the current_user
from flask_login
is also wrong. The current_user
seems to depend on the request. The request was one of user B's polling requests (which are not mutations.)
I traced it back a bit and found the point where the context is being populated (https://github.com/graphql-python/flask-graphql/blob/master/flask_graphql/graphqlview.py#L42) but it was difficult to figure out why it was getting the incorrect request from Flask.
My best guess is that there's something going on with Flask's request context stack, but it's tough to track down.
I should mention that authentication is done using an Authorization header and that I tried to find a case where a user was being mis-authenticated but couldn't.
This only seems to happen when I'm running flask directly using FLASK_ENV=production flask run
and seems to disappear when I run it using gunicorn
. Even so, it's concerning that the authentication could be so fragile.
Has anyone seen this issue before? Is there something in the Flask documentation explaining this issue, why it happens, and more importantly, why it won't happen when I use gunicorn
?
Relevant code versions:
- Flask 1.0.2
- Flask-GraphQL 2.0.0
- Flask-Login 0.4.1
- Flask-SQLAlchemy 2.3.2
- graphene 2.1.3
- graphene-sqlalchemy 2.1.0
- graphql-core 2.1
- SQLAlchemy 1.2.12
Example code:
import graphene as gr
from graphql import GraphQLError
from flask_login import current_user
from ...models import Message
from .shared import MessageNode
class CreateMessage(gr.Mutation):
""" Send a message to a channel account """
message = gr.Field(MessageNode)
class Arguments:
body = gr.JSONString(required=True)
@login_required
def mutate(self, info, body):
# Make sure that the body is populated with something
if not (body.get("text") and not body.get("image")) and not (
not body.get("text") and body.get("image")
):
raise GraphQLError("Body must contain either text or an image")
new_message = Message(
body=body,
sender_account=current_user, # CURRENT USER IS INCORRECT HERE
)
db.session.add(new_message)
db.session.commit()
return CreateMessage(message=new_message)
flask graphql flask-login graphene-python flask-graphql
flask graphql flask-login graphene-python flask-graphql
edited Nov 12 at 15:36
asked Nov 9 at 21:08
maxlang
13
13
add a comment |
add a comment |
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53233291%2fpython-flask-and-graphene-incorrect-request-causes-security-issue%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown