PEP 466 – Python 2.7.x를 위한 네트워크 보안 개선
- Author:
- Alyssa Coghlan <ncoghlan at gmail.com>
- Status:
- Final
- Type:
- Standards Track
- Created:
- 23-Mar-2014
- Python-Version:
- 2.7.9
- Post-History:
- 23-Mar-2014, 24-Mar-2014, 25-Mar-2014, 26-Mar-2014, 16-Apr-2014
- Resolution:
- Python-Dev message
Table of Contents
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
대부분의 CPython 트래커 이슈는 동작상의 오류 또는 개선 제안으로 분류됩니다. 동작상의 오류를 수정하는 패치는 대부분 현재 유지보수 중인 모든 브랜치에 적용됩니다. 개선 패치는 다음 Python 버전이 될 기본 브랜치에만 적용됩니다.
이러한 주기는 Python의 일반적인 18~24개월 기능 릴리스 주기에서는 상당히 잘 작동하며, 이 주기는 Python 3 시리즈에 여전히 적용됩니다. 그러나 Python 2의 표준 라이브러리는 이제 네트워크 보안 프로토콜의 최신 기술 수준에서 크게 뒤처질 만큼 오래되었고, 이 때문에 가까운 시일 내에 Python 3으로 업그레이드하기 어려울 수 있는 사용 사례에서 실제 문제가 발생하고 있습니다.
Python 2.7의 4년 이상에 걸친 유지보수 주기 동안 생겨난 추가적인 현실적 고려 사항을 반영하여, 이 PEP는 네트워크 보안과 관련된 핵심 기능들을 Python 3.4에서 향후 Python 2.7.x 유지보수 릴리스로 백포트하는 것을 허용합니다.
이 PEP는 더 이상 활발히 유지보수되지 않는 보안 수정 전용 브랜치에 대한 핵심 개발팀의 처리 방식은 변경하지 않지만, Python 표준 라이브러리에 대해 연장된 지원 기간을 제공하는 상용 재배포자에게 이러한 기능을 자신이 지원하는 버전으로 백포트하거나, 그렇지 않으면 공용 인터넷에 직접 연결하는 역할에 이전 버전을 사용하는 것은 지원하지 않는다고 명시적으로 밝힐 것을 권고하기는 합니다.
Python 2.7 유지보수 릴리스의 새로운 보안 관련 기능
이 제안에 따라 다음 기능들이 Python 3.4에서 향후 Python 2.7.x 유지보수 릴리스로 백포트됩니다:
os모듈에서:os.urandom()을 위한 영구 파일 디스크립터.
hmac모듈에서:- 상수 시간 비교 함수(
hmac.compare_digest()).
- 상수 시간 비교 함수(
hashlib모듈에서:- 비밀번호 해싱 함수(
hashlib.pbkdf2_hmac()). - 해시 알고리즘 사용 가능 여부에 대한 세부 정보(
hashlib.algorithms_guaranteed및hashlib.algorithms_available).
- 비밀번호 해싱 함수(
ssl모듈에서:- 이 모듈은 Python 3의 대응 모듈과 거의 완전히 동기화되어, TLSv1.x 설정, SSLContext 조작, 서버 이름 표시(Server Name Indication), 플랫폼 인증서 저장소 접근, 피어 호스트 이름 검증에 대한 표준 라이브러리 지원 등을 Python 2 시리즈에 제공합니다.
- 이 정책에 따라 백포트되지 않는 유일한
ssl모듈 기능은 OpenSSL의 난수 생성 기능에 대한 접근을 제공하는ssl.RAND_*함수들입니다 - 대신os.urandom()을 사용하십시오.
유지보수 정책의 일반적인 변경 사항으로서, Python 2.7의 새 유지보수 릴리스용 바이너리 설치 프로그램을 준비할 때 OpenSSL의 더 새로운 기능 릴리스로 업그레이드하는 것도 허용됩니다.
이 PEP는 Python 2.7에 새 기능을 백포트하는 것에 대한 일반적인 예외를 제안하지 않습니다. 백포트가 제안되는 모든 새 기능은 여전히 개별적으로 그 타당성을 입증해야 합니다. 특히, Python 패키지 색인에서 독립적으로 업데이트되는 백포트에 의존하는 것이 왜 허용 가능한 해결책이 아닌지 설명해야 합니다.
구현 현황
이 PEP는 원래 나열된 모든 기능을 Python 2.7.7 유지보수 릴리스에 추가할 것을 제안했습니다. 그러나 PEP의 최초 작성 및 승인부터 Python 2.7.7rc1 릴리스까지의 기간이 짧았기 때문에 이 접근 방식은 지나치게 야심 찬 것으로 드러났습니다. 대신, 승인된 각 기능 백포트의 진행 상황은 Python 2.7을 대상으로 하는 독립적인 개선 사항으로 추적되고 있습니다.
Python 2.7.7에 구현됨:
- Issue #21306:
hmac.compare_digest백포트 - Issue #21462: Python 2.7 Windows 설치 프로그램의 OpenSSL 업그레이드
Python 2.7.8에 구현됨:
- Issue #21304:
hashlib.pbkdf2백포트
Python 2.7.9(개발 중)에 구현되었습니다:
- Issue #21308: 지정된
ssl모듈 기능 백포트 - Issue #21307: 지정된
hashlib모듈 기능 중 나머지 백포트 - Issue #21305:
os.urandom공유 파일 디스크립터 변경 사항 백포트
하위 호환성 고려 사항
Python 3 시리즈에서와 마찬가지로, 백포트된 ssl.create_default_context() API에는 하위 호환성 예외가 부여됩니다. 이 예외에 따라 유지보수 릴리스에서는 생성된 SSL 컨텍스트의 프로토콜, 옵션, 암호화 방식 및 기타 설정을 더 높은 기본 보안 설정으로 갱신할 수 있습니다. 이로써 원래 기능 릴리스 시점이 아니라 유지보수 릴리스 시점을 기준으로 호환성과 보안 사이의 균형을 적절히 맞출 수 있습니다.
이 PEP는 유지보수 릴리스에 대한 통상적인 하위 호환성 정책에 그 밖의 예외를 부여하지 않습니다. 대신 기능 기반 검사의 사용을 명시적으로 권장함으로써, 버전 간에 호환되면서도 더 안전한 Python 소프트웨어를 쉽게 작성할 수 있도록 하는 동시에, 새로운 Python 2.7 유지보수 릴리스로 업그레이드할 때 현재 잘 동작하는 소프트웨어가 망가질 위험은 계속 제한하도록 설계되었습니다.
이 제안이 새 기능을 Python 2.7 릴리스 시리즈로 백포트하도록 허용하는 모든 경우에, Python 버전을 명시적으로 확인할 필요 없이 “기능 탐지”(예를 들어, 모듈에 특정 속성이 있는지 확인하는 것)로 동작하는 버전 간 호환 코드를 작성할 수 있습니다.
그러면 원하는 기능이 없는 것으로 확인되었을 때 적절한 경고와 대체 동작을 제공하는 일은 라이브러리와 프레임워크 코드의 몫이 됩니다. 보안에 특히 민감한 일부 소프트웨어는 원하는 보안 기능을 사용할 수 없을 때 곧바로 실패해도 되지만(MAY), 대부분의 소프트웨어는 그 대신 경고를 내보내고 보안 수준이 약간 낮아진 구성으로 계속 동작해야 합니다(SHOULD).
백포트된 API를 사용하면 라이브러리와 애플리케이션 코드는 관련 네트워크 보안 기능이 있는지 감지한 뒤 다음 작업을 수행할 수 있습니다:
- 더 안전한 설정을 명시적으로 선택합니다(기본 동작의 보안 수준이 더 낮은 이전 Python 유지보수 릴리스에서도 강화된 보안 기능을 사용할 수 있도록 하기 위함입니다)
- 덜 안전한 설정을 명시적으로 선택합니다(보안 수준이 더 낮은 환경에서도 더 새로운 Python 기능 릴리스를 사용할 수 있도록 하기 위함입니다)
- 해당 기능의 기본 설정을 확인합니다(Python 기능 릴리스를 판별하려면 Python 버전을 명시적으로 확인해야 할 수도 있지만(MAY), 특정 유지보수 릴리스까지 확인할 필요는 없습니다(DOES NOT))
다른 모듈(예를 들어 더 높은 수준의 네트워킹 라이브러리와 데이터 형식 처리 라이브러리)의 보안 관련 변경 사항은 앞으로도 Python 패키지 색인에서 백포트와 새 모듈 형태로 제공됩니다. 변화하는 개발 요구 사항에 맞춰 Python 2 표준 라이브러리와 무관하게 계속 발전해야 하는 소프트웨어는 여전히 독립 배포 방식으로 다루는 것이 바람직하기 때문입니다. 보안 네트워킹 인프라를 특별히 고려할 가치가 있게 만드는 특성에 대한 검토는 Motivation and Rationale 절을 참조하십시오.
OpenSSL 호환성
이 제안에 따라 Python 2.7 유지보수 릴리스에서 OpenSSL을 더 최신 기능 릴리스로 업그레이드할 수 있습니다. Linux 및 대부분의 다른 POSIX 시스템에서는 CPython이 기본적으로 시스템이 제공하는 OpenSSL 라이브러리에 동적으로 링크하므로, 사용되는 OpenSSL의 구체적인 버전이 이미 제각각입니다.
Windows 바이너리 설치 프로그램의 경우, _ssl 및 _hashlib 모듈은 OpenSSL과 정적으로 링크되며 관련 심볼은 외부로 내보내지지 않습니다. Marc-Andre Lemburg에 따르면, egenix-pyopenssl 바이너리에서 OpenSSL을 더 새로운 릴리스로 업데이트했을 때 보고된 호환성 문제는 없었습니다 [3]
Mac OS X 바이너리 설치 프로그램은 지금까지 다른 POSIX 설치 환경과 같은 정책을 따라 Apple이 제공하는 OpenSSL 라이브러리에 동적으로 링크했습니다. 그러나 Apple은 이제 이러한 크로스 플랫폼 라이브러리의 업데이트를 중단했으며, 대신 크로스 플랫폼 개발자라도 Apple 플랫폼에서 최신 보안 인프라를 사용하려면 Mac OS X 전용 인터페이스를 채택하도록 요구하고 있습니다. 이에 따라 이 PEP와는 별개로, Mac OS X 바이너리 설치 프로그램은 이미 더 새로운 버전의 OpenSSL을 정적으로 링크하는 방식으로 전환될 예정이었습니다 [4]
기타 고려 사항
유지 보수성
Alex Gaynor와 Donald Stufft를 비롯한 여러 개발자가 이 정책에 해당하는 기능 백포트를 수행하고, 그 결과 Python 2 시리즈에서 생기는 추가 유지보수 부담을 함께 지겠다는 뜻을 밝혔습니다.
Steve Dower와 Brian Curtin이 Windows 설치 프로그램 제작을 돕겠다고 나섰으므로, Martin von Löwis는 2.7 Windows 설치 프로그램을 유지 관리하는 일에서 물러날 수 있게 되었습니다.
이 PEP의 주된 목적은 그들이 이 작업을 수행할 수 있도록 하는 데 필요한 합의를 이루는 것입니다. 다른 코어 개발자에게는 이 정책 변경으로 인한 추가 부담이 없어야 합니다. 다만 영향을 받는 모듈에 특별히 관심이 있는 개발자라면 그 결과로 나오는 패치를 검토할 수는 있습니다.
보안 릴리스
이 PEP는 보안 릴리스 처리 방식을 바꾸자고 제안하지 않습니다. 보안 릴리스는 앞으로도 중대한 보안 수정만 포함하는 소스 전용 릴리스로 유지됩니다.
다만 라이브러리 개발자와 애플리케이션 개발자를 위한 권고 사항은 상업 재배포자도 수용할 수 있도록 의도적으로 설계되었습니다. 이는 보안 수정 전용 모드에 있거나 코어 개발 팀이 “지원 종료(end of life)”를 선언한 다른 Python 릴리스 시리즈에도 이 변경 사항을 적용하기로 선택하는 재배포자를 위한 것입니다.
재배포자가 그 선택지를 실제로 사용할지는 각 재배포자가 결정합니다.
통합 테스트
서드파티 통합 테스트 서비스는 사용자가 여러 Python 2.7 유지보수 릴리스(최소한 2.7.6과 2.7.7 이상)를 대상으로 테스트할 수 있는 기능을 제공해야 합니다. 그래야 이 제안에서 다루는 기능이 Python 2.7 시리즈에 백포트된 뒤에도 라이브러리, 프레임워크, 애플리케이션이 레거시 보안 인프라를 올바르게 처리하는지(소프트웨어의 보안 민감도에 따라 실패하거나 우아하게 기능을 낮추는지) 계속 테스트할 수 있습니다.
위험 허용도가 낮은 저보안 환경 처리
좋든 나쁘든(대개는 나쁜 쪽으로), 유지보수 릴리스에서 회귀가 생길 위험이 조금만 커져도 받아들이지 못하면서 잠재적인 보안 결함의 위험은 더 쉽게 용인하는 환경이 있습니다. 이 제안은 예외 대상 모듈에 관해서는 이러한 환경을 대체로 고려하지 않습니다. 그런 접근 방식은 공용 인터넷에 연결된 소프트웨어에는 전혀 적절하지 않으며, 심층 방어 보안 원칙에 따르면 대부분의 사설 네트워크에도 적절하지 않습니다.
다운스트림 재배포자는 여전히 그런 환경을 지원하기로 선택할 수 있습니다. 다만 그 경우 보안 관련 모듈을 다운그레이드하는 과정과 이에 따른 회귀 테스트는 직접 처리해야 합니다. 주 CPython 지속적 통합 인프라는 이 시나리오를 다루지 않습니다.
동기와 근거
이 PEP를 작성한 주된 계기는 Python 2 시리즈의 SSL 지원이 노후화되었다는 점입니다. 2014년 3월 기준으로 Python 2.7 SSL 모듈은 나온 지 4년 가까이 되었고, 여전히 널리 쓰이는 Python 2.6 릴리스의 SSL 지원은 6년 전에 기능이 고정되었습니다.
이들은 공용 인터넷에서 동작하는 보안 네트워킹 소프트웨어의 기반으로 떳떳하게 권장하기에는 너무 오래되었습니다. 지능형 지속 보안 위협이 이전에 알려진 것보다 훨씬 더 널리 퍼져 있고 공격 대상도 더 가리지 않는다는 사실이 점점 분명해지고 있는 지금은 더욱 그렇습니다. 이들은 당시에는 합리적인 보안 인프라였지만, 이후 기술 수준이 발전했습니다. 따라서 어떤 이유로든 현재 Python 3으로 옮길 수 없는 사용자에게 더 최신의 네트워크 보안 인프라를 효과적으로 제공할 방법을 찾아야 합니다.
Linux 플랫폼에서는 시스템에 설치된 OpenSSL을 사용하면 이런 우려의 상당수가 해결되지만, 전부 해결되지는 않습니다(특히 소프트웨어가 더 높은 수준의 보안 설정을 명시적으로 요구하기는 여전히 어렵습니다). PyOpenSSL이나 Pycurl 같은 서드파티 라이브러리를 사용하면 표준 라이브러리 지원을 우회할 수 있습니다. 하지만 이런 라이브러리는 의존성으로 배포하기 까다로울 수 있고, 많은 사용자는 자신에게 이런 라이브러리가 필요할 수 있다는 사실조차 모르기 때문에 보안 문제는 여전히 남습니다. 경험이 부족할 수 있는 사용자에게 이런 라이브러리를 구하고 사용하는 방법을 설명하는 것보다 기본 포함된 배터리(included batteries)를 고치는 편이 낫다고 판단합니다.
python.org에 게시되는 Windows용 및 Mac OS X용 바이너리 설치 프로그램의 경우, 사용할 OpenSSL 버전은 전적으로 Python 코어 개발 팀이 결정합니다. 그러나 현재는 해당 Python 기능 릴리스에 처음 포함되어 배포된 OpenSSL 버전의 유지보수 릴리스로만 제한됩니다.
인기가 높아지면 책임도 커집니다. 이 제안은 Python의 인기와 채택률이 충분히 높아져서 우리의 설계 결정과 정책 결정 중 일부가 Python 개발 커뮤니티 밖에까지 큰 영향을 미친다는 사실을 인정하고자 합니다.
한 예로, Python 2 ssl 모듈은 Server Name Indication 표준을 지원하지 않습니다. 서드파티 requests 클라이언트 라이브러리를 사용하면 SNI 지원을 얻을 수 있습니다. 하지만 현재 실제로 그렇게 하려면 requests와 거기에 내장된 의존성뿐 아니라 추가 라이브러리를 여섯 개 이상 더 사용해야 합니다. Python 2 클라이언트는 SNI를 제대로 처리하지 못하는 경우가 많습니다. 이처럼 Python 2 시리즈에 SNI 지원이 없다는 점이 서버에서 SNI를 효과적으로 활용하는 데 걸림돌이 됩니다.
더 심각한 또 다른 예는 Python 2 표준 라이브러리에 SSL 호스트 이름 일치 검사가 없다는 점입니다. 현재 Python 2에서 이 기능을 쓰려면 requests나 backports.ssl_match_hostname 같은 서드파티 라이브러리에 의존해야 합니다.
또한 Python 2 시리즈에는 타이밍 공격에 강한 hmac.compare_digest() 함수에 해당하는 표준 라이브러리 기능이 없습니다. 그래서 보안에 민감한 비교에서 원격 타이밍 공격에 Python 3 시리즈보다 여전히 더 취약합니다. 적절한 보안 비교 함수를 서드파티 확장으로 구현할 수는 있지만, 많은 사용자는 이 문제를 아예 고려하지 않고 일반적인 동등 비교를 사용합니다. 표준 라이브러리 해법이 있다고 해서 이 문제가 저절로 해결되지는 않지만, 문제가 지적되었을 때 해결하기가 확실히 훨씬 쉬워집니다.
Python 2.7은 코어 개발 팀이 제공한 유일한 장기 유지보수 릴리스입니다. 그러므로 과거처럼 짧은 유지보수 기간에는 통하던 방식이 이렇게 긴 지원 기간에는 통하지 않는 것은 자연스러운 일입니다. 이 PEP에서 설명하는 문제의 경우 가장 간단한 해결책은 다음 사실을 인정하는 것입니다. 네트워크 보안 관련 모듈을 장기간 유지보수하려면 기존 인터페이스의 하위 호환성을 유지하면서도 새 기능을 추가할 수 있어야 합니다.
이 방식에 익숙한 분이라면, 이 PEP에서 설명하는 접근 방식을 Red Hat이 장기 오픈 소스 지원 약속을 이행하는 방식과 비교해 볼 만합니다. 10년간의 지원을 받는 것은 RHEL 6.0 릴리스 자체가 아니라 RHEL 6 시리즈 전체입니다. 그리고 이 시리즈에 속한 개별 RHEL 6.x 포인트 릴리스는 기존 소프트웨어에 대한 엄격한 하위 호환성 보장을 지키면서도 보안 강화를 포함한 매우 다양한 새 기능을 받습니다. 이 PEP에서 다루는 제안은 장기 유지 보수에 대한 우리의 접근 방식을 이 선례에 더 가깝게 맞춥니다. 엄격한 하위 호환성 요구 사항은 그대로 유지하되, 새 기능 추가를 금지하는 제한에는 예외를 둡니다.
지금까지 다운스트림 재배포자들은 “Python 유지보수 릴리스에는 새 기능을 넣지 않는다”는 우리의 업스트림 정책을 존중해 왔습니다. 이 PEP는 네트워크 보안 관련 기능에는 더 세분화된 정책이 적절하다는 점을 명시적으로 받아들이며, 이 PEP가 설명하는 구체적인 변경은 Red Hat Enterprise Linux와 그 다운스트림 파생 배포판에도 적합할 수 있도록 의도적으로 설계되었습니다.
왜 하필 이러한 변경입니까?
어떤 기능을 이 제안에 포함할 후보로 고려하기 위한 핵심 요구 사항은, Python으로 작성된 특정 애플리케이션과 그 애플리케이션이 실행되는 시스템을 넘어서는 보안상 영향이 있어야 한다는 것이었습니다. 그래서 네트워크 보안 프로토콜, 비밀번호 저장 및 관련 암호화 인프라에 초점을 맞추었습니다. Python은 웹 서비스와 클라이언트 개발에 널리 선택되는 언어이므로, 널리 쓰이는 Python 버전의 기능은 다른 서비스의 보안 설계에도 영향을 미칩니다. 그러한 서비스는 자체적으로는 더 새로운 버전의 Python이나 다른 개발 언어를 사용하더라도, 더 오래된 버전의 Python으로 작성된 클라이언트나 서버와 상호 운용해야 하기 때문입니다.
이 요구 사항의 의도는 이 정책의 도입이 유지보수 릴리스의 안정성과 호환성에 미칠 수 있는 영향을 최소화하면서도, Python 2.7의 특정 측면과 관련된 몇 가지 핵심 보안 문제를 해결하는 것이었습니다. 최종 사용자가 같은 릴리스 시리즈 내의 새 기능 릴리스로 업데이트하는 것만큼이나 새 Python 2.7 유지보수 릴리스로 업데이트하는 것을 조심스러워하게 된다면, 이는 완전히 역효과를 낳는 일이 될 것입니다.
ssl 모듈 변경은 지난 4년간 이루어진 네트워크 보안 표준의 발전을 Python 2 시리즈에 반영하고, 그 표준들이 서버와 클라이언트 모두에서 폭넓게 채택되기 쉽도록 하기 위해 이 제안에 포함되었습니다. 마찬가지로 hashlib의 해시 알고리즘 가용성 지표는 애플리케이션이 Python 2와 3 모두에서 적절한 해시 정의를 감지하고 사용하기 쉽도록 하기 위해 포함되었습니다.
hmac.compare_digest() 함수와 hashlib.pbkdf2_hmac() 함수는 Python 2 서버 애플리케이션에서 비밀번호를 안전하게 저장하고 검사하는 일의 장벽을 낮추는 데 도움이 되도록 포함되었습니다.
os.urandom() 변경은 암호학적 사용 사례를 위한 고품질 난수를 제공하는 일을 운영 체제 공급업체에 맡기도록 사용자를 더욱 장려하기 위해 이 제안에 포함되었습니다. 충분히 무작위적이지 않은 난수를 사용하면 어떤 암호 시스템이든 손상될 수 있으며, 운영 체제 개발자들은 일반적인 Python 애플리케이션 런타임보다 이 문제를 적절히 해결할 수 있는 도구를 더 많이 갖추고 있습니다.
기각된 대안: 개발자들에게 그냥 Python 3으로 마이그레이션하라고 권고하기
이 대안은 현재 상태를 그대로 유지하는 것입니다. 안타깝게도 이 방식은 실제로는 실행 불가능하다는 것이 입증되었습니다. 하위 호환성 문제 때문에 대규모 애플리케이션과 통합 프로젝트에서는 마이그레이션 과정이 결코 간단하지 않기 때문입니다. 마이그레이션 도구는 Python 2와 Python 3의 넓은 공통 부분집합에서 실행되도록 코드를 갱신하는 방식으로 대규모 애플리케이션조차 (한꺼번에가 아니라) 기회가 될 때마다 점진적으로 마이그레이션할 수 있는 수준까지 발전했지만, 상업적 환경에서는 최신 기술을 사용하는 것이 우선순위가 아닌 경우가 많습니다.
이전에는 이것이 감수할 만한 피해로 여겨졌습니다. 영향을 받는 개발자들이 맞닥뜨려야 하는 불행한 문제이기는 했지만, 인프라 현대화의 필요성을 설득하는 일은 그들과 그들의 관리 계층 사이의 문제로 간주되었고, Python 3 시리즈가 발전함에 따라 그 설득 근거도 자연스럽게 더 강력해질 것이라고 보았기 때문입니다.
그러나 이제 Python 2 표준 라이브러리의 한계가 인터넷 보안 표준의 발전에 미치고 있을 수 있는 영향을 충분히 인식하게 된 이상, 저는 Python 3에서 이미 제공되는 네트워크 보안 강화 기능을 사용하려는 목적만으로 플랫폼 및 애플리케이션 개발자들이 애플리케이션의 유니코드 정확성에 잠재된 모든 결함을 해결하기를 기대하는 것이 더 이상 합리적이라고 생각하지 않습니다.
Ubuntu(그리고 어느 정도는 Debian도)는 모든 기본 시스템 서비스와 스크립트를 Python 3으로 포팅하고 기본 배포 이미지에서 Python 2를 제거하기로(아카이브에서는 제거하지 않음) 약속했지만, 이는 방대한 작업이며 Ubuntu 14.04 LTS 릴리스까지는 완료되지 않을 것입니다(적어도 데스크톱 이미지의 경우 그러하며, 모바일 및 서버 이미지에서는 달성될 수도 있습니다).
Fedora는 마이그레이션을 위해 해야 할 작업이 훨씬 더 많으며, 관련 인프라 구성 요소를 마이그레이션하는 데 상당한 시간이 걸릴 것입니다. Red Hat 역시 사용자들이 우리의 안정적인 플랫폼에서 더 최신 버전의 Python을 쉽게 사용할 수 있도록 적극적으로 노력하고 있지만, 그러한 노력이 최종 사용자의 버전 선택에 영향을 미치기 시작하기까지는 시간이 걸릴 것입니다. 또한 그러한 변경은 필연적으로 통합된 시스템 Python에서 실행되는 핵심 플랫폼 인프라에는 아무런 도움이 되지 않습니다.
OpenStack의 Python 3 마이그레이션 역시 아직 초기 단계에 있습니다. 광범위하고 비교적 견고한 자동화 테스트 스위트를 갖춘 프로젝트이기는 하지만, 여전히 규모가 커서 Python 2/3 호환 코드 베이스로 완전히 마이그레이션하는 데 상당한 시간이 걸릴 것입니다.
그리고 이것은 Python을 많이 사용하는 가장 유명한 오픈 소스 프로젝트 중 단 세 개일 뿐입니다. Python 2에서 Python 3으로의 마이그레이션을 뒷받침하는 데 필요한 종류의 자동화된 회귀 테스트 스위트가 없는 레거시 코드가 대량으로 존재할 가능성이 높다는 점을 고려하면, 마이그레이션보다 (어쩌면 Python 3으로) 다시 구현하는 편이 더 쉬운 경우가 많을 것입니다. 이 PEP의 핵심은 그러한 상황이 영향을 받는 애플리케이션의 개발자와 사용자보다 더 많은 사람에게 영향을 미친다는 점입니다. 오래된 네트워크 보안 인프라를 가진 클라이언트와 서버가 존재한다는 사실은 안전한 네트워크 서비스 개발자들이 보안 설계의 일부로 고려해야 하는 요소가 되며, 이는 더 나은 보안 표준의 채택을 가로막는 문제입니다.
Terry Reedy가 지적했듯이, 우리가 현재 상태를 고수하려 한다면 상업적 재배포자들이 어쨌든 고객을 대신해 이와 비슷한 일을 시도하게 될 가능성이 높지만, 그 방식은 일관성이 없고 임시방편적일 수 있습니다. 범위를 정의하는 과정을 업스트림 프로젝트로 끌어들이면, 이 상황을 해결하기 위해 취하는 접근 방식에 영향을 미치고 재배포자들 사이에 어느 정도 일관성을 확보하는 데 도움을 주기에 더 유리한 위치에 서게 됩니다.
이 문제는 실재하므로 무언가는 바뀌어야 하며, 이 PEP는 이 상황을 해결하기 위해 제가 선호하는 접근 방식을 설명합니다.
기각된 대안: Python 2.8을 만들어 릴리스하기
충분한 기업 지원이 있다면 Python 2.8을 만들어 릴리스하는 것이 아마 가능할 것입니다(그러한 프로젝트가 자원봉사자만으로 달성할 수 있을 만큼 충분한 관심을 모을 가능성은 매우 낮습니다). 그러나 이것으로는 실제로 문제가 해결되지 않습니다. 목표는 Python 2를 사용하는 통합 제품과 배포 환경에 향상된 보안 기능을 비교적 영향이 적은 방식으로 도입하는 것이기 때문입니다.
새로운 Python 기능 릴리스로 업그레이드하면 핵심 개발 팀의 작업이 늘어날 뿐만 아니라, 대부분의 잠재적 최종 사용자가 아마 아예 건너뛰어 버릴 만큼 파급이 큰 업데이트가 됩니다.
Python 2.8 릴리스를 만들려고 하면 Python 3의 여러 추가 기능(tracemalloc과 개선된 코루틴 지원 등)을 백포트하자는 제안도 들어오게 되어, Python 2.7에서 이 가상의 2.8 릴리스로 이전하는 일이 훨씬 더 위험하고 파급이 커집니다.
이 방식은 권장하지 않습니다. 상당한 추가 작업이 필요한데도, 그 결과는 원래 목표(Python 2 시리즈에서 현재 널리 사용되는 노후한 네트워크 보안 인프라를 없애는 것)를 달성하는 데 오히려 덜 효과적이기 때문입니다.
더욱이 저는 Red Hat 플랫폼에서 이 문제를 실제로 해결하겠다고 약속할 수는 없지만, 이 문제를 해결하려는 시도에서조차 Python 2.8이 제게 조금이라도 쓸모 있으리라는 생각은 단호히 배제할 수 있습니다.
기각된 대안: 보안 개선 사항을 PyPI를 통해 배포하기
처음에는 이 방식이 매력적이고 관리하기 쉬워 보이지만, 실제로는 몇 가지 중대한 문제가 있습니다.
첫째, 이것은 다양한 POSIX 플랫폼(Mac OS X 포함)과 Windows에 걸쳐 하부 운영 체제와 통합되는 복잡하고 저수준인 크로스 플랫폼 코드입니다. CPython BuildBot 군은 이미 그러한 환경에서 지속적 통합을 처리하도록 구성되어 있지만, 무료로 이용할 수 있는 대부분의 지속적 통합 서비스는 Linux만 제공하고, 경우에 따라 Windows를 유료로 제공할 뿐입니다. 이러한 서비스는 Python과 기타 동적 언어가 제공하는 추상화 계층 위에서 주로 실행되는 소프트웨어나, JVM이 제공하는 더 포괄적인 추상화 위에서 실행되는 소프트웨어에는 꽤 잘 작동하지만, 여기서 다루는 종류의 코드에는 충분하지 않습니다.
네트워크 보안 지원을 위한 OpenSSL 의존성 역시 pip 기반 소프트웨어 배포 생태계가 아직 잘 처리하지 못하는 일종의 “복잡한 바이너리 의존성”에 해당합니다. 서드파티 바이너리 의존성에 기대면 PyPy 같은 다른 인터프리터에서 실행할 때 pip에 호환성 문제가 생길 가능성도 있습니다.
이 아이디어의 또 다른 실질적인 문제는 pip 자체가 표준 라이브러리의 ssl 지원에 의존한다는 사실입니다(번들로 포함된 requests 사본으로부터 추가 지원을 일부 받으며, requests는 다시 backport.ssl_match_hostname을 번들로 포함합니다). 따라서 대체 모듈 역시 pip 안에 번들로 포함해야 합니다. 이것이 극복할 수 없는 어려움을 일으키지는 않겠지만(벤더링할 의존성이 하나 더 늘어날 뿐입니다), 최신 상태로 유지해야 할 OpenSSL 사본이 또 하나 생긴다는 뜻이기는 합니다.
이 방식에는 “이름을 바꿔서 보안을 개선하는” 다른 모든 방식과 같은 결함도 있습니다. 즉, 도움이 가장 필요한 사용자를 완전히 놓치고, 인프라가 지원할 때 사용자가 올바른 일을 하도록 권장하는 데 상당한 장벽을 세웁니다(“이 다른 모듈을 사용하십시오”는 “이 더 높은 보안 설정을 켜십시오”보다 훨씬 파급이 큰 변경이기 때문입니다). 표준 라이브러리의 노후한 SSL 인프라를 폐지하고 외부 모듈을 쓰게 하는 것은, 그 인프라를 제자리에서 업그레이드하는 데 따르는 약간 증가한 회귀 위험을 감수하는 것보다 사용자에게 훨씬 더 적대적인 일입니다.
마지막으로, 그러나 결코 사소하지 않은 문제로, 이 방식은 Python 2.8 릴리스를 만드는 아이디어와 같은 문제를 안고 있습니다. 즉, 실제 문제를 해결하지 못할 가능성이 높습니다. Python의 상용 재배포자들은 Python과 기존의 추가 패키지 묶음을 재배포하도록 체계가 갖춰져 있습니다. 기존 묶음에 새 패키지를 추가하는 일은 가능하지만, 그러려면 재배포자 한 곳 한 곳을 찾아가 재패키징 프로세스를 그에 맞게 갱신해 달라고 요청해야 합니다. 반면, 이 PEP에서 설명하는 방식에서는 재배포자가 제공된 네트워크 보안 인프라를 일부러 다운그레이드하여 보안 개선 사항을 의도적으로 거부해야 하며, 대부분의 재배포자는 그렇게 하지 않을 것입니다.
기각된 변형안: “레거시 SSL 인프라” 브랜치 제공하기
이 PEP의 이전 버전에는 Python 2.7.6 네트워크 보안 인프라의 기능 집합을 그대로 보존하는 2.7-legacy-ssl 브랜치라는 개념이 포함되어 있었습니다.
제 의견으로는, 실제로 이것을 원하는 사람은 거의 확실히 실수를 하고 있는 것이며, 자신의 특정 상황에서 정말로 이것이 필요하다고 고집한다면 직접 만들거나 다운스트림 재배포자에게 만들어 달라고 요청하면 됩니다.
그러한 재빌드를 공개적으로 배포한다면, 더 최신의 네트워크 보안 인프라를 포함하는 공식 Python 2.7 릴리스와 명확히 구별되도록 “Python 2.7 with Legacy SSL”이라고 불러야 합니다.
이 PEP를 구현하는 첫 번째 Python 2.7 유지보수 릴리스 이후에는 Python 2.7.6 및 그 이전 릴리스를 “Python 2.7 with Legacy SSL”이라고 부르는 것도 적절합니다.
기각된 변형안: 특정 모듈을 Python 3과 완전히 동기화하기
이 PEP의 이전 버전에서는 hmac, hashlib, ssl 모듈을 Python 3의 대응 모듈과 완전히 동기화하자고 제안했습니다.
이 방식은 너무 모호하여 예외를 인정할 설득력 있는 근거를 마련하지 못했으므로, 현재의 더 명시적인 제안으로 대체되었습니다.
기각된 변형안: 제한 없는 백포트 정책
이 PEP의 이전 버전에서는 인터넷의 전반적인 보안에 영향을 미치는 향후 Python 3 개선 사항과 관련하여 일반적인 정책 변경을 제안했습니다.
그 접근 방식은 불필요한 불확실성을 낳았기 때문에, 구체적으로 정해진 일련의 변경 사항을 백포트하도록 제안하는 방식으로 단순화했습니다. 향후 기능 백포트 제안은 이 PEP를 선례로 참조할 수 있지만, Python 2.7 장기 지원 릴리스에 기능을 추가할 때마다 여전히 그 기능에 대한 구체적인 근거를 제시해야 합니다.
이해관계 공개
이 PEP의 저자는 현재 Red Hat에서 테스트 자동화 도구 관련 업무를 하고 있습니다. 이 제안이 수락되면, 저는 Red Hat이 그로 인해 생기는 기회를 활용하여 Python 생태계 전반의 보안 향상에 기여하도록 적극적으로 권장할 것입니다. 그러나 이 사안에 관해 저는 Red Hat을 대변하지 않으며, Red Hat을 대신하여 어떠한 약속도 할 수 없습니다.
감사의 글
Python 3 시리즈에서 Python의 SSL 지원을 크게 개선하기 위해 노력한 Christian Heimes와 다른 분들께 감사드립니다. 또한 우리 SSL 모듈이 제공하는 기본 설정이 어떤 의미를 갖는지, 그리고 2010년(Python 2.7) 또는 심지어 2008년(Python 2.6)에 정의된 SSL 인프라의 사용을 용인하는 것이 웹 전체의 보안에 미칠 수 있는 영향을 제가 더 잘 이해하도록 도와주신 Python 커뮤니티의 여러 구성원께도 감사드립니다.
필수 보안 기능을 더 좁은 범위로 추려 주어, Python 3.4의 모듈 전체를 백포트하는 것보다 더 세분화된 제안을 할 수 있게 해 준 Donald Stufft와 Alex Gaynor께 감사드립니다([7], [8]).
Christian과 Donald는 이 제안의 예비 초안에 대해서도 귀중한 피드백을 제공해 주었습니다.
python-dev 메일링 리스트 스레드의 참여자들([1], [2], [5], [6])과, 몬트리올에서 열린 PyCon 2014에서 이 문제를 함께 논의한 여러 분께도 감사드립니다.
참고 문헌
Copyright
This document has been placed in the public domain.