Werkzeug: Werkzeugκ°€ μ—¬λŸ¬ 쀄 헀더λ₯Ό 잘λͺ» μ²˜λ¦¬ν•¨

에 λ§Œλ“  2017λ…„ 03μ›” 10일  Β·  8μ½”λ©˜νŠΈ  Β·  좜처: pallets/werkzeug

RFC 2616 에 λ”°λ₯΄λ©΄:

HTTP/1.1 헀더 ν•„λ“œ 값은 연속 쀄이 κ³΅λ°±μ΄λ‚˜ κ°€λ‘œ νƒ­μœΌλ‘œ μ‹œμž‘ν•˜λŠ” 경우 μ—¬λŸ¬ μ€„λ‘œ 접을 수 μžˆμŠ΅λ‹ˆλ‹€. μ ‘κΈ°λ₯Ό ν¬ν•¨ν•œ λͺ¨λ“  μ„ ν˜• 곡백은 SP와 λ™μΌν•œ 의미λ₯Ό κ°–μŠ΅λ‹ˆλ‹€. μˆ˜μ‹ μžλŠ” ν•„λ“œ 값을 ν•΄μ„ν•˜κ±°λ‚˜ λ©”μ‹œμ§€ λ‹€μš΄μŠ€νŠΈλ¦Όμ„ μ „λ‹¬ν•˜κΈ° 전에 μ„ ν˜• 곡백을 단일 SP둜 λŒ€μ²΄ν•  수 μžˆμŠ΅λ‹ˆλ‹€(MAY).

κ·ΈλŸ¬λ‚˜ werkzeugλŠ” 이 κ·œμΉ™μ„ μ€€μˆ˜ν•˜λ”λΌλ„ 쀄 λ°”κΏˆμ΄ μžˆλŠ” 헀더 값을 ν—ˆμš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

>>> import werkzeug
>>> werkzeug.Headers().add('foo', 'bar\n baz')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../venv/local/lib/python2.7/site-packages/werkzeug/datastructures.py", line 1136, in add
    self._validate_value(_value)
  File ".../venv/local/lib/python2.7/site-packages/werkzeug/datastructures.py", line 1143, in _validate_value
    raise ValueError('Detected newline in header value.  This is '
ValueError: Detected newline in header value.  This is a potential security problem

λ˜ν•œ 이 μ œν•œμ€ μΌκ΄€λ˜κ²Œ μ μš©λ©λ‹ˆλ‹€.

>>> werkzeug.Headers([('foo', 'bar\n baz')])
Headers([('foo', 'bar\n baz')])

헀더λ₯Ό ν†΅ν•œ ν΄λΌμ΄μ–ΈνŠΈ μΈμ¦μ„œμ˜ nginx 전달과 κ΄€λ ¨λœ ν…ŒμŠ€νŠΈ 사둀λ₯Ό μž‘μ„±ν•˜λ €κ³  ν•  λ•Œ 이 λ¬Έμ œμ— λΆ€λ”ͺμ³€μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ 이λ₯Ό μ μ ˆν•˜κ²Œ μ§€μ›ν•˜κΈ° μœ„ν•œ μ‹€μ œ μ‚¬μš© 사둀가 μžˆμŠ΅λ‹ˆλ‹€.

bug server

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

@davidism 이전 λŒ“κΈ€μ—μ„œ μ–ΈκΈ‰ν–ˆλ“―μ΄ μ‹€μ œλ‘œ μ—¬κΈ°μ—λŠ” 두 가지 버그가 있으며 λ‘˜ λ‹€ ν˜„μž¬ λ§ˆμŠ€ν„° λΈŒλžœμΉ˜μ—μ„œ μˆ˜μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.


첫 번째 λ²„κ·ΈλŠ” werkzeug 개발 μ„œλ²„κ°€ 쀄 λ°”κΏˆλœ 헀더λ₯Ό μ²˜λ¦¬ν•˜λŠ” 방법과 관련이 μžˆμŠ΅λ‹ˆλ‹€. X-Example 헀더 값을 μΈμ‡„ν•˜λŠ” λ‹€μŒ μ„œλ²„ μ½”λ“œλ‘œ μž¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

from werkzeug.serving import run_simple
from werkzeug.wrappers import Request, Response

def app(environ, start_response):
    request = Request(environ)
    print(repr(request.headers.get('X-Example')))
    response = Response(status=204)
    return response(environ, start_response)

run_simple('localhost', 8080, app)

그런 λ‹€μŒ μ—¬λŸ¬ 쀄에 걸친 헀더가 μžˆλŠ” μš”μ²­μ„ 보낼 수 μžˆμŠ΅λ‹ˆλ‹€.

GET / HTTP/1.1
Host: localhost:8080
Connection: close
X-Example: foo
 bar

μ˜ˆμƒ μ„œλ²„ 좜λ ₯:
헀더 값이 ν•œ 쀄에 λ³‘ν•©λ©λ‹ˆλ‹€.

'foo bar'

μ‹€μ œ μ„œλ²„ 좜λ ₯(Python 2):

----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 57361)
Traceback (most recent call last):
  File "/usr/lib/python2.7/SocketServer.py", line 295, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib/python2.7/SocketServer.py", line 321, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib/python2.7/SocketServer.py", line 334, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python2.7/SocketServer.py", line 649, in __init__
    self.handle()
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 320, in handle
    rv = BaseHTTPRequestHandler.handle(self)
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 340, in handle
    self.handle_one_request()
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 355, in handle_one_request
    return self.run_wsgi()
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 238, in run_wsgi
    self.environ = environ = self.make_environ()
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 217, in make_environ
    for key, value in self.get_header_items():
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 441, in get_header_items
    key, value = header[0:-2].split(":", 1)
ValueError: need more than 1 value to unpack
----------------------------------------

μ‹€μ œ μ„œλ²„ 좜λ ₯(Python 3):
헀더 값에 WSGI μ‚¬μ–‘μ—μ„œ ν—ˆμš©ν•˜μ§€ μ•ŠλŠ” 쀄 λ°”κΏˆ λ¬Έμžκ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

'foo\r\n bar'

두 번째 λ²„κ·ΈλŠ” Headers κ°œμ²΄κ°€ 쀄 λ°”κΏˆ 값을 μ²˜λ¦¬ν•˜λŠ” 방법과 관련이 μžˆμŠ΅λ‹ˆλ‹€.

>>> from werkzeug import Headers
>>> h1 = Headers([('X-Example', 'foo\r\n bar')])
>>> h2 = Headers()
>>> h2.add('X-Example', 'foo\r\n bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/.../venv3/lib/python3.6/site-packages/werkzeug/datastructures.py", line 1166, in add
    self._validate_value(_value)
  File "/home/.../venv3/lib/python3.6/site-packages/werkzeug/datastructures.py", line 1173, in _validate_value
    raise ValueError('Detected newline in header value.  This is '
ValueError: Detected newline in header value.  This is a potential security problem

μ˜ˆμƒ κ²°κ³Ό:
ValueError 이든 성곡이든 두 μž‘μ—…μ˜ κ²°κ³ΌλŠ” 동일해야 ν•©λ‹ˆλ‹€.

μ‹€μ œ κ²°κ³Ό:
Headers μƒμ„±μžλŠ” 쀄 λ°”κΏˆμ„ ν—ˆμš©ν•˜λŠ” 반면 Headers.add() ValueError μ‹œν‚΅λ‹ˆλ‹€.

λͺ¨λ“  8 λŒ“κΈ€

HTTP ν—€λ”λŠ” κ°œν–‰μ„ ν—ˆμš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ . μΈμš©ν•˜κ³  μžˆλŠ” μ„Ήμ…˜μ€ μ ‘νžŒ κ°’μ—μ„œ κ°œν–‰μ„ μ œκ±°ν•΄μ•Ό ν•˜λŠ” 접기에 λŒ€ν•΄ μ„€λͺ…ν•©λ‹ˆλ‹€. 이:

"""foo
     bar"""

λ‹€μŒκ³Ό 같이 νŽΌμ³μ Έμ•Ό ν•©λ‹ˆλ‹€.

"foo bar"

κ·Έ 외에도 WerkzeugλŠ” 이 μˆ˜μ€€μ—μ„œ HTTPλ₯Ό ꡬ문 λΆ„μ„ν•˜μ§€ μ•ŠμœΌλ©° 이것이 WSGI μ„œλ²„μ˜ μž‘μ—…μž…λ‹ˆλ‹€. μš”μ²­μ„ ꡬ문 뢄석할 λ•Œ 쀄 λ°”κΏˆμ„ κ±°λΆ€ν•˜λŠ” μœ μΌν•œ μ΄μœ λŠ” λ³΄μ•ˆ 문제λ₯Ό ν¬μ°©ν•˜κΈ° μœ„ν•΄μ„œμž…λ‹ˆλ‹€.

이 티켓은 nginx ν”„λ‘μ‹œ 전달 ν΄λΌμ΄μ–ΈνŠΈ μΈμ¦μ„œ 뒀에 μžˆλŠ” 개발 λͺ¨λ“œμ—μ„œ Flask의 μ‹€μ œ λ™μž‘μ— μ˜ν•΄ 동기가 λΆ€μ—¬λ˜μ—ˆμŠ΅λ‹ˆλ‹€. κ·Έ μ„€μ •μœΌλ‘œ ν—€λ”μ˜ 쀄 λ°”κΏˆμ΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— μ „λ‹¬λ˜λŠ” 것을 κ΄€μ°°ν–ˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ‹¨μœ„ ν…ŒμŠ€νŠΈμ—μ„œ 이것을 λ³΅μ œν•˜λ €κ³  μ‹œλ„ν–ˆμ„ λ•Œ μš”μ²­ 헀더λ₯Ό μž‘μ„±ν•  λ•Œ μœ„μ˜ ValueError μ–»μ—ˆμŠ΅λ‹ˆλ‹€.

이 λ¬Έμ œμ— λŒ€ν•΄ μ’€ 더 μ‘°μ‚¬ν•œ κ²°κ³Ό λ‹€μŒμ„ λ°œκ²¬ν–ˆμŠ΅λ‹ˆλ‹€.

  • HTTP 사양( RFC 2616 )에 λ”°λ₯΄λ©΄ ν—€λ”μ˜ 쀄 λ°”κΏˆμ€ 단일 곡백으둜 λŒ€μ²΄λ  수 μžˆμ§€λ§Œ 보μž₯λ˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€(μœ„μ˜ 인용문 μ°Έμ‘°).

  • WSGIκ°€ ν™•μž₯ν•˜λŠ” CGI 사양( RFC 3875 )μ—μ„œλŠ” μš”μ²­ ν—€λ”μ˜ 쀄 λ°”κΏˆμ„ ꡐ체해야 ν•©λ‹ˆλ‹€.

    μœ μ‚¬ν•˜κ²Œ, μ—¬λŸ¬ 쀄에 걸쳐 μžˆλŠ” 헀더 ν•„λ“œλŠ” λ°˜λ“œμ‹œ ν•œ μ€„λ‘œ λ³‘ν•©λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

  • WSGI 사양( PEP 333 )도 응닡 헀더에 쀄 λ°”κΏˆμ„ κΈˆμ§€ν•©λ‹ˆλ‹€.

    각 header_value μ—λŠ” 캐리지 리턴 λ˜λŠ” 쀄 λ°”κΏˆμ„ ν¬ν•¨ν•˜μ—¬ ν¬ν•¨λ˜κ±°λ‚˜ 끝에 μ œμ–΄ λ¬Έμžκ°€ ν¬ν•¨λ˜μ–΄μ„œλŠ” μ•ˆ λ©λ‹ˆλ‹€.

이것은 여기에 두 가지 버그가 μžˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€.

  • werkzeug 개발 μ„œλ²„λŠ” μš”μ²­ ν—€λ”μ—μ„œ μ ‘νžŒ λ¬Έμžμ—΄μ„ μ˜¬λ°”λ₯΄κ²Œ μ •κ·œν™”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

  • Headers κ°œμ²΄λŠ” 헀더 κ°’μ—μ„œ 쀄 λ°”κΏˆμ„ ν—ˆμš©ν•˜λŠ” 것과 μΌμΉ˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. κ°œν–‰μ€ μƒμ„±μžμ—μ„œ ν—ˆμš©λ˜μ§€λ§Œ add() λ©”μ„œλ“œμ—μ„œλŠ” ν—ˆμš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. BaseResponse μ—μ„œ μ‹€μ œλ‘œ WSGI 응닡을 ꡬ성할 λ•Œ Headers κ°œμ²΄κ°€ ν—ˆμš© μƒνƒœλ₯Ό μœ μ§€ν•˜κ³  μœ νš¨μ„± 검사λ₯Ό μˆ˜ν–‰ν•˜λŠ” 것이 더 λ‚˜μ„ κ²ƒμž…λ‹ˆλ‹€. κ·Έλ ‡κ²Œ ν•˜λ©΄ μƒμ„±μžμ—μ„œ 쀄 λ°”κΏˆμ„ κΈˆμ§€ν•΄λ„ λΉ„μ€€μˆ˜ WSGI μ„œλ²„(예: werkzeug 자체 개발 μ„œλ²„)μ™€μ˜ ν˜Έν™˜μ„±μ΄ μ†μƒλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

그럴 수 μžˆμ§€. 이것과 κ΄€λ ¨λœ #1070도 μžˆμŠ΅λ‹ˆλ‹€.

이것은 #1070에 λŒ€ν•œ μˆ˜μ • μ‚¬ν•­μœΌλ‘œ μˆ˜μ •λœ 것이 ν™•μ‹€ν•©λ‹ˆλ‹€. 그렇지 μ•Šμ€ 경우 μž¬ν˜„ κ°€λŠ₯ν•œ 예λ₯Ό λ“€μ–΄ μ•Œλ €μ£Όμ‹­μ‹œμ˜€.

@davidism 이전 λŒ“κΈ€μ—μ„œ μ–ΈκΈ‰ν–ˆλ“―μ΄ μ‹€μ œλ‘œ μ—¬κΈ°μ—λŠ” 두 가지 버그가 있으며 λ‘˜ λ‹€ ν˜„μž¬ λ§ˆμŠ€ν„° λΈŒλžœμΉ˜μ—μ„œ μˆ˜μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.


첫 번째 λ²„κ·ΈλŠ” werkzeug 개발 μ„œλ²„κ°€ 쀄 λ°”κΏˆλœ 헀더λ₯Ό μ²˜λ¦¬ν•˜λŠ” 방법과 관련이 μžˆμŠ΅λ‹ˆλ‹€. X-Example 헀더 값을 μΈμ‡„ν•˜λŠ” λ‹€μŒ μ„œλ²„ μ½”λ“œλ‘œ μž¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

from werkzeug.serving import run_simple
from werkzeug.wrappers import Request, Response

def app(environ, start_response):
    request = Request(environ)
    print(repr(request.headers.get('X-Example')))
    response = Response(status=204)
    return response(environ, start_response)

run_simple('localhost', 8080, app)

그런 λ‹€μŒ μ—¬λŸ¬ 쀄에 걸친 헀더가 μžˆλŠ” μš”μ²­μ„ 보낼 수 μžˆμŠ΅λ‹ˆλ‹€.

GET / HTTP/1.1
Host: localhost:8080
Connection: close
X-Example: foo
 bar

μ˜ˆμƒ μ„œλ²„ 좜λ ₯:
헀더 값이 ν•œ 쀄에 λ³‘ν•©λ©λ‹ˆλ‹€.

'foo bar'

μ‹€μ œ μ„œλ²„ 좜λ ₯(Python 2):

----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 57361)
Traceback (most recent call last):
  File "/usr/lib/python2.7/SocketServer.py", line 295, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib/python2.7/SocketServer.py", line 321, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib/python2.7/SocketServer.py", line 334, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python2.7/SocketServer.py", line 649, in __init__
    self.handle()
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 320, in handle
    rv = BaseHTTPRequestHandler.handle(self)
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 340, in handle
    self.handle_one_request()
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 355, in handle_one_request
    return self.run_wsgi()
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 238, in run_wsgi
    self.environ = environ = self.make_environ()
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 217, in make_environ
    for key, value in self.get_header_items():
  File "/home/.../venv/local/lib/python2.7/site-packages/werkzeug/serving.py", line 441, in get_header_items
    key, value = header[0:-2].split(":", 1)
ValueError: need more than 1 value to unpack
----------------------------------------

μ‹€μ œ μ„œλ²„ 좜λ ₯(Python 3):
헀더 값에 WSGI μ‚¬μ–‘μ—μ„œ ν—ˆμš©ν•˜μ§€ μ•ŠλŠ” 쀄 λ°”κΏˆ λ¬Έμžκ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

'foo\r\n bar'

두 번째 λ²„κ·ΈλŠ” Headers κ°œμ²΄κ°€ 쀄 λ°”κΏˆ 값을 μ²˜λ¦¬ν•˜λŠ” 방법과 관련이 μžˆμŠ΅λ‹ˆλ‹€.

>>> from werkzeug import Headers
>>> h1 = Headers([('X-Example', 'foo\r\n bar')])
>>> h2 = Headers()
>>> h2.add('X-Example', 'foo\r\n bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/.../venv3/lib/python3.6/site-packages/werkzeug/datastructures.py", line 1166, in add
    self._validate_value(_value)
  File "/home/.../venv3/lib/python3.6/site-packages/werkzeug/datastructures.py", line 1173, in _validate_value
    raise ValueError('Detected newline in header value.  This is '
ValueError: Detected newline in header value.  This is a potential security problem

μ˜ˆμƒ κ²°κ³Ό:
ValueError 이든 성곡이든 두 μž‘μ—…μ˜ κ²°κ³ΌλŠ” 동일해야 ν•©λ‹ˆλ‹€.

μ‹€μ œ κ²°κ³Ό:
Headers μƒμ„±μžλŠ” 쀄 λ°”κΏˆμ„ ν—ˆμš©ν•˜λŠ” 반면 Headers.add() ValueError μ‹œν‚΅λ‹ˆλ‹€.

μ΅œκ·Όμ— nginx ν”„λ‘μ‹œ 뒀에 μžˆλŠ” ν”„λ‘œμ νŠΈ(Flaskκ°€ ν¬ν•¨λœ Python 2.7) 쀑 ν•˜λ‚˜μ—μ„œ ValueError λ³΄μ•˜μŠ΅λ‹ˆλ‹€. κ²°κ΅­ 0.14.1 ( Flask λ²ˆλ“€λ‘œ μ œκ³΅λ˜λŠ” 버전 λ¬΄μ‹œ)둜 λ˜λŒμ•„κ°”κ³  였λ₯˜κ°€ μ‚¬λΌμ‘ŒμŠ΅λ‹ˆλ‹€. 0.15.x λΆ„κΈ°κ°€ 이 문제λ₯Ό λ„μž…ν•œ 것 κ°™κΈ° λ•Œλ¬Έμ— μΆ”κ°€ν•  것이라고 μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€(λ˜λŠ” 잠재적으둜 μš”μ²­ 헀더λ₯Ό μ²˜λ¦¬ν•˜λŠ” 방법에 μƒˆλ‘œμš΄ λ¬Έμ œκ°€ λ°œμƒν•  수 있음).

------μ΅œμ‹  정보-------:

λ‚˜λŠ” μš°λ¦¬κ°€ μ „λ‹¬ν•œ 헀더λ₯Ό μΆ”μ ν–ˆκ³  κ·Έ 쀑 ν•˜λ‚˜λŠ” pem ν˜•μ‹μ˜ μ—¬λŸ¬ 쀄 μΈμ¦μ„œμ˜€μŠ΅λ‹ˆλ‹€.

SSL_CLIENT_CERT: -----BEGIN CERTIFICATE-----
    MIIFHzCCAwegAwIBAgICEDgwDQYJKoZIhvcNAQELBQAwajELMAkGA1UEBhMCdXMx
    GDAWBgNVBAoMD3Uucy4gZ292ZXJubWVudDEPMA0GA1UECwwGcGVvcGxlMQwwCgYD
    VQQLDANkYWUxEDAOBgNVBAsMB2NoaW1lcmExEDAOBgNVBAMMB0ludGVyQ0EwHhcN
    MTcwODMxMTUwMzEwWhcNMjcwODI5MTUwMzEwWjBwMQswCQYDVQQGEwJVUzEYMBYG
    A1UECgwPVS5TLiBHb3Zlcm5tZW50MRAwDgYDVQQLDAdjaGltZXJhMQwwCgYDVQQL
    ....  
    -----END CERTIFICATE-----

nginx μ„œλ²„λŠ” λ‹€μŒκ³Ό 같이 κ΅¬μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

proxy_set_header SSL_CLIENT_CERT $ssl_client_cert;

μš°λ¦¬λŠ” μ•„λ§ˆ μ‚¬μš©ν•΄μ•Όν•©λ‹ˆλ‹€ $ssl_client_escaped_cert λŒ€μ‹  $ssl_client_cert (이 μ–΄μ¨Œλ“ λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ λ•Œλ¬Έμ—). κ·Έ λ³€κ²½μœΌλ‘œ 헀더 ꡬ문 뢄석 λ¬Έμ œκ°€ ν•΄κ²°λ˜λŠ”μ§€ ν™•μ‹€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

이것이이 λ¬Έμ œμ— 직면 ν•œ λ‹€λ₯Έ μ‚¬λžŒμ—κ²Œ λ„μ›€μ΄λ˜κΈ°λ₯Ό λ°”λžλ‹ˆλ‹€. 0.15.1 λŠ” ν˜„μž¬ Python 2.7μ—μ„œ PEM μΈμ¦μ„œμ™€ 같은 μ—¬λŸ¬ 쀄 헀더λ₯Ό μ œλŒ€λ‘œ μ²˜λ¦¬ν•˜μ§€ λͺ»ν•˜λŠ” κ²ƒμœΌλ‘œ λ³΄μž…λ‹ˆλ‹€.

이것은 개발 μ„œλ²„μ˜ 헀더 처리둜 인해 λ‹€μ‹œ 2.7 λ¬Έμ œμž…λ‹ˆλ‹€. μš”μ²­ 헀더에 λŒ€ν•œ 2.7 ν˜Έν™˜μ„± μ½”λ“œμ— 헀더 μ ‘κΈ°λ₯Ό μ²˜λ¦¬ν•˜λŠ” κΈ°λŠ₯을 μΆ”κ°€ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

개발 μ„œλ²„ 버그가 이제 Python 2 및 3μ—μ„œ μˆ˜μ •λ˜μ—ˆμŒμ„ ν™•μΈν–ˆμŠ΅λ‹ˆλ‹€. Headers κ°œμ²΄μ— λŒ€ν•œ 두 번째 λ¬Έμ œλŠ” μ—¬μ „νžˆ μ‘΄μž¬ν•©λ‹ˆλ‹€. #1608을 μ—΄μ—ˆμŠ΅λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰

κ΄€λ ¨ 문제

d42 picture d42  Β·  6μ½”λ©˜νŠΈ

lepture picture lepture  Β·  6μ½”λ©˜νŠΈ

androiddrew picture androiddrew  Β·  14μ½”λ©˜νŠΈ

taion picture taion  Β·  7μ½”λ©˜νŠΈ

KangOl picture KangOl  Β·  16μ½”λ©˜νŠΈ