[python] 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) 응용 프로그램의 원래 쿠키를 SECRET_KEY사용하여 3 단계와 동일한 방법으로 서명을 다시 계산합니다.

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

(7) 계산 된 결과를 방금받은 쿠키에서 이전에 튀어 나온 서명과 비교합니다. 일치하면 쿠키가 엉망이되지 않은 것입니다. 그러나 쿠키에 공백 만 추가 된 경우에도 서명이 일치하지 않습니다.

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

(8) 일치하지 않는 경우 여러 작업으로 응답하고, 이벤트를 기록하고, 쿠키를 삭제하고, 새 쿠키를 발행하고, 로그인 페이지로 리디렉션하는 등의 작업을 수행 할 수 있습니다.

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

해시 기반 메시지 인증 코드 (HMAC)

일부 콘텐츠의 무결성을 보장하기 위해 비밀 키가 필요한 위에서 생성 된 서명 유형을 암호화에서 메시지 인증 코드 또는 MAC이라고 합니다.

앞서 위의 예는 해당 개념을 지나치게 단순화 한 것이며 자체 서명을 구현하는 것은 좋지 않다고 명시했습니다. 이는 Flask에서 쿠키에 서명하는 데 사용되는 알고리즘을 HMAC 라고 하며 위의 간단한 단계별 절차보다 약간 더 복잡하기 때문입니다. 일반적인 아이디어는 동일하지만이 논의의 범위를 벗어난 이유로 인해 일련의 계산은 조금 더 복잡합니다. 일반적으로 그렇듯이 DIY 제작에 여전히 관심이 있다면 Python에는 시작하는 데 도움이되는 몇 가지 모듈이 있습니다. 🙂 여기에 시작 블록이 있습니다.

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()

hmachashlib에 대한 문서입니다 .


SECRET_KEY🙂 의 “Demystification”

이 맥락에서 “서명”이란 무엇입니까?

이는 권한이있는 사람이나 법인이 아닌 다른 사람이 일부 콘텐츠를 수정하지 않았는지 확인하는 방법입니다.

가장 간단한 형태의 서명 중 하나는 ” 체크섬 “으로, 두 개의 데이터가 동일한 지 간단히 확인합니다. 예를 들어 소스에서 소프트웨어를 설치할 때 먼저 소스 코드 사본이 작성자와 동일한 지 확인하는 것이 중요합니다. 이를 수행하는 일반적인 접근 방식은 암호화 해시 함수를 통해 소스를 실행하고 출력을 프로젝트의 홈 페이지에 게시 된 체크섬과 비교하는 것입니다.

예를 들어 웹 미러에서 gzip 파일로 프로젝트 소스를 다운로드하려고한다고 가정 해 보겠습니다. 프로젝트 웹 페이지에 게시 된 SHA1 체크섬은 ‘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....

두 해시가 동일하며 동일한 사본이 있음을 알고 있습니다.

쿠키 란?

쿠키에 대한 광범위한 논의는이 질문의 범위를 벗어납니다. 최소한의 이해 SECRET_KEY가 유용한 방법과 이유를 더 잘 이해하는 데 유용 할 수 있으므로 여기에 개요를 제공 합니다. HTTP 쿠키에 대한 개인적인 정보를 확인하시기를 강력히 권장합니다.

웹 애플리케이션의 일반적인 관행은 클라이언트 (웹 브라우저)를 경량 캐시로 사용하는 것입니다. 쿠키는이 관행의 한 가지 구현입니다. 쿠키는 일반적으로 서버가 헤더를 통해 HTTP 응답에 추가 한 일부 데이터입니다. 요청을 발행 할 때 HTTP 헤더를 통해 서버로 다시 전송하는 브라우저에 의해 보관됩니다. 쿠키에 포함 된 데이터는 상태 저장 을 에뮬레이션하는 데 사용될 수 있습니다., 서버가 클라이언트와 지속적인 연결을 유지하고 있다는 착각입니다. 이 경우에만 연결을 “활성”상태로 유지하기위한 와이어 대신 클라이언트의 요청을 처리 한 후 응용 프로그램 상태에 대한 스냅 샷이 있습니다. 이러한 스냅 샷은 클라이언트와 서버간에 앞뒤로 전달됩니다. 요청을 받으면 서버는 먼저 쿠키의 내용을 읽어 클라이언트와의 대화 컨텍스트를 다시 설정합니다. 그런 다음 해당 컨텍스트 내에서 요청을 처리하고 클라이언트에 응답을 반환하기 전에 쿠키를 업데이트합니다. 따라서 진행중인 세션의 환상이 유지됩니다.

쿠키는 어떻게 생겼습니까?

일반적인 쿠키는 다음과 같습니다.

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

쿠키는 최신 브라우저에서 쉽게 읽을 수 있습니다. 예를 들어 Firefox에서는 환경 설정> 개인 정보> 기록> 개별 쿠키 제거 로 이동 합니다 .

content필드는 애플리케이션과 가장 관련이 있습니다. 다른 필드는 다양한 영향 범위를 지정하기 위해 대부분 메타 명령을 전달합니다.

왜 쿠키를 사용합니까?

짧은 대답은 성능입니다. 쿠키를 사용하면 다양한 데이터 저장소 (메모리 캐시, 파일, 데이터베이스 등)에서 항목을 조회 할 필요성을 최소화하여 서버 애플리케이션 측에서 작업 속도를 높일 수 있습니다. 쿠키가 클수록 네트워크를 통한 페이로드가 무거워 지므로 서버의 데이터베이스 조회에 저장 한 내용은 네트워크를 통해 손실 될 수 있습니다. 쿠키에 포함 할 내용을 신중하게 고려하십시오.

쿠키에 서명이 필요한 이유는 무엇입니까?

쿠키는 모든 종류의 정보를 보관하는 데 사용되며 일부는 매우 민감 할 수 있습니다. 또한 본질적으로 안전하지 않으며 당사자, 클라이언트 및 서버 모두에 대해 어떤 식 으로든 안전한 것으로 간주되도록 여러 가지 보조 예방 조치를 취해야합니다. 서명 쿠키는 서버 애플리케이션을 속이려는 시도에서 수정할 수있는 문제를 구체적으로 해결합니다. 다른 유형의 취약성을 완화하기위한 다른 조치가 있습니다. 쿠키에 대해 자세히 읽어 보시기 바랍니다.

쿠키는 어떻게 변조 될 수 있습니까?

쿠키는 클라이언트에 텍스트 형식으로 상주하며 쉽게 편집 할 수 있습니다. 서버 응용 프로그램에서받은 쿠키는 여러 가지 이유로 수정되었을 수 있으며, 그중 일부는 무해하지 않을 수 있습니다. 사용자에 대한 권한 정보를 쿠키에 보관하고 해당 정보를 기반으로 권한을 부여하는 웹 애플리케이션을 상상해보십시오. 쿠키가 땜질 방지가되지 않으면 누구나 쿠키를 수정하여 “role = visitor”에서 “role = admin”으로 상태를 올릴 수 있으며 응용 프로그램은 더 현명하지 않습니다.

SECRET_KEY쿠키에 서명해야하는 이유는 무엇 입니까?

쿠키를 확인하는 것은 앞에서 설명한 방식으로 소스 코드를 확인하는 것과 약간 다릅니다. 소스 코드의 경우 원본 작성자는 수탁자이자 참조 지문 (체크섬)의 소유자이며 공개로 유지됩니다. 신뢰하지 않는 것은 소스 코드이지만 공개 서명을 신뢰합니다. 따라서 소스 사본을 확인하려면 계산 된 해시가 공개 해시와 일치하기를 원합니다.

그러나 쿠키의 경우 응용 프로그램은 서명을 추적하지 않고 SECRET_KEY. 는 SECRET_KEY기준 지문이다. 쿠키는 합법적이라고 주장하는 서명과 함께 이동합니다. 여기서 합법성은 서명이 쿠키 소유자, 즉 응용 프로그램에 의해 발급되었음을 의미하며,이 경우 신뢰하지 않으며 서명의 유효성을 확인해야한다는 주장입니다. 그렇게하려면 자신에게만 알려진 서명에 요소를 포함해야합니다 SECRET_KEY. 누군가 쿠키를 변경할 수 있지만 유효한 서명을 올바르게 계산할 수있는 비밀 성분이 없기 때문에 쿠키를 스푸핑 할 수 없습니다. 앞서 언급했듯이이 유형의 지문은 체크섬 위에 비밀 키도 제공합니다.

세션은 어떻습니까?

기존 구현의 세션은 content필드에 ID 만있는 쿠키입니다 session_id. 세션의 목적은 서명 된 쿠키와 정확히 동일합니다. 즉, 쿠키 변조를 방지하기위한 것입니다. 클래식 세션에는 다른 접근 방식이 있습니다. 세션 쿠키를 받으면 서버는 ID를 사용하여 자체 로컬 스토리지 (데이터베이스, 파일 또는 메모리의 캐시 일 수 있음)에서 세션 데이터를 조회합니다. 세션 쿠키는 일반적으로 브라우저가 닫힐 때 만료되도록 설정됩니다. 로컬 스토리지 조회 단계로 인해 이러한 세션 구현은 일반적으로 성능 저하를 발생시킵니다. 서명 된 쿠키가 선호되는 대안이되고 있으며 이것이 바로 Flask의 세션이 구현되는 방식입니다. 즉, Flask 세션 서명 된 쿠키를 사용하고 Flask에서 서명 된 쿠키를 사용하려면 해당 SessionAPI를 사용하면 됩니다.

쿠키도 암호화하지 않는 이유는 무엇입니까?

때때로 쿠키의 내용은 서명 되기 전에 암호화 될 수 있습니다 . 이것은 브라우저에서 볼 수 없을 정도로 민감하다고 판단되는 경우 수행됩니다 (암호화는 내용을 숨 깁니다). 그러나 단순히 쿠키에 서명하는 것은 다른 요구를 해결합니다. 브라우저에서 쿠키에 대한 가시성과 사용성을 어느 정도 유지하면서 간섭을 방지하려는 욕구가 있습니다.

변경하면 어떻게됩니까 SECRET_KEY?

를 변경하면 이전 키로 서명 된 모든 쿠키 SECRET_KEY가 무효화 됩니다. 애플리케이션이 이전으로 서명 된 쿠키가 포함 된 요청을 수신 하면 new으로 서명을 계산하려고 시도 하고 두 서명이 일치하지 않으면이 쿠키와 모든 데이터가 거부됩니다. 브라우저가 처음으로 서버에 연결됩니다. 사용자는 로그 아웃되고 내부에 저장된 모든 항목과 함께 이전 쿠키를 잊게됩니다. 이는 만료 된 쿠키를 처리하는 방식과 다릅니다. 만료 된 쿠키는 서명이 체크 아웃되면 임대가 연장 될 수 있습니다. 유효하지 않은 서명은 일반 유효하지 않은 쿠키를 의미합니다.SECRET_KEYSECRET_KEY

따라서 서명 된 모든 쿠키를 무효화하지 않으려면 SECRET_KEY장기간 동일 하게 유지하십시오 .

좋은게 뭐야 SECRET_KEY?

비밀 키는 추측하기 어렵습니다. 세션에 대한 문서 에는 무작위 키 생성을위한 좋은 방법이 있습니다.

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

키를 복사하여 구성 파일에의 값으로 붙여 넣습니다 SECRET_KEY.

무작위로 생성 된 키를 사용하는 것보다 더 복잡한 단어, 숫자 및 기호를 사용할 수 있으며, 아마도 사용자에게만 알려진 문장으로 배열되어 바이트 형식으로 인코딩됩니다.

하지 을 설정 SECRET_KEY다른 키가 호출 될 때마다 생성하는 기능을 직접. 예를 들어 다음과 같이하지 마십시오.

# this is not good
SECRET_KEY = random_key_generator()

애플리케이션이 다시 시작될 때마다 새 키가 제공되므로 이전 키가 무효화됩니다.

대신 대화 형 Python 셸을 열고 함수를 호출하여 키를 생성 한 다음 복사하여 구성에 붙여 넣습니다.


답변