2017-07-14 21 views
0

我正嘗試使用python創建套接字連接。在Python中驗證對端

這裏是我的Python代碼...

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
socket.settimeout(config['timeout']) 
self.socket.connect((config['host'], config['port'])) 

self.ssl = ssl.wrap_socket(
    self.socket, 
    certfile=config['certificate'], 
    keyfile=config['key'] 
) 

遠程服務器的證書似乎是自簽名或信任存儲缺少它沒有工作。我是新來的python,並不知道如何禁用python中的verify_peer,所以連接可以工作。

我有工作在PHP代碼...

$context = stream_context_create([ 
    'ssl' => [ 
     'verify_peer' => false, 
     'local_cert' => $config['certificate'], 
     'local_pk' => $config['key'] 
    ] 
]); 

$socket = stream_socket_client(
    'ssl://secure.test.com:700', 
    $errno, $errstr, $config['timeout'], 
    STREAM_CLIENT_CONNECT, $context 
); 

設置'verify_peer' => false有助於建立連接。我如何在Python中做類似的事情?

OpenSSL的調試

openssl s_client -connect secure.test.com:700 

verify error:num=20:unable to get local issuer certificate 
verify return:1 

verify error:num=21:unable to verify the first certificate 
verify return:1 

請幫助和建議。謝謝

+0

*「設置'verify_peer => FALSE'有助於確立連接。我如何在python中做類似的事情?「 - 非常糟糕的主意;請參閱[世界上最危險的代碼:在非瀏覽器軟件中驗證SSL證書](http://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html)。 – jww

+0

*「它不起作用,因爲遠程服務器的證書似乎是自簽名的或從信任存儲庫中丟失...」 - - 這是什麼?用例影響答案。請發佈您用於連接服務器的URL,併發布'openssl s_client -connect -tls1 -servername | openssl x509 -text -noout'。點擊*編輯*(不要將其作爲評論發佈),將其添加到您的問題中。否則,我們無法複製它,並且沒有足夠的信息來幫助排除故障。 – jww

+0

@jww感謝您的幫助。我已經編輯了更多細節的問題。我得到這個錯誤:'驗證錯誤:num = 20:無法獲得本地頒發者證書'已經嘗試通過Linux命令重新獲取當前證書'openssl s_client -connect secure.test.com:700:' – seoppc

回答

0

禁用證書驗證可以簡單地通過添加cert_reqs = ssl.CERT_NONE完成。但是,只要禁用證書驗證是一個非常糟糕的主意,因爲您知道對man-in-the-middle attacks開放。

因此您應該檢查證書是否是預期的證書。對於自簽名證書(和其他人也行),您可以檢查例如接收到的證書下面的代碼預期的證書指紋一致,如:

import socket 
import ssl 
import hashlib 

dst = ('www.paypal.com',443) 
fp_expected = '0722d46c216327bab8075f5db57ebed64d80e6699204c249c3f6ea9cc281c15b' 

# connect to the target with TCP 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect(dst) 

# upgrade the socket to SSL without checking the certificate 
s = ssl.wrap_socket(s,cert_reqs = ssl.CERT_NONE) 

# get certificate, compute fingerprint and check against expected value 
cert_bin = s.getpeercert(True) 
fp = hashlib.sha256() 
fp.update(cert_bin) 
assert(fp.hexdigest() == fp_expected) 
+0

感謝您的解釋。我被這個錯誤困住了。當我運行'openssl s_client -connect secure.test.com:700 -key client'時,驗證錯誤:num = 20:無法獲得本地頒發者證書並且驗證錯誤:num = 21:無法驗證第一個證書。 key -cert client.crt',所以我想禁用證書檢查。 – seoppc

+0

@seoppc:上面的代碼可以用來驗證服務器證書是否是自簽名或某種程度上中斷的預期。但是它應該有適當的證書+鏈,那麼你可能從一開始就做錯了:例如,它可能是服務器要求你使用SNI擴展來獲得一個簡單的wrap_socket不能實現的正確的證書和鏈。請注意,我無法使用s_client進行測試,因爲secure.test.com:700無法從我的位置訪問,即TCP連接已失敗。 –