2015-04-09 9 views
6

Próbowałem użyć Python-LDAP (wersja 2.4.19) pod MacOS X 10.9.5 i Python 2.7.9Jak wymusić Python LDAP, aby potwierdzić/zweryfikować certyfikat SSL podczas korzystania .start_tls_s()

Chcę sprawdzić poprawność połączenia z danym serwerem LDAP po tym, jak zadzwoniłem pod numer .start_tls_s() (lub aby metoda była podnoszona i wyjątkowa, jeśli certyfikat nie może zostać zweryfikowany). (Chciałbym też sprawdzić CRL, ale to już inna sprawa).

Oto mój kod:

#!python 
#!/usr/bin/env python 
import ConfigParser, os, sys 
import ldap 

CACERTFILE='./ca_ldap.bad' 
## CACERTFILE='./ca_ldap.crt' 

config = ConfigParser.ConfigParser() 
config.read(os.path.expanduser('~/.ssh/creds.ini')) 
uid = config.get('LDAP', 'uid') 
pwd = config.get('LDAP', 'pwd') 
svr = config.get('LDAP', 'svr') 
bdn = config.get('LDAP', 'bdn') 

ld = ldap.initialize(svr) 
ld.protocol_version=ldap.VERSION3 
ld.set_option(ldap.OPT_DEBUG_LEVEL, 255) 
ld.set_option(ldap.OPT_PROTOCOL_VERSION, 3) 
ld.set_option(ldap.OPT_X_TLS_CACERTFILE, CACERTFILE) 
ld.set_option(ldap.OPT_X_TLS_DEMAND, True) 
ld.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_HARD) 

## From: https://stackoverflow.com/a/7810308/149076 
## and : http://python-ldap.cvs.sourceforge.net/viewvc/python-ldap/python-ldap/Demo/initialize.py?revision=1.14&view=markup 

ld.start_tls_s() 

for each in dir(ldap): 
    if 'OPT_X_TLS' in each: 
     try: 
      print '\t*** %s: %s' % (each, ld.get_option((getattr(ldap, each)))) 
     except Exception, e: 
      print >> sys.stderr, '... Except %s: %s\n' % (each, e) 

ld.simple_bind_s(uid, pwd) 
results = ld.search_s(bdn, ldap.SCOPE_SUBTREE) 

print 'Found %s entries under %s' % (len(results), bdn) 
sys.exit() 

Jak zauważył w komentarzach mam skopiowanych większość to od https://stackoverflow.com/a/7810308/149076 iz http://python-ldap.cvs.sourceforge.net/viewvc/python-ldap/python-ldap/Demo/initialize.py?revision=1.14&view=markup ... chociaż próbowałem wiele odmian i sekwencje z tego.

Jak widać mam dwa pliki, które stanowią świadectwo złe i jeden, który powinien działać (to faktycznie pochodzi z jednego z naszych systemów, które są skonfigurowane do uruchamiania sssd (System Usług Bezpieczeństwa Daemon), który uznaje się za sprawdzanie tego poprawnie:

W "złym" egzemplarzu po prostu zastąpiłem pierwszy znak każdej linii kluczowej literą "x" przy założeniu, że spowoduje to uszkodzenie klucza CA i spowoduje, że kod spróbuje zweryfikować łańcuch sygnatury do niepowodzenia:

Wydaje się jednak, że kod LDAP w języku Python ignoruje to, nawet jeśli ustawię go na /dev/null lub całkowicie fałszywa ścieżka, którą mój kod nadal działa, nadal wiąże się z serwerem LDAP i wciąż wykonuje moją prośbę wyszukiwania.

Więc pytanie brzmi, jak mogę dostać tego na „nie” w sposób zamierzony (lub, bardziej ogólnie, w jaki sposób mogę zapobiec wyświetlaniu mojej kod jest podatny na MiTM (Mallory) ataki?

Jeśli to którejkolwiek konsekwencją tej dyskusji oto moja wersja OpenSSL:

$ openssl version 
OpenSSL 0.9.8za 5 Jun 2014 

serwer LDAP jest uruchomiony OpenLDAP, ale nie znam żadnych szczegółów na temat jego wersji ani konfiguracji

Oto próba wyjścia z mojego kodu.

*** OPT_X_TLS: 0 
    *** OPT_X_TLS_ALLOW: 0 
    *** OPT_X_TLS_CACERTDIR: None 
    *** OPT_X_TLS_CACERTFILE: /bogus/null 
    *** OPT_X_TLS_CERTFILE: None 
    *** OPT_X_TLS_CIPHER_SUITE: None 
    *** OPT_X_TLS_CRLCHECK: 0 
    *** OPT_X_TLS_CRLFILE: None 
    *** OPT_X_TLS_CRL_ALL: 1 
    *** OPT_X_TLS_CRL_NONE: {'info_version': 1, 'extensions': ('X_OPENLDAP', 'THREAD_SAFE', 'SESSION_THREAD_SAFE', 'OPERATION_THREAD_SAFE', 'X_OPENLDAP_THREAD_SAFE'), 'vendor_version': 20428, 'protocol_version': 3, 'vendor_name': 'OpenLDAP', 'api_version': 3001} 
    *** OPT_X_TLS_CRL_PEER: 3 
... Except OPT_X_TLS_CTX: unknown option 24577 

    *** OPT_X_TLS_DEMAND: 1 
    *** OPT_X_TLS_DHFILE: None 
    *** OPT_X_TLS_HARD: 3 
    *** OPT_X_TLS_KEYFILE: None 
    *** OPT_X_TLS_NEVER: {'info_version': 1, 'extensions': ('X_OPENLDAP', 'THREAD_SAFE', 'SESSION_THREAD_SAFE', 'OPERATION_THREAD_SAFE', 'X_OPENLDAP_THREAD_SAFE'), 'vendor_version': 20428, 'protocol_version': 3, 'vendor_name': 'OpenLDAP', 'api_version': 3001} 
... Except OPT_X_TLS_NEWCTX: unknown option 24591 

    *** OPT_X_TLS_PACKAGE: OpenSSL 
    *** OPT_X_TLS_PROTOCOL_MIN: 0 
    *** OPT_X_TLS_RANDOM_FILE: None 
    *** OPT_X_TLS_REQUIRE_CERT: 1 
    *** OPT_X_TLS_TRY: 0 

Found 883 entries under [... redacted ...] 
+0

* "Chciałbym również sprawdzić CRL, ale to już inna sprawa" * - uważaj na to. Możesz ustawić się na DoS z powodu brakujących/uszkodzonych list CRL i respondentów OCSP. Mozilla wyłączyła go na jakiś czas, ponieważ miała tak negatywny wpływ na wygodę użytkownika. Zszyte odpowiedzi byłyby prawdopodobnie drogą do zrobienia. – jww

+0

W moim przypadku będzie działać w środowisku, które zapewnia własny urząd certyfikacji i zarządza własnymi listami CRL. To wszystko jest wewnętrzne. –

+0

Mogę być nośnikiem złych wiadomości ... Python-LDAP może korzystać z OpenSSL. Jednak połączenia zwykle używane lub spotykane w celu obsługi certyfikatów nie są obecne. Na przykład otrzymuję 0 trafień dla 'cd python-ldap; grep -R -i ca_certs *; grep -R -i wrap_socket *; grep -R -i certs_reqs * '. Możesz skontaktować się z programistami, aby zobaczyć ich pozycję. Mogą oni powiedzieć coś w stylu "kod ma być uruchamiany na tej samej granicy bezpieczeństwa co serwer LDAP, więc używamy certyfikatu dla poufności, ale nie weryfikujemy serwera ani nie stosujemy uwierzytelniania serwera, ponieważ nie ma aktywnego MitM". – jww

Odpowiedz

7

Twój kod działa zgodnie z oczekiwaniami. Właściwie to miałem dokładnie przeciwny problem, kiedy wykonałem twój kod po raz pierwszy. To zawsze powiedział, że "weryfikacja certyfikatu nie powiodła się". Dodając następujące linie ustalone następująco:

# Force libldap to create a new SSL context (must be last TLS option!) 
ld.set_option(ldap.OPT_X_TLS_NEWCTX, 0) 

Teraz kiedy używam niewłaściwego certyfikatu CA lub taki, który został zmodyfikowany, jak opisał to, wynik jest ten komunikat o błędzie:

Traceback (most recent call last): 
    File "ldap_ssl.py", line 28, in <module> 
    ld.start_tls_s() 
    File "/Library/Python/2.7/site-packages/python_ldap-2.4.19-py2.7-macosx-10.10-intel.egg/ldap/ldapobject.py", line 571, in start_tls_s 
    return self._ldap_call(self._l.start_tls_s) 
    File "/Library/Python/2.7/site-packages/python_ldap-2.4.19-py2.7-macosx-10.10-intel.egg/ldap/ldapobject.py", line 106, in _ldap_call 
    result = func(*args,**kwargs) 
ldap.CONNECT_ERROR: {'info': 'error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (unable to get local issuer certificate)', 'desc': 'Connect error'} 

Gdy używam odpowiedni certyfikat CA, wynik jest taki jak twój.


Teraz interesujące pytanie brzmi: Jakie są różnice między naszymi konfiguracjami, a zwłaszcza jakie różnice powodują to dziwne zachowanie na komputerze?

Moja konfiguracja to:

  • Mac OS X 10.10
  • Python 2.7.6
  • python-ldap 2.4.19 (instalacja ręczna)
  • OpenLDAP 2.4.39 (przez Homebrew)
  • OpenSSL 1.0.1l (przez Homebrew)

mam lokalny OpenLDAP uruchomiony, Insta lled z Homebrew:

brew install homebrew/dupes/openldap --with-berkeley-db 

Na Yosemite python-LDAP jest całkiem buggy po zainstalowaniu z PIP (zob Python-ldap set_option not working on Yosemite), więc musiałem pobrać archiwum i skompilować/zainstalować go, co było na szczęście dość łatwe, bo już miał instalację OpenLDAP z aktualnymi libs/nagłówkami:

Pierwsza Edycja [_ldap] sekcja w setup.cfg tak:

[_ldap] 
library_dirs = /usr/local/opt/openldap/lib /usr/lib /usr/local/lib 
include_dirs = /usr/local/opt/openldap/include /usr/include/sasl /usr/include /usr/local/include 
extra_compile_args = -g -arch x86_64 
extra_objects = 
libs = ldap_r lber sasl2 ssl crypto 

Niektóre pliki nagłówkowe są w systemie Mac OS SDK Link t on katalog (zmienić ścieżkę w zależności od wersji) do/usr/include:

sudo ln -s /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/ /usr/include 

Następnie zbudować i zainstalować:

python setup.py build 
sudo python setup.py install 

Wyjście otool pokazuje, że python-ldap jest teraz połączone z biblioteki OpenSSL OpenLDAP 2.4.39 i 0.9.8:

$ otool -L /Library/Python/2.7/site-packages/python_ldap-2.4.19-py2.7-macosx-10.10-intel.egg/_ldap.so 
/Library/Python/2.7/site-packages/python_ldap-2.4.19-py2.7-macosx-10.10-intel.egg/_ldap.so: 
    /usr/local/lib/libldap_r-2.4.2.dylib (compatibility version 13.0.0, current version 13.2.0) 
    /usr/local/lib/liblber-2.4.2.dylib (compatibility version 13.0.0, current version 13.2.0) 
    /usr/lib/libsasl2.2.dylib (compatibility version 3.0.0, current version 3.15.0) 
    /usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) 
    /usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) 
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0) 

alternatywnym podejściem do budowania python-ldap jest zainstalowanie tylko bibliotek OpenLDAP i nagłówki potrzebne dla budownictwa: http://projects.skurfer.com/posts/2011/python_ldap_lion/

Wszystkie te kroki powinny działać również pod Mavericks i zakładam, że korzystanie z najnowszych bibliotek OpenLDAP i OpenSSL rozwiąże problem.

+0

Na moim Macu pod MacOS 10.9.5, nie otrzymałem żadnego ostrzeżenia lub awarii. Na maszynie wirtualnej Linux pod CentOS 6.5, ostatnio sprawdziłem, otrzymuję zachowanie, które opisujesz tutaj (przynajmniej do tego stopnia, że ​​"zawsze podnosi wyjątek"). Spróbuję ustawić 'ld.set_option (ldap.OPT_X_TLS_NEWCTX, 0)' i dostosować niektóre z moich bibliotek 'brew'. (Używam Pythona 2.7.9, jak wspomniano powyżej, mój LDAP/OpenSSL jest albo domyślny MacOS, albo firmowy załadowany --- nie mam z nimi żadnego problemu –

+0

Omikron, na pewno jesteś czołowym biegaczem dla nagrody daleko;) –

+0

Dodałem wyjście z otool, wygląda na to, że wersja OpenSSL nie ma tu znaczenia, ponieważ mój python-ldap jest połączony z 0.9.8z nie 1.0.1l. – Omikron

Powiązane problemy