在Flask会话中存储oAuth状态令牌

6
一些oAuth教程使用Flask会话在flask会话中存储状态参数和访问令牌。(Brendan McCollam在Pycon上的非常有用的演示是一个例子)
我了解到Flask将会话存储在客户端的cookie中,而且很容易被暴露出来(请参阅Michael Grinberg的how-secure-is-the-flask-user-session)。我自己尝试过,可以看到令牌的过期等信息。
将状态和令牌存储在Flask会话中是否正确,或者它们应该存储在其他地方?
代码示例:
@app.route('/login', methods=['GET'])
def login():
    provider = OAuth2Session(
                   client_id=CONFIG['client_id'],
                   scope=CONFIG['scope'],
                   redirect_uri=CONFIG['redirect_uri'])
    url, state = provider.authorization_url(CONFIG['auth_url'])
    session['oauth2_state'] = state
    return redirect(url)

@app.route('/callback', methods=['GET'])
def callback():
    provider = OAuth2Session(CONFIG['client_id'],
                             redirect_uri=CONFIG['redirect_uri'],
                             state=session['oauth2_state'])
    token_response = provider.fetch_token(
                        token_url=CONFIG['token_url'],
                        client_secret=CONFIG['client_secret'],
                        authorization_response=request.url)

    session['access_token'] = token_response['access_token']
    session['access_token_expires'] = token_response['expires_at']

    transfers = provider.get('https://transfer.api.globusonline.org/v0.10/task_list?limit=1')

    return redirect(url_for('index'))

@app.route('/')
def index():
    if 'access_token' not in session:
        return redirect(url_for('login'))
    transfers = requests.get('https://transfer.api.globusonline.org/v0.10/task_list?limit=1',
                             headers={'Authorization': 'Bearer ' + session['access_token']})
    return render_template('index.html.jinja2',
                           transfers=transfers.json())

有人吗?有人能回答一半吗?我相信不只有我认为这很重要。 - ThierryMichel
1个回答

8
我认为有些教程过于简化,以展示更简单的代码。一个好的经验规则是仅将会话 cookie 用于必须由您的应用程序和用户浏览器知道且不是私有的信息。通常,这意味着会话 ID 和可能包括其他非敏感信息,例如语言选择。
应用这个经验规则,我建议针对每个令牌做如下处理:
1. 授权令牌:根据定义,该数据被用户和应用程序共同知晓,因此公开它不应该成为安全问题。然而,一旦获得访问代码,就没有必要再保留此令牌,因此我建议不要在本地或 cookie 中保留它。
2. 访问代码:该数据必须视为机密,只能由您的应用程序和提供商知晓。没有理由让任何其他方(包括用户)了解它,因此不应包含在 cookie 中。如果需要存储它,请在您的服务器上(例如在您的数据库中)保留它并引用您用户的会话 ID。
3. CSRF 状态令牌:最好将此数据作为隐藏表单字段包含,并针对服务器端变量进行验证,因此 cookie 看起来像是一个不必要的复杂性。但是,我不会担心此数据位于 cookie 中,因为它本来就是响应的一部分。
请记住,有一些扩展程序(例如 flask-sessions)可以使用服务器端变量而不是 cookie 变量,这样实际上相同的代码将会得到简化。

谢谢JavoSN...我已经寻找这个答案很长时间了...非常感谢您提供的全面解释。 - ThierryMichel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接