【问题标题】:Internal Server Error when using Flask session使用 Flask 会话时出现内部服务器错误
【发布时间】:2013-08-10 23:39:09
【问题描述】:

我想在请求之间保存一个 ID,使用 Flask session cookie,但是当我执行请求时,我得到了一个 Internal Server Error

我制作了一个简单的 Flask 应用程序原型来演示我的问题:

#!/usr/bin/env python

from flask import Flask, session

app = Flask(__name__)

@app.route('/')
def run():
    session['tmp'] = 43
    return '43'

if __name__ == '__main__':
    app.run()

为什么我在执行请求时无法存储具有以下值的session cookie?

【问题讨论】:

  • 你得到什么错误?
  • @sberry 我收到“未设置密钥”错误。但我认为(显然是错误的)这是自动设置的

标签: python session cookies flask


【解决方案1】:

根据Flask sessions documentation

... 这意味着用户可以查看您的内容 cookie 但不修改它,除非他们知道用于 签名。

为了使用会话,您必须设置密钥

设置密钥。你应该返回字符串,而不是整数。

#!/usr/bin/env python

from flask import Flask, session

app = Flask(__name__)

@app.route('/')
def run():
    session['tmp'] = 43
    return '43'

if __name__ == '__main__':
    app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
    app.run()

【讨论】:

  • @falstru 谢谢,43 int 是一个错字。到时你会得到答案
  • 您可能希望从随机来源生成密钥,而不是对其进行编码。密钥大小也很重要。试试 SECRET_KEY = open("/dev/random","rb").read(32) 。见andorian.blogspot.com/2014/08/…
  • @Lmwangi,实际上我使用os.urandom 来生成随机字节,并过滤可打印的字节。顺便说一句,如果您每次运行服务器时总是生成ranodm 编号,那么您将遇到问题。例如,如果您有多个烧瓶实例,则每个实例都有不同的密钥。
  • @falsetru:是的,我同意。实际上,在工作中,我们将秘密缓存到一个文件中,并在启动时读取该文件。
  • 可能值得注意的是,当遇到这个问题时,如果将他们的SESSION_COOKIE_SECURE 设置为True,并通过 HTTP 服务(例如测试),结果类似于遇到的问题这里(即cookie不会设置)。换句话说,安全 cookie 在不通过 HTTPS 提供时不会保存。
【解决方案2】:

正如 @falsetru 提到的,您必须设置一个密钥。

在将session cookie 发送到用户浏览器之前,Flask 会对 cookie 进行加密签名,这并不意味着您无法解码 cookie。我认为 Flask 会跟踪签名的 cookie,因此它可以执行它自己的“魔术”,以确定与请求(请求标头)一起发送的 cookie 是否是有效的 cookie。

你可能用到的一些方法,都与Flask类实例相关,一般定义为app

  • app 对象定义secret_key 变量

    app.secret_key = b'6hc/_gsh,./;2ZZx3c6_s,1//'
    
  • 使用config() 方法

    app.config['SECRET_KEY'] = b'6hc/_gsh,./;2ZZx3c6_s,1//'
    
  • 为整个 Flask 应用程序使用外部配置文件

    $ grep pyfile app.py
    app.config.from_pyfile('flask_settings.cfg')
    
    $ cat flask_settings.py
    SECRET_KEY = b'6hc/_gsh,./;2ZZx3c6_s,1//'
    

这是一个例子(改编自this article),重点是提供更清晰的Flask session cookie图片,考虑到客户端和服务器端的参与:

from flask import Flask, request, session                                       
import os                                                                       

app = Flask(__name__)                                                           

@app.route('/')                                                                 
def f_index():                                                               
    # Request Headers, sent on every request                                    
    print("\n\n\n[Client-side]\n", request.headers)                             
    if 'visits' in session:                                                     
        # getting value from session dict (Server-side) and incrementing by 1   
        session['visits'] = session.get('visits') + 1                           
    else:                                                                       
        # first visit, generates the key/value pair {"visits":1}                
        session['visits'] = 1                                                   
        # 'session' cookie tracked from every request sent                          
        print("[Server-side]\n", session)                                           
    return "Total visits:{0}".format(session.get('visits'))                     


if __name__ == "__main__":                                                      
    app.secret_key = os.urandom(24)                                             
    app.run()

这是输出:

$ python3 sessions.py 
* Serving Flask app "sessions" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

[Client-side]
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: keep-alive
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5

[Server-side]
<SecureCookieSession {'visits': 1}>
127.0.0.1 - - [12/Oct/2018 14:27:05] "GET / HTTP/1.1" 200 -


[Client-side]
Upgrade-Insecure-Requests: 1
Cookie: session=eyJ2aXNpdHMiOjF9.DqKHCQ.MSZ7J-Zicehb6rr8qw43dCVXVNA  # <--- session cookie
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Connection: keep-alive
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5

[Server-side]
<SecureCookieSession {'visits': 2}>
127.0.0.1 - - [12/Oct/2018 14:27:14] "GET / HTTP/1.1" 200 -

您可能已经注意到,在上面的示例中,我使用了os lib 和urandom() 函数来生成 Flask 的密钥,对吧?

来自the official doc

如何生成好的密钥

密钥应尽可能随机。您的操作系统有办法基于加密随机生成器生成相当随机的数据。使用以下命令快速生成 Flask.secret_key(或 SECRET_KEY)的值:

$ python -c '导入操作系统;打印(os.urandom(16))'

b'_5#y2L"F4Q8z\n\xec]/'


加注

如您所见,Flask 的创建者支持使用 os.urandom() 构建 Flask 密钥的做法,从该工具的旧版本到最新版本。那么:为什么 @joshlsullivan 的 的回答会收到反对票(值得一票)以及为什么 @MikhailKashkin 写道,使用 os.urandom() 是一个糟糕的主意,是个谜。

【讨论】:

    【解决方案3】:

    app = Flask(__name__) 下放置:app.secret_key = os.urandom(24)

    【讨论】:

    • @MikhailKashkin 曾经是官方文档的一部分。
    • 我很好奇:为什么这是一个糟糕的主意?我明白了为应用程序的每个实例使用不同的密钥,但我不认为这是一个安全威胁(请睁开眼睛:))。很糟糕,我们仍然有一些人在这里,只是投反对票,没有任何解释。
    • @ivanleoncz 同意。不鼓励投反对票。 :-)
    • @joshlsullivan,看看我的回答。 Flask 在其官方文档中绝对推荐它;)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-23
    • 1970-01-01
    • 2015-05-29
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    相关资源
    最近更新 更多