--ciphers ์ต์
์ ๊ธฐ๋ณธ๊ฐ์ TLSv1
์
๋๋ค.
์ด ๊ฐ์ TLSv1.2์์๋ง ์ฌ์ฉํ ์ ์๋ ์๋กญ๊ณ ๊ฐ๋ ฅํ ์ํธ๋ฅผ ์ ๊ทน์ ์ผ๋ก ๋นํ์ฑํํ๊ธฐ ๋๋ฌธ์ ์๋ชป๋ ๊ธฐ๋ณธ๊ฐ์ ๋๋ค. ํนํ, ์ด ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๊ตฌ์ฑ๋ ์ํธ ์ธํธ์ OWASP์์ A+ ๋ฑ๊ธ์ ๋ฐ์ ์ํธ ์ฌ์ด์๋ ๊ต์ฐจ์ ์ด ์์ต๋๋ค.
>>> import ssl
>>> ctx = ssl.SSLContext()
>>> ctx.set_ciphers('TLSv1')
>>> tlsv1 = {c['name'] for c in ctx.get_ciphers()}
>>> ctx.set_ciphers('DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256') # From OWASP
>>> aplus = {c['name'] for c in ctx.get_ciphers()}
>>> aplus & tlsv1
set()
์ด๋ก ์ธํด ๋์ ๋ณด์ ์ค์ ์ผ๋ก ๊ตฌ์ฑ๋ ํด๋ผ์ด์ธํธ์ ๋ํด OpenSSL NO_SHARED_CIPHER
์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
ํ ๊ฐ์ง ํด๊ฒฐ์ฑ
์ ๊ธฐ๋ณธ๊ฐ์ 'TLSv1:TLSv1.2'
๋ฌธ์์ด๋ก ๋ณ๊ฒฝํ์ฌ ์ธํธ์ TLSv1.2 ์ํธ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์
๋๋ค. ์ด๋ ๊ธฐ์กด gunicorn ์ฌ์ฉ์๋ฅผ ์์์ํค์ง ์๊ณ ์๊ฒฉํ ๋ณด์ ์ค์ ์ผ๋ก ๊ตฌ์ฑ๋ ํด๋ผ์ด์ธํธ์ ๋ํ ํธํ์ฑ์ ์ถ๊ฐํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ ๊ฒ ํ๋ฉด ์งํฉ์ ์ฝํ ์ํธ๊ฐ ๋จ๊ฒ ๋ฉ๋๋ค.
๋ณด๋ค ์์ ํ ์ต์ ์ ์ค๋ช ๋ ํธํ์ฑ ์์ค์ ๊ธฐ๋ฐ์ผ๋ก OWASP ๋ฌธ์์ด ์ค ํ๋๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ ํํ๋ ๊ฒ์ ๋๋ค. ์๋ฅผ ๋ค์ด OWASP Cipher String C ๋๋ C-๋ ์๋ ค์ง ์ฝํ ์ํธ๋ฅผ ๋ฐฐ์ ํ๋ฉด์ ๊ด๋ฒ์ํ ํธํ์ฑ์ ์ ์งํฉ๋๋ค.
๋ ๊ฒฝ์ฐ ๋ชจ๋ OWASP ํ์ด์ง์ ๋ํ ์ฐธ์กฐ ๋งํฌ๋ฅผ ํฌํจํ์ฌ ์์ ์ฌ์ฉ์ ๋ฐ๋ผ ๊ธฐ๋ณธ๊ฐ์ ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๊ต์ฒดํ๋๋ก ๊ถ์ฅํ๋๋ก ์ค๋ช ์๋ฅผ ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ์ ๊ณ ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ด๊ฒ์ ์ ๋์ ์ผ๋ก ์ ์๊ณ ์์ต๋๋ค. Gunicorn์ ํ๋์ SSL ์ง์์ ํฐ ๋ณํ๊ฐ ์์์ต๋๋ค. #1933 ๋ฐ ํด๋น ํ ๋ก ์ ์ฐ๊ฒฐ๋ ๋ฌธ์ ๋ฅผ ์ฐธ์กฐํ์ธ์.
๊ทธ๋์ Gunicorn์ด Python 3.4 ์ด์๋ง ์ง์ํ๋ฏ๋ก ๋ ํฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ๊ฐ์ด ์๋ค๋ฉด pull request๋ฅผ ์ ์ถํด ์ฃผ์๋ฉด ๊ธฐ๊บผ์ด ๋ณํฉํ๊ฒ ์ต๋๋ค. ์ฐ๋ฆฌ๋ ๋ํ ์ต์ ๋ฒ์ ์ ๋์ด๋ ๊ฒ์ ๊ณ ๋ คํ๊ณ ์์ผ๋ฏ๋ก ๋ ์์ ํ ๊ธฐ๋ณธ์ ํ์ฑํํ ์ ์๋ ๋ ๋์ ์ต์ Python ๋ฒ์ ์ด ์๋ ๊ฒฝ์ฐ ๋ค์ ๋ฆด๋ฆฌ์ค ์ ์ ํด๋น ๊ฒฐ์ ์ ๋ด๋ฆฌ๋ ๋ฐ ๋์์ด ๋๋๋ก ํด๋น ์ ๋ณด๋ฅผ ์ฌ๊ธฐ์ ๊ฒ์ํ์ญ์์ค.
์ฌ์ฉ ๊ฐ๋ฅํ ์ํธ(๋ฐ SSLContext.set_ciphers()
์ ๋ํ ์ธ์ ํด์)๋ Python ๋ฒ์ ์ ์ํฅ์ ๋ฐ์ง ์์ง๋ง Python์ด ๋น๋ํ๋ OpenSSL/LibreSSL ๋ฒ์ ์ ์ํฅ์ ๋ฐ์ต๋๋ค. Linux์์๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฐฐํฌํ์์ ์ ๊ณตํ๋ ๋ฒ์ ์
๋๋ค.
๊ทํ์ ์ง๋ฌธ์ด "Python 3.4 ์ด์์์ ํญ์ ์๋ํ๋ ๋ณด๋ค ์์ ํ ๊ธฐ๋ณธ๊ฐ์ ์ค์ ํ ์ ์์ต๋๊น?"๋ผ๋ฉด ์๊ฒฉํ ๋๋ต์ "์๋์ค"์ ๋๋ค. ์ด๋ Python์ ์ปดํ์ผํ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋๋ค. ๊ฐ๋ ฅํ ์ํธ๊ฐ ์๋ ์์ฃผ ์ค๋๋ OpenSSL์ ๋ํด ์ต์ Python์ ์ปดํ์ผํ๋ ๊ฒ์ด ๊ฐ๋ฅํ ์ ์์ผ๋ฏ๋ก gunicorn์ ๊ฐ๋ ฅํ ์ํธ๊ฐ ํ์ํ๋ฉด SSL์ด ์ ํ ์๋ํ์ง ์์ ์ ์์ต๋๋ค.
ํ์ง๋ง ์ฐ๋ฆฌ๋ ๊ฝค ์์ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. Python 3.4๋ 2014๋ ์ ์ถ์๋์์ผ๋ฉฐ TLSv1.2๋ฅผ ์ถ๊ฐํ OpenSSL 1.0.1a๋ 2012๋ 4์์ ์ถ์๋์์ต๋๋ค. ๋ฐ๋ผ์ Python์ ๋ฐฐํฌํ ๋ฒ์ ์๋ ๊ฐ๋ ฅํ ์ํธ๊ฐ ์์ ๊ฒ์ ๋๋ค. ๋ค๋ฅธ ํ๋๋ ๊ฐ Python ๋ฆด๋ฆฌ์ค์๋ ํน์ OpenSSL ๋ฒ์ ์ด ํ์ํ์ง๋ง(์: Python 3.7์๋ OpenSSL 1.0.2๊ฐ ํ์ํฉ๋๋ค), ์ ํํ ์ด๋ค Python ๋ฒ์ ์ ๋ฌด์์ด ํ์ํ์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
์ ๋ฐ์ ์ผ๋ก ๋๋ OWASP์ ์๋ด๋ฅผ ๋ฐ์์ผ ํ ๊ฒ์ ๋๋ค. ๊ทธ๋ค์ C-๊ฐ "์ค์ ์ค๋๋ ๋ธ๋ผ์ฐ์ ๋ฐ ๋ ๊ฑฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ๊ฐ์ฅ ๊ด๋ฒ์ํ ํธํ์ฑ"์ธ ๋ ๊ฑฐ์๋ผ๊ณ ๋งํฉ๋๋ค. ์์ค๋ก ์ธ์ฉํ ์ ์๋ค๋ ์ถ๊ฐ ๋ณด๋์ค๋ ์์ต๋๋ค.
๋ํ Python์๋ ์์ฒด ๊ธฐ๋ณธ ์ํธ ๋ชฉ๋ก์ด ์์ต๋๋ค. OpenSSL์ ๊ธฐ๋ณธ๊ฐ( DEFAULT:!aNULL:!eNULL
์์ด ๋ถ๋ช
ํจ)์ผ๋ก ์ ๋ ํด๋ฐฑํ์ง ์์ต๋๋ค. ๋ด๋ถ/๋ฌธ์ํ๋์ง ์์์ง๋ง ssl._DEFAULT_CIPHERS
๋ก ์ก์ธ์คํ ์ ์์ผ๋ฏ๋ก ๊ธฐ๋ณธ๊ฐ์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ SSLContext์์ set_ciphers()๋ฅผ ํธ์ถํ์ง ์๋ ๊ฒ์
๋๋ค.
Python 3.6์ ๊ฒฝ์ฐ _DEFAULT_CIPHERS
๋
'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!3DES'
ํ์ด์ฌ 3.7์์๋
'DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK'
์ ์ฃผ์์ด ๋งํ๋ "DEFAULT :. OpenSSL์์ ๊ธฐ๋ณธ ์ํธ ๋ชฉ๋ก์ 1.0.2 ์ดํ ๋ชฉ๋ก ํฉ๋ฆฌ์ ์ธ ์์์ ๋๋ค."
์ด๋ฌํ ์ค์ ์ OWASP์ ๋์ผํ ์ ์ ์ผ๋ก ๋งค์ฐ ์๊ฒฉํด ๋ณด์ ๋๋ค.
์๋ฒ์์ ์ฌ์ฉํ๊ธฐ ์ํ _RESTRICTED_SERVER_CIPHERS
์์ผ๋ฉฐ(gunicorn์ ์ ํฉ) ์ผ๋ถ Python ๋ฒ์ ์์๋ _DEFAULT_CIPHERS
๋ณด๋ค ๋ ๋นก๋นกํ์ง๋ง ๋ด๋ถ์ฉ์ด๋ฉฐ ์ด๋์๋ ์ฌ์ฉ๋์ง ์์ต๋๋ค. ์ต์ 3.4 ์ดํ๋ก ์ ์ง๋ฉ๋๋ค.
๋ฐ๋ผ์ ์ต์ 3์ Python์ ๊ธฐ๋ณธ ์ํธ ์ ํ๊ตฐ์ ๋ํ ๊ธฐ๋ณธ๊ฐ์ ๋๋ค.
๊ทธ๋ ๊ฒ ํ์ง ์๋ ์ ์ผํ ์ด์ ๋ ์ด์ Python ๋ฒ์ ๋ณด๋ค ๋ ์์ ํ ๋ชฉ๋ก์ ์ค๋ ๋ฐฐ์กํ ์ ์๋ค๊ณ ์๊ฐํ๊ฑฐ๋ ๋ ์๊ฒฉํ OWASP ์์ค ์ค ํ๋๋ฅผ ์ ํํ๋ ค๋ ๊ฒฝ์ฐ์ ๋๋ค. ์์งํ ๋๋ฌด ๋ฏธ๋ฏธํฉ๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๋ํ Python์๋ ์์ฒด ๊ธฐ๋ณธ ์ํธ ๋ชฉ๋ก์ด ์์ต๋๋ค. OpenSSL์ ๊ธฐ๋ณธ๊ฐ(
DEFAULT:!aNULL:!eNULL
์์ด ๋ถ๋ช ํจ)์ผ๋ก ์ ๋ ํด๋ฐฑํ์ง ์์ต๋๋ค. ๋ด๋ถ/๋ฌธ์ํ๋์ง ์์์ง๋งssl._DEFAULT_CIPHERS
๋ก ์ก์ธ์คํ ์ ์์ผ๋ฏ๋ก ๊ธฐ๋ณธ๊ฐ์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ SSLContext์์ set_ciphers()๋ฅผ ํธ์ถํ์ง ์๋ ๊ฒ์ ๋๋ค.Python 3.6์ ๊ฒฝ์ฐ
_DEFAULT_CIPHERS
๋ํ์ด์ฌ 3.7์์๋
์ ์ฃผ์์ด ๋งํ๋ "DEFAULT :. OpenSSL์์ ๊ธฐ๋ณธ ์ํธ ๋ชฉ๋ก์ 1.0.2 ์ดํ ๋ชฉ๋ก ํฉ๋ฆฌ์ ์ธ ์์์ ๋๋ค."
์ด๋ฌํ ์ค์ ์ OWASP์ ๋์ผํ ์ ์ ์ผ๋ก ๋งค์ฐ ์๊ฒฉํด ๋ณด์ ๋๋ค.
์๋ฒ์์ ์ฌ์ฉํ๊ธฐ ์ํ
_RESTRICTED_SERVER_CIPHERS
์์ผ๋ฉฐ(gunicorn์ ์ ํฉ) ์ผ๋ถ Python ๋ฒ์ ์์๋_DEFAULT_CIPHERS
๋ณด๋ค ๋ ๋นก๋นกํ์ง๋ง ๋ด๋ถ์ฉ์ด๋ฉฐ ์ด๋์๋ ์ฌ์ฉ๋์ง ์์ต๋๋ค. ์ต์ 3.4 ์ดํ๋ก ์ ์ง๋ฉ๋๋ค.๋ฐ๋ผ์ ์ต์ 3์ Python์ ๊ธฐ๋ณธ ์ํธ ์ ํ๊ตฐ์ ๋ํ ๊ธฐ๋ณธ๊ฐ์ ๋๋ค.
๊ทธ๋ ๊ฒ ํ์ง ์๋ ์ ์ผํ ์ด์ ๋ ์ด์ Python ๋ฒ์ ๋ณด๋ค ๋ ์์ ํ ๋ชฉ๋ก์ ์ค๋ ๋ฐฐ์กํ ์ ์๋ค๊ณ ์๊ฐํ๊ฑฐ๋ ๋ ์๊ฒฉํ OWASP ์์ค ์ค ํ๋๋ฅผ ์ ํํ๋ ค๋ ๊ฒฝ์ฐ์ ๋๋ค. ์์งํ ๋๋ฌด ๋ฏธ๋ฏธํฉ๋๋ค.