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 μ λ¬κ³Ό κ΄λ ¨λ ν μ€νΈ μ¬λ‘λ₯Ό μμ±νλ €κ³ ν λ μ΄ λ¬Έμ μ λΆλͺμ³€μ΅λλ€. λ°λΌμ μ΄λ₯Ό μ μ νκ² μ§μνκΈ° μν μ€μ μ¬μ© μ¬λ‘κ° μμ΅λλ€.
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μ μ΄μμ΅λλ€.
κ°μ₯ μ μ©ν λκΈ
@davidism μ΄μ λκΈμμ μΈκΈνλ―μ΄ μ€μ λ‘ μ¬κΈ°μλ λ κ°μ§ λ²κ·Έκ° μμΌλ©° λ λ€ νμ¬ λ§μ€ν° λΈλμΉμμ μμ λμ§ μμμ΅λλ€.
첫 λ²μ§Έ λ²κ·Έλ werkzeug κ°λ° μλ²κ° μ€ λ°κΏλ ν€λλ₯Ό μ²λ¦¬νλ λ°©λ²κ³Ό κ΄λ ¨μ΄ μμ΅λλ€.
X-Example
ν€λ κ°μ μΈμνλ λ€μ μλ² μ½λλ‘ μ¬νν μ μμ΅λλ€.κ·Έλ° λ€μ μ¬λ¬ μ€μ κ±ΈμΉ ν€λκ° μλ μμ²μ λ³΄λΌ μ μμ΅λλ€.
μμ μλ² μΆλ ₯:
ν€λ κ°μ΄ ν μ€μ λ³ν©λ©λλ€.
μ€μ μλ² μΆλ ₯(Python 2):
μ€μ μλ² μΆλ ₯(Python 3):
ν€λ κ°μ WSGI μ¬μμμ νμ©νμ§ μλ μ€ λ°κΏ λ¬Έμκ° ν¬ν¨λμ΄ μμ΅λλ€.
λ λ²μ§Έ λ²κ·Έλ
Headers
κ°μ²΄κ° μ€ λ°κΏ κ°μ μ²λ¦¬νλ λ°©λ²κ³Ό κ΄λ ¨μ΄ μμ΅λλ€.μμ κ²°κ³Ό:
ValueError
μ΄λ μ±κ³΅μ΄λ λ μμ μ κ²°κ³Όλ λμΌν΄μΌ ν©λλ€.μ€μ κ²°κ³Ό:
Headers
μμ±μλ μ€ λ°κΏμ νμ©νλ λ°λ©΄Headers.add()
ValueError
μν΅λλ€.