developer tip

Flask app.secret_key 이해하기

copycodes 2020. 8. 13. 23:34
반응형

Flask app.secret_key 이해하기


경우 app.secret_key설정되지 않은, 플라스크는 세션 사전을 설정하거나 액세스 할 수 없습니다.

이것이 플라스크 사용자 가이드가 주제에 대해 말하는 전부입니다 .

저는 웹 개발을 처음 접했고 보안 기능이 어떻게 작동하는지 이유를 모릅니다. Flask가 내부적으로 무엇을하는지 이해하고 싶습니다.

  • Flask가이 secret_key속성 을 설정하도록하는 이유는 무엇 입니까?
  • Flask는 secret_key속성을 어떻게 사용 합니까?

암호화가 필요한 모든 것 (공격자에 의한 변조를 방지하기 위해)은 비밀 키를 설정해야합니다. 들어 단지 플라스크 자체, 즉 '아무것도'는 것입니다 Session객체하지만 다른 확장은 동일한 비밀의 사용을 할 수 있습니다.

secret_keySECRET_KEY구성 키에 대해 설정된 값일 뿐이 거나 직접 설정할 수 있습니다.

빠른 시작세션 섹션에는 설정해야하는 서버 측 비밀의 종류에 대한 훌륭하고 건전한 조언이 있습니다.

암호화는 비밀에 의존합니다. 사용할 암호화에 대해 서버 측 비밀을 설정하지 않으면 모든 사람이 암호화를 깰 수 있습니다. 컴퓨터의 암호와 같습니다. 암호와 서명 할 데이터는 암호화 해싱 알고리즘을 사용하여 재생성하기 어려운 값인 서명 문자열을 만드는 데 사용됩니다 . 정확히 동일한 비밀이 있고 원본 데이터가이 값을 다시 생성 할 수있는 경우에만 Flask가 허가없이 변경된 것이 있는지 감지하도록합니다. Flask가 클라이언트에 보내는 데이터에는 비밀이 포함되지 않으므로 클라이언트는 세션 데이터를 조작 할 수 없으며 새롭고 유효한 서명을 생성 할 수 있습니다.

Flask는 itsdangerous라이브러리사용하여 모든 노력을 다합니다. 세션 은 사용자 정의 된 JSON 시리얼 라이저와 함께 itsdangerous.URLSafeTimedSerializer클래스사용합니다 .


아래 답변은 주로 세션 개념을 구현 한 서명 된 쿠키 (웹 애플리케이션에서 사용됨)와 관련이 있습니다. 플라스크 이벤트 모두 정상 (서명) 쿠키 (경유 ) 서명 쿠키 (통해 ). 답변은 두 부분으로 구성됩니다. 첫 번째 부분은 서명 된 쿠키가 생성되는 방법을 설명하고 두 번째 부분은 체계의 다른 측면을 다루는 QA 형식으로 제공됩니다. 예제에 사용 된 구문은 Python3이지만 개념은 이전 버전에도 적용됩니다.request.cookiesresponse.set_cookie()flask.session

무엇입니까 SECRET_KEY(또는 서명 된 쿠키를 만드는 방법)?

쿠키에 서명하는 것은 쿠키 변조에 대한 예방 조치입니다. 쿠키에 서명하는 과정 SECRET_KEY에서는 암호를 해싱하기 전에 "소금"을 사용하여 암호를 엉망으로 만드는 것과 유사한 방식으로 사용됩니다. 여기에 개념에 대한 (엄청난) 단순화 된 설명이 있습니다. 예제의 코드는 설명을위한 것입니다. 많은 단계가 생략되었으며 모든 기능이 실제로 존재하는 것은 아닙니다. 여기서의 목표는 일반적인 아이디어에 대한 이해를 제공하는 것입니다. 실제 구현은 조금 더 복잡합니다. 또한 Flask는 백그라운드에서이 작업의 대부분을 수행합니다. 따라서 쿠키에 값을 설정하고 (세션 API를 통해)를 제공하는 것 외에도 SECRET_KEY이를 직접 다시 구현하는 것이 좋지 않을뿐만 아니라 그렇게 할 필요가 없습니다.

가난한 사람의 쿠키 서명

브라우저에 응답을 보내기 전에 :

(1) 먼저 a SECRET_KEY가 성립됩니다. 응용 프로그램에만 알려야하며 응용 프로그램 다시 시작을 포함하여 응용 프로그램의 수명주기 동안 비교적 일정하게 유지되어야합니다.

# choose a salt, a secret string of bytes
>>> SECRET_KEY = 'my super secret key'.encode('utf8')

(2) 쿠키 생성

>>> cookie = make_cookie(
...     name='_profile', 
...     content='uid=382|membership=regular',
...     ...
...     expires='July 1 2030...'
... )

>>> print(cookie)
name: _profile
content: uid=382|membership=regular...
    ...
    ...
expires: July 1 2030, 1:20:40 AM UTC

(3) 서명을 생성 SECRET_KEY하려면 쿠키 바이트 문자열에를 추가 (또는 앞에 추가) 한 다음 해당 조합에서 해시를 생성합니다.

# encode and salt the cookie, then hash the result
>>> cookie_bytes = str(cookie).encode('utf8')
>>> signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()
>>> print(signature)
7ae0e9e033b5fa53aa....

(4) 이제 content원래 쿠키 필드의 한쪽 끝에 서명을 붙 입니다.

# include signature as part of the cookie
>>> cookie.content = cookie.content + '|' + signature
>>> print(cookie)
name: _profile
content: uid=382|membership=regular|7ae0e9...  <--- signature
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC

이것이 클라이언트에게 전송되는 것입니다.

# add cookie to response
>>> response.set_cookie(cookie)
# send to browser --> 

브라우저에서 쿠키를 수신하면 :

(5) 브라우저가이 쿠키를 다시 서버로 반환하면 쿠키 content필드 에서 서명을 제거 하여 원래 쿠키를 되 찾으십시오.

# Upon receiving the cookie from browser
>>> cookie = request.get_cookie()
# pop the signature out of the cookie
>>> (cookie.content, popped_signature) = cookie.content.rsplit('|', 1)

( 6 ) Use the original cookie with the application's SECRET_KEY to recalculate the signature using the same method as in step 3.

# recalculate signature using SECRET_KEY and original cookie
>>> cookie_bytes = str(cookie).encode('utf8')
>>> calculated_signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()

( 7 ) Compare the calculated result with the signature previously popped out of the just received cookie. If they match, we know that the cookie has not been messed with. But if even just a space has been added to the cookie, the signatures won't match.

# if both signatures match, your cookie has not been modified
>>> good_cookie = popped_signature==calculated_signature

( 8 ) If they don't match then you may respond with any number of actions, log the event, discard the cookie, issue a fresh one, redirect to a login page, etc.

>>> if not good_cookie:
...     security_log(cookie)

Hash-based Message Authentication Code (HMAC)

The type of signature generated above that requires a secret key to ensure the integrity of some contents is called in cryptography a Message Authentication Code or MAC.

I specified earlier that the example above is an oversimplification of that concept and that it wasn't a good idea to implement your own signing. That's because the algorithm used to sign cookies in Flask is called HMAC and is a bit more involved than the above simple step-by-step. The general idea is the same, but due to reasons beyond the scope of this discussion, the series of computations are a tad bit more complex. If you're still interested in crafting a DIY, as it's usually the case, Python has some modules to help you get started :) here's a starting block:

import hmac
import hashlib

def create_signature(secret_key, msg, digestmod=None):
    if digestmod is None:
        digestmod = hashlib.sha1
    mac = hmac.new(secret_key, msg=msg, digestmod=digestmod)
    return mac.digest()

The documentaton for hmac and hashlib.


The "Demystification" of SECRET_KEY :)

What's a "signature" in this context?

It's a method to ensure that some content has not been modified by anyone other than a person or an entity authorized to do so.

One of the simplest forms of signature is the "checksum", which simply verifies that two pieces of data are the same. For example, when installing software from source it's important to first confirm that your copy of the source code is identical to the author's. A common approach to do this is to run the source through a cryptographic hash function and compare the output with the checksum published on the project's home page.

Let's say for instance that you're about to download a project's source in a gzipped file from a web mirror. The SHA1 checksum published on the project's web page is 'eb84e8da7ca23e9f83....'

# so you get the code from the mirror
download https://mirror.example-codedump.com/source_code.tar.gz
# you calculate the hash as instructed
sha1(source_code.tar.gz)
> eb84e8da7c....

Both hashes are the same, you know that you have an identical copy.

What's a cookie?

An extensive discussion on cookies would go beyond the scope of this question. I provide an overview here since a minimal understanding can be useful to have a better understanding of how and why SECRET_KEY is useful. I highly encourage you to follow up with some personal readings on HTTP Cookies.

A common practice in web applications is to use the client (web browser) as a lightweight cache. Cookies are one implementation of this practice. A cookie is typically some data added by the server to an HTTP response by way of its headers. It's kept by the browser which subsequently sends it back to the server when issuing requests, also by way of HTTP headers. The data contained in a cookie can be used to emulate what's called statefulness, the illusion that the server is maintaining an ongoing connection with the client. Only, in this case, instead of a wire to keep the connection "alive", you simply have snapshots of the state of the application after it has handled a client's request. These snapshots are carried back and forth between client and server. Upon receiving a request, the server first reads the content of the cookie to reestablish the context of its conversation with the client. It then handles the request within that context and before returning the response to the client, updates the cookie. The illusion of an ongoing session is thus maintained.

What does a cookie look like?

A typical cookie would look like this:

name: _profile
content: uid=382|status=genie
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC

Cookies are trivial to peruse from any modern browser. On Firefox for example go to Preferences > Privacy > History > remove individual cookies.

The content field is the most relevant to the application. Other fields carry mostly meta instructions to specify various scopes of influence.

Why use cookies at all?

The short answer is performance. Using cookies, minimizes the need to look things up in various data stores (memory caches, files, databases, etc), thus speeding things up on the server application's side. Keep in mind that the bigger the cookie the heavier the payload over the network, so what you save in database lookup on the server you might lose over the network. Consider carefully what to include in your cookies.

Why would cookies need to be signed?

Cookies are used to keep all sorts of information, some of which can be very sensitive. They're also by nature not safe and require that a number of auxiliary precautions be taken to be considered secure in any way for both parties, client and server. Signing cookies specifically addresses the problem that they can be tinkered with in attempts to fool server applications. There are other measures to mitigate other types of vulnerabilities, I encourage you to read up more on cookies.

How can a cookie be tampered with?

Cookies reside on the client in text form and can be edited with no effort. A cookie received by your server application could have been modified for a number of reasons, some of which may not be innocent. Imagine a web application that keeps permission information about its users on cookies and grants privileges based on that information. If the cookie is not tinker-proof, anyone could modify theirs to elevate their status from "role=visitor" to "role=admin" and the application would be none the wiser.

Why is a SECRET_KEY necessary to sign cookies?

Verifying cookies is a tad bit different than verifying source code the way it's described earlier. In the case of the source code, the original author is the trustee and owner of the reference fingerprint (the checksum), which will be kept public. What you don't trust is the source code, but you trust the public signature. So to verify your copy of the source you simply want your calculated hash to match the public hash.

In the case of a cookie however the application doesn't keep track of the signature, it keeps track of its SECRET_KEY. The SECRET_KEY is the reference fingerprint. Cookies travel with a signature that they claim to be legit. Legitimacy here means that the signature was issued by the owner of the cookie, that is the application, and in this case, it's that claim that you don't trust and you need to check the signature for validity. To do that you need to include an element in the signature that is only known to you, that's the SECRET_KEY. Someone may change a cookie, but since they don't have the secret ingredient to properly calculate a valid signature they cannot spoof it. As stated a bit earlier this type of fingerprinting, where on top of the checksum one also provides a secret key, is called a Message Authentication Code.

What about Sessions?

Sessions in their classical implementation are cookies that carry only an ID in the content field, the session_id. The purpose of sessions is exactly the same as signed cookies, i.e. to prevent cookie tampering. Classical sessions have a different approach though. Upon receiving a session cookie the server uses the ID to look up the session data in its own local storage, which could be a database, a file, or sometimes a cache in memory. The session cookie is typically set to expire when the browser is closed. Because of the local storage lookup step, this implementation of sessions typically incurs a performance hit. Signed cookies are becoming a preferred alternative and that's how Flask's sessions are implemented. In other words, Flask sessions are signed cookies, and to use signed cookies in Flask just use its Session API.

Why not also encrypt the cookies?

Sometimes the contents of cookies can be encrypted before also being signed. This is done if they're deemed too sensitive to be visible from the browser (encryption hides the contents). Simply signing cookies however, addresses a different need, one where there's a desire to maintain a degree of visibility and usability to cookies on the browser, while preventing that they'd be meddled with.

What happens if I change the SECRET_KEY?

By changing the SECRET_KEY you're invalidating all cookies signed with the previous key. When the application receives a request with a cookie that was signed with a previous SECRET_KEY, it will try to calculate the signature with the new SECRET_KEY, and both signatures won't match, this cookie and all its data will be rejected, it will be as if the browser is connecting to the server for the first time. Users will be logged out and their old cookie will be forgotten, along with anything stored inside. Note that this is different from the way an expired cookie is handled. An expired cookie may have its lease extended if its signature checks out. An invalid signature just implies a plain invalid cookie.

So unless you want to invalidate all signed cookies, try to keep the SECRET_KEY the same for extended periods.

What's a good SECRET_KEY?

A secret key should be hard to guess. The documentation on Sessions has a good recipe for random key generation:

>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'

You copy the key and paste it in your configuration file as the value of SECRET_KEY.

Short of using a key that was randomly generated, you could use a complex assortment of words, numbers, and symbols, perhaps arranged in a sentence known only to you, encoded in byte form.

Do not set the SECRET_KEY directly with a function that generates a different key each time it's called. For example, don't do this:

# this is not good
SECRET_KEY = random_key_generator()

Each time your application is restarted it will be given a new key, thus invalidating the previous.

Instead, open an interactive python shell and call the function to generate the key, then copy and paste it to the config.

참고URL : https://stackoverflow.com/questions/22463939/demystify-flask-app-secret-key

반응형