Browse Source

Merge pull request #2399 from davidism/docs-secret-key

clean up secret key docs
pull/2409/head
David Lord 7 years ago committed by GitHub
parent
commit
d13e41ddef
  1. 12
      docs/api.rst
  2. 8
      docs/config.rst
  3. 2
      docs/patterns/flashing.rst
  4. 23
      docs/quickstart.rst
  5. 8
      docs/tutorial/setup.rst
  6. 2
      examples/flaskr/flaskr/factory.py
  7. 2
      examples/minitwit/minitwit/minitwit.py
  8. 4
      flask/app.py
  9. 7
      tests/conftest.py
  10. 2
      tests/static/config.json
  11. 24
      tests/test_basic.py
  12. 13
      tests/test_config.py
  13. 5
      tests/test_signals.py
  14. 2
      tests/test_templating.py
  15. 6
      tests/test_testing.py

12
docs/api.rst

@ -103,12 +103,12 @@ Response Objects
Sessions Sessions
-------- --------
If you have the :attr:`Flask.secret_key` set you can use sessions in Flask If you have set :attr:`Flask.secret_key` (or configured it from
applications. A session basically makes it possible to remember :data:`SECRET_KEY`) you can use sessions in Flask applications. A session makes
information from one request to another. The way Flask does this is by it possible to remember information from one request to another. The way Flask
using a signed cookie. So the user can look at the session contents, but does this is by using a signed cookie. The user can look at the session
not modify it unless they know the secret key, so make sure to set that contents, but can't modify it unless they know the secret key, so make sure to
to something complex and unguessable. set that to something complex and unguessable.
To access the current session you can use the :class:`session` object: To access the current session you can use the :class:`session` object:

8
docs/config.rst

@ -39,7 +39,7 @@ method::
app.config.update( app.config.update(
DEBUG=True, DEBUG=True,
SECRET_KEY='...' SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/'
) )
.. admonition:: Debug Mode with the ``flask`` Script .. admonition:: Debug Mode with the ``flask`` Script
@ -367,7 +367,7 @@ Here is an example of a configuration file::
# Example configuration # Example configuration
DEBUG = False DEBUG = False
SECRET_KEY = '?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83' SECRET_KEY = b'_5#y2L"F4Q8z\n\xec]/'
Make sure to load the configuration very early on, so that extensions have Make sure to load the configuration very early on, so that extensions have
the ability to access the configuration when starting up. There are other the ability to access the configuration when starting up. There are other
@ -385,7 +385,7 @@ from the environment.
Environment variables can be set on Linux or OS X with the export command in Environment variables can be set on Linux or OS X with the export command in
the shell before starting the server:: the shell before starting the server::
$ export SECRET_KEY='?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83' $ export SECRET_KEY='5f352379324c22463451387a0aec5d2f'
$ export DEBUG=False $ export DEBUG=False
$ python run-app.py $ python run-app.py
* Running on http://127.0.0.1:5000/ * Running on http://127.0.0.1:5000/
@ -393,7 +393,7 @@ the shell before starting the server::
On Windows systems use the `set` builtin instead:: On Windows systems use the `set` builtin instead::
>set SECRET_KEY='?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83' >set SECRET_KEY='5f352379324c22463451387a0aec5d2f'
>set DEBUG=False >set DEBUG=False
While this approach is straightforward to use, it is important to remember that While this approach is straightforward to use, it is important to remember that

2
docs/patterns/flashing.rst

@ -22,7 +22,7 @@ So here is a full example::
request, url_for request, url_for
app = Flask(__name__) app = Flask(__name__)
app.secret_key = 'some_secret' app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
@app.route('/') @app.route('/')
def index(): def index():

23
docs/quickstart.rst

@ -160,7 +160,7 @@ Screenshot of the debugger in action:
:class: screenshot :class: screenshot
:alt: screenshot of debugger in action :alt: screenshot of debugger in action
More information on using the debugger can be found in the `Werkzeug More information on using the debugger can be found in the `Werkzeug
documentation`_. documentation`_.
.. _Werkzeug documentation: http://werkzeug.pocoo.org/docs/debug/#using-the-debugger .. _Werkzeug documentation: http://werkzeug.pocoo.org/docs/debug/#using-the-debugger
@ -724,6 +724,9 @@ sessions work::
app = Flask(__name__) app = Flask(__name__)
# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
@app.route('/') @app.route('/')
def index(): def index():
if 'username' in session: if 'username' in session:
@ -748,24 +751,18 @@ sessions work::
session.pop('username', None) session.pop('username', None)
return redirect(url_for('index')) return redirect(url_for('index'))
# set the secret key. keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
The :func:`~flask.escape` mentioned here does escaping for you if you are The :func:`~flask.escape` mentioned here does escaping for you if you are
not using the template engine (as in this example). not using the template engine (as in this example).
.. admonition:: How to generate good secret keys .. admonition:: How to generate good secret keys
The problem with random is that it's hard to judge what is truly random. And A secret key should be as random as possible. Your operating system has
a secret key should be as random as possible. Your operating system ways to generate pretty random data based on a cryptographic random
has ways to generate pretty random stuff based on a cryptographic generator. Use the following command to quickly generate a value for
random generator which can be used to get such a key:: :attr:`Flask.secret_key` (or :data:`SECRET_KEY`)::
>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
Just take that thing and copy/paste it into your code and you're done. $ python -c 'import os; print(os.urandom(16))'
b'_5#y2L"F4Q8z\n\xec]/'
A note on cookie-based sessions: Flask will take the values you put into the A note on cookie-based sessions: Flask will take the values you put into the
session object and serialize them into a cookie. If you are finding some session object and serialize them into a cookie. If you are finding some

8
docs/tutorial/setup.rst

@ -33,12 +33,12 @@ initialize it with the config from the same file in :file:`flaskr.py`::
app.config.from_object(__name__) # load config from this file , flaskr.py app.config.from_object(__name__) # load config from this file , flaskr.py
# Load default config and override config from an environment variable # Load default config and override config from an environment variable
app.config.update(dict( app.config.update(
DATABASE=os.path.join(app.root_path, 'flaskr.db'), DATABASE=os.path.join(app.root_path, 'flaskr.db'),
SECRET_KEY='development key', SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/',
USERNAME='admin', USERNAME='admin',
PASSWORD='default' PASSWORD='default'
)) )
app.config.from_envvar('FLASKR_SETTINGS', silent=True) app.config.from_envvar('FLASKR_SETTINGS', silent=True)
In the above code, the :class:`~flask.Config` object works similarly to a In the above code, the :class:`~flask.Config` object works similarly to a
@ -77,7 +77,7 @@ method on the config object and provide it with an import name of a
module. Flask will then initialize the variable from that module. Note module. Flask will then initialize the variable from that module. Note
that in all cases, only variable names that are uppercase are considered. that in all cases, only variable names that are uppercase are considered.
The ``SECRET_KEY`` is needed to keep the client-side sessions secure. The :data:`SECRET_KEY` is needed to keep the client-side sessions secure.
Choose that key wisely and as hard to guess and complex as possible. Choose that key wisely and as hard to guess and complex as possible.
Lastly, add a method that allows for easy connections to the specified Lastly, add a method that allows for easy connections to the specified

2
examples/flaskr/flaskr/factory.py

@ -22,7 +22,7 @@ def create_app(config=None):
app.config.update(dict( app.config.update(dict(
DATABASE=os.path.join(app.root_path, 'flaskr.db'), DATABASE=os.path.join(app.root_path, 'flaskr.db'),
DEBUG=True, DEBUG=True,
SECRET_KEY='development key', SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/',
USERNAME='admin', USERNAME='admin',
PASSWORD='default' PASSWORD='default'
)) ))

2
examples/minitwit/minitwit/minitwit.py

@ -22,7 +22,7 @@ from werkzeug import check_password_hash, generate_password_hash
DATABASE = '/tmp/minitwit.db' DATABASE = '/tmp/minitwit.db'
PER_PAGE = 30 PER_PAGE = 30
DEBUG = True DEBUG = True
SECRET_KEY = 'development key' SECRET_KEY = b'_5#y2L"F4Q8z\n\xec]/'
# create our little application :) # create our little application :)
app = Flask('minitwit') app = Flask('minitwit')

4
flask/app.py

@ -221,11 +221,11 @@ class Flask(_PackageBoundObject):
testing = ConfigAttribute('TESTING') testing = ConfigAttribute('TESTING')
#: If a secret key is set, cryptographic components can use this to #: If a secret key is set, cryptographic components can use this to
#: sign cookies and other things. Set this to a complex random value #: sign cookies and other things. Set this to a complex random value
#: when you want to use the secure cookie for instance. #: when you want to use the secure cookie for instance.
#: #:
#: This attribute can also be configured from the config with the #: This attribute can also be configured from the config with the
#: ``SECRET_KEY`` configuration key. Defaults to ``None``. #: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
secret_key = ConfigAttribute('SECRET_KEY') secret_key = ConfigAttribute('SECRET_KEY')
#: The secure cookie uses this for the name of the session cookie. #: The secure cookie uses this for the name of the session cookie.

7
tests/conftest.py

@ -18,12 +18,7 @@ from flask import Flask as _Flask
class Flask(_Flask): class Flask(_Flask):
testing = True testing = True
secret_key = __name__ secret_key = 'test key'
def make_response(self, rv):
if rv is None:
rv = ''
return super(Flask, self).make_response(rv)
@pytest.fixture @pytest.fixture

2
tests/static/config.json

@ -1,4 +1,4 @@
{ {
"TEST_KEY": "foo", "TEST_KEY": "foo",
"SECRET_KEY": "devkey" "SECRET_KEY": "config"
} }

24
tests/test_basic.py

@ -220,8 +220,6 @@ def test_endpoint_decorator(app, client):
def test_session(app, client): def test_session(app, client):
app.secret_key = 'testkey'
@app.route('/set', methods=['POST']) @app.route('/set', methods=['POST'])
def set(): def set():
flask.session['value'] = flask.request.form['value'] flask.session['value'] = flask.request.form['value']
@ -237,7 +235,6 @@ def test_session(app, client):
def test_session_using_server_name(app, client): def test_session_using_server_name(app, client):
app.config.update( app.config.update(
SECRET_KEY='foo',
SERVER_NAME='example.com' SERVER_NAME='example.com'
) )
@ -253,7 +250,6 @@ def test_session_using_server_name(app, client):
def test_session_using_server_name_and_port(app, client): def test_session_using_server_name_and_port(app, client):
app.config.update( app.config.update(
SECRET_KEY='foo',
SERVER_NAME='example.com:8080' SERVER_NAME='example.com:8080'
) )
@ -269,7 +265,6 @@ def test_session_using_server_name_and_port(app, client):
def test_session_using_server_name_port_and_path(app, client): def test_session_using_server_name_port_and_path(app, client):
app.config.update( app.config.update(
SECRET_KEY='foo',
SERVER_NAME='example.com:8080', SERVER_NAME='example.com:8080',
APPLICATION_ROOT='/foo' APPLICATION_ROOT='/foo'
) )
@ -297,7 +292,6 @@ def test_session_using_application_root(app, client):
app.wsgi_app = PrefixPathMiddleware(app.wsgi_app, '/bar') app.wsgi_app = PrefixPathMiddleware(app.wsgi_app, '/bar')
app.config.update( app.config.update(
SECRET_KEY='foo',
APPLICATION_ROOT='/bar' APPLICATION_ROOT='/bar'
) )
@ -312,7 +306,6 @@ def test_session_using_application_root(app, client):
def test_session_using_session_settings(app, client): def test_session_using_session_settings(app, client):
app.config.update( app.config.update(
SECRET_KEY='foo',
SERVER_NAME='www.example.com:8080', SERVER_NAME='www.example.com:8080',
APPLICATION_ROOT='/test', APPLICATION_ROOT='/test',
SESSION_COOKIE_DOMAIN='.example.com', SESSION_COOKIE_DOMAIN='.example.com',
@ -336,7 +329,6 @@ def test_session_using_session_settings(app, client):
def test_session_localhost_warning(recwarn, app, client): def test_session_localhost_warning(recwarn, app, client):
app.config.update( app.config.update(
SECRET_KEY='testing',
SERVER_NAME='localhost:5000', SERVER_NAME='localhost:5000',
) )
@ -353,7 +345,6 @@ def test_session_localhost_warning(recwarn, app, client):
def test_session_ip_warning(recwarn, app, client): def test_session_ip_warning(recwarn, app, client):
app.config.update( app.config.update(
SECRET_KEY='testing',
SERVER_NAME='127.0.0.1:5000', SERVER_NAME='127.0.0.1:5000',
) )
@ -368,8 +359,8 @@ def test_session_ip_warning(recwarn, app, client):
assert 'cookie domain is an IP' in str(w.message) assert 'cookie domain is an IP' in str(w.message)
def test_missing_session(): def test_missing_session(app):
app = flask.Flask(__name__) app.secret_key = None
def expect_exception(f, *args, **kwargs): def expect_exception(f, *args, **kwargs):
e = pytest.raises(RuntimeError, f, *args, **kwargs) e = pytest.raises(RuntimeError, f, *args, **kwargs)
@ -383,7 +374,6 @@ def test_missing_session():
def test_session_expiration(app, client): def test_session_expiration(app, client):
permanent = True permanent = True
app.secret_key = 'testkey'
@app.route('/') @app.route('/')
def index(): def index():
@ -415,8 +405,6 @@ def test_session_expiration(app, client):
def test_session_stored_last(app, client): def test_session_stored_last(app, client):
app.secret_key = 'development-key'
@app.after_request @app.after_request
def modify_session(response): def modify_session(response):
flask.session['foo'] = 42 flask.session['foo'] = 42
@ -431,7 +419,6 @@ def test_session_stored_last(app, client):
def test_session_special_types(app, client): def test_session_special_types(app, client):
app.secret_key = 'development-key'
now = datetime.utcnow().replace(microsecond=0) now = datetime.utcnow().replace(microsecond=0)
the_uuid = uuid.uuid4() the_uuid = uuid.uuid4()
@ -463,7 +450,6 @@ def test_session_special_types(app, client):
def test_session_cookie_setting(app): def test_session_cookie_setting(app):
app.secret_key = 'dev key'
is_permanent = True is_permanent = True
@app.route('/bump') @app.route('/bump')
@ -505,8 +491,6 @@ def test_session_cookie_setting(app):
def test_session_vary_cookie(app, client): def test_session_vary_cookie(app, client):
app.secret_key = 'testkey'
@app.route('/set') @app.route('/set')
def set_session(): def set_session():
flask.session['test'] = 'test' flask.session['test'] = 'test'
@ -562,8 +546,6 @@ def test_session_vary_cookie(app, client):
def test_flashes(app, req_ctx): def test_flashes(app, req_ctx):
app.secret_key = 'testkey'
assert not flask.session.modified assert not flask.session.modified
flask.flash('Zap') flask.flash('Zap')
flask.session.modified = False flask.session.modified = False
@ -579,8 +561,6 @@ def test_extended_flashing(app):
# in the view functions will cause a 500 response to the test client # in the view functions will cause a 500 response to the test client
# instead of propagating exceptions. # instead of propagating exceptions.
app.secret_key = 'testkey'
@app.route('/') @app.route('/')
def index(): def index():
flask.flash(u'Hello World') flask.flash(u'Hello World')

13
tests/test_config.py

@ -19,11 +19,11 @@ import pytest
# config keys used for the TestConfig # config keys used for the TestConfig
TEST_KEY = 'foo' TEST_KEY = 'foo'
SECRET_KEY = 'devkey' SECRET_KEY = 'config'
def common_object_test(app): def common_object_test(app):
assert app.secret_key == 'devkey' assert app.secret_key == 'config'
assert app.config['TEST_KEY'] == 'foo' assert app.config['TEST_KEY'] == 'foo'
assert 'TestConfig' not in app.config assert 'TestConfig' not in app.config
@ -50,21 +50,21 @@ def test_config_from_json():
def test_config_from_mapping(): def test_config_from_mapping():
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config.from_mapping({ app.config.from_mapping({
'SECRET_KEY': 'devkey', 'SECRET_KEY': 'config',
'TEST_KEY': 'foo' 'TEST_KEY': 'foo'
}) })
common_object_test(app) common_object_test(app)
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config.from_mapping([ app.config.from_mapping([
('SECRET_KEY', 'devkey'), ('SECRET_KEY', 'config'),
('TEST_KEY', 'foo') ('TEST_KEY', 'foo')
]) ])
common_object_test(app) common_object_test(app)
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config.from_mapping( app.config.from_mapping(
SECRET_KEY='devkey', SECRET_KEY='config',
TEST_KEY='foo' TEST_KEY='foo'
) )
common_object_test(app) common_object_test(app)
@ -81,7 +81,8 @@ def test_config_from_class():
TEST_KEY = 'foo' TEST_KEY = 'foo'
class Test(Base): class Test(Base):
SECRET_KEY = 'devkey' SECRET_KEY = 'config'
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config.from_object(Test) app.config.from_object(Test)
common_object_test(app) common_object_test(app)

5
tests/test_signals.py

@ -157,10 +157,7 @@ def test_appcontext_signals():
flask.appcontext_popped.disconnect(record_pop, app) flask.appcontext_popped.disconnect(record_pop, app)
def test_flash_signal(): def test_flash_signal(app):
app = flask.Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
@app.route('/') @app.route('/')
def index(): def index():
flask.flash('This is a flash message', category='notice') flask.flash('This is a flash message', category='notice')

2
tests/test_templating.py

@ -52,8 +52,6 @@ def test_request_less_rendering(app, app_ctx):
def test_standard_context(app, client): def test_standard_context(app, client):
app.secret_key = 'development key'
@app.route('/') @app.route('/')
def index(): def index():
flask.g.foo = 23 flask.g.foo = 23

6
tests/test_testing.py

@ -107,8 +107,6 @@ def test_blueprint_with_subdomain(app, client):
def test_redirect_keep_session(app, client, app_ctx): def test_redirect_keep_session(app, client, app_ctx):
app.secret_key = 'testing'
@app.route('/', methods=['GET', 'POST']) @app.route('/', methods=['GET', 'POST'])
def index(): def index():
if flask.request.method == 'POST': if flask.request.method == 'POST':
@ -139,8 +137,6 @@ def test_redirect_keep_session(app, client, app_ctx):
def test_session_transactions(app, client): def test_session_transactions(app, client):
app.secret_key = 'testing'
@app.route('/') @app.route('/')
def index(): def index():
return text_type(flask.session['foo']) return text_type(flask.session['foo'])
@ -169,8 +165,6 @@ def test_session_transactions_no_null_sessions():
def test_session_transactions_keep_context(app, client, req_ctx): def test_session_transactions_keep_context(app, client, req_ctx):
app.secret_key = 'testing'
rv = client.get('/') rv = client.get('/')
req = flask.request._get_current_object() req = flask.request._get_current_object()
assert req is not None assert req is not None

Loading…
Cancel
Save