我正在尝试编写一个简单的(哈!)Python Flask 应用程序,它将使用 Google 的
people
API 来检索用户的数字 Google ID(否则似乎几乎无法确定)。 执行此操作需要用户使用 Google 的 OAUTH 进行身份验证。 我可以正常工作,但是 Google 的 Using OAuth 2.0 for Web Server Applications 文档说:
OAuth 客户端必须阻止 OAuth2 中规定的 CSRF 规格 。实现这一目标的一种方法是使用状态 参数来维护您的授权请求和 授权服务器的响应。
所以我遵循这个示例,并将状态存储在会话变量中。
@app.route('/auth')
def auth():
auth_url, state = get_oauth_flow().authorization_url()
app.logger.debug(f'Setting session state: {state}')
flask.session['state'] = state
return flask.redirect(auth_url)
@app.route('/oauth2callback')
def oauth2callback():
session_state = flask.session.get('state')
request_state = flask.request.args.get('state')
app.logger.debug(f'Got session state: {session_state}')
app.logger.debug(f'Got request state: {request_state}')
if session_state is None or session_state != request_state:
return 'Danger, Will Robinson!', 400
del flask.session['state']
flow = get_oauth_flow()
flow.fetch_token(authorization_response=flask.request.url)
flask.session['oauth_token'] = flow.credentials.token
return flask.redirect('success')
每当我执行初始登录过程时,都会失败。 (我收到一条“危险,威尔·罗宾逊!”消息。)我的日志显示会话变量已被清除。
DEBUG in ging: Setting session state: ijV2BAyuZG8uSO4rpN77nczw5UDEJf
DEBUG in ging: Got session state: None
DEBUG in ging: Got request state: ijV2BAyuZG8uSO4rpN77nczw5UDEJf
我不是一名 Web 开发人员,所以我对此感到非常茫然。 任何关于我可能做错的事情和/或其他方法的建议将不胜感激。
我 99% 确信我已经找出问题所在。 我不喜欢在任何地方放置静态密钥(用于 Flask 会话变量)的想法,所以我这样做了。
app = flask.Flask(__name__)
app.secret_key = os.urandom(24)
当我刚刚从命令行运行 Flask 应用程序时,这工作得很好,但在使用 Apache 和
mod_wsgi
运行时,它偶尔会失败。 我终于意识到 Apache 正在为我的应用程序生成多个进程,并且每个进程最终都有自己的密钥,该密钥无法解密另一个进程设置的会话 cookie。 (当 Flask 无法解密会话 cookie 时发出某种警告会真的很好。)
解决此问题的常用方法包括将密钥保存在文件中的某个位置或设置环境变量(可能使用硬编码值),这使我回到了我想要避免的静态密钥。 (我应该在这里指出,我正在开发的应用程序非常简单,所以我真的不关心会话是否能够在重新启动后继续存在。)
我最终决定采用这种方法。
app = flask.Flask(__name__)
# This file should be created by the httpd startup script/service
with open('/tmp/ging-session-key', 'rb') as gsk:
app.secret_key = gsk.read()
我将以下插入项添加到我的
httpd.service
定义中,以便在启动时创建文件。
[Service]
ExecStartPre=/usr/bin/dd if=/dev/urandom of=/tmp/ging-session-key bs=24 count=1
ExecStartPre=/usr/bin/chown apache:apache /tmp/ging-session-key
ExecStartPre=/usr/bin/chmod 0400 /tmp/ging-session-key
ExecStartPre=/usr/bin/chcon -t httpd_tmp_t /tmp/ging-session-key
操作系统提供的单元文件已经包含
PrivateTmp=true
,所以这应该是相对安全的。