2011-07-11 38 views
14

Tôi sử dụng python 2.6 và yêu cầu API Facebook (https). Tôi đoán dịch vụ của tôi có thể là mục tiêu của các cuộc tấn công của Man In The Middle. tôi phát hiện ra sáng nay đọc tài liệu hướng dẫn mô-đun lần nữa urllib rằng: lời trích dẫn:Urllib và xác thực chứng chỉ máy chủ

Warning : When opening HTTPS URLs, it is not attempted to validate the server certificate. Use at your own risk! 

Bạn có gợi ý/url/ví dụ để hoàn thành một xác nhận giấy chứng nhận đầy đủ?

Nhờ sự giúp đỡ của bạn

+1

Bạn có thể quan tâm đến câu hỏi này: http://stackoverflow.com/questions/6167148/drop-in-replacement -for-urllib2-urlopen-that-do-cert-verification – Bruno

+0

Xem thêm [Xác thực chứng chỉ SSL bằng Python - Stack Overflow] (http://stackoverflow.com/questions/1087227/validate-ssl-certificates-with-python) – nealmcb

Trả lời

9

Bạn có thể tạo trình mở urllib2 có thể thực hiện xác thực cho bạn bằng trình xử lý tùy chỉnh. Đoạn mã sau là một ví dụ làm việc với Python 2.7.3. Giả sử bạn đã tải xuống http://curl.haxx.se/ca/cacert.pem vào cùng một thư mục nơi tập lệnh được lưu.

#!/usr/bin/env python 
import urllib2 
import httplib 
import ssl 
import socket 
import os 

CERT_FILE = os.path.join(os.path.dirname(__file__), 'cacert.pem') 


class ValidHTTPSConnection(httplib.HTTPConnection): 
     "This class allows communication via SSL." 

     default_port = httplib.HTTPS_PORT 

     def __init__(self, *args, **kwargs): 
      httplib.HTTPConnection.__init__(self, *args, **kwargs) 

     def connect(self): 
      "Connect to a host on a given (SSL) port." 

      sock = socket.create_connection((self.host, self.port), 
              self.timeout, self.source_address) 
      if self._tunnel_host: 
       self.sock = sock 
       self._tunnel() 
      self.sock = ssl.wrap_socket(sock, 
             ca_certs=CERT_FILE, 
             cert_reqs=ssl.CERT_REQUIRED) 


class ValidHTTPSHandler(urllib2.HTTPSHandler): 

    def https_open(self, req): 
      return self.do_open(ValidHTTPSConnection, req) 

opener = urllib2.build_opener(ValidHTTPSHandler) 


def test_access(url): 
    print "Acessing", url 
    page = opener.open(url) 
    print page.info() 
    data = page.read() 
    print "First 100 bytes:", data[0:100] 
    print "Done accesing", url 
    print "" 

# This should work 
test_access("https://www.google.com") 

# Accessing a page with a self signed certificate should not work 
# At the time of writing, the following page uses a self signed certificate 
test_access("https://tidia.ita.br/") 

Chạy kịch bản này, bạn sẽ thấy một cái gì đó một đầu ra như thế này:

Acessing https://www.google.com 
Date: Mon, 14 Jan 2013 14:19:03 GMT 
Expires: -1 
... 

First 100 bytes: <!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage"><head><meta itemprop 
Done accesing https://www.google.com 

Acessing https://tidia.ita.br/ 
Traceback (most recent call last): 
    File "https_validation.py", line 54, in <module> 
    test_access("https://tidia.ita.br/") 
    File "https_validation.py", line 42, in test_access 
    page = opener.open(url) 
    ... 
    File "/usr/local/Cellar/python/2.7.3/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1177, in do_open 
    raise URLError(err) 
urllib2.URLError: <urlopen error [Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed> 
+3

'def __init __ (self, * args, ** kwargs): httplib.HTTPConnection .__ init __ (self, * args, ** kwargs)' điều dường như vô dụng đối với tôi – pictuga

-3

Nếu bạn có một tập tin đáng tin cậy Certificate Authority (CA), bạn có thể sử dụng Python 2.6 và sau đó là ssl thư viện để xác nhận chứng chỉ. Dưới đây là một số mã:

import os.path 
import ssl 
import sys 
import urlparse 
import urllib 

def get_ca_path(): 
    '''Download the Mozilla CA file cached by the cURL project. 

    If you have a trusted CA file from your OS, return the path 
    to that instead. 
    ''' 
    cafile_local = 'cacert.pem' 
    cafile_remote = 'http://curl.haxx.se/ca/cacert.pem' 
    if not os.path.isfile(cafile_local): 
     print >> sys.stderr, "Downloading %s from %s" % (
      cafile_local, cafile_remote) 
    urllib.urlretrieve(cafile_remote, cafile_local) 
    return cafile_local 

def check_ssl(hostname, port=443): 
    '''Check that an SSL certificate is valid.''' 
    print >> sys.stderr, "Validating SSL cert at %s:%d" % (
     hostname, port) 

    cafile_local = get_ca_path() 
    try: 
     server_cert = ssl.get_server_certificate((hostname, port), 
      ca_certs=cafile_local) 
    except ssl.SSLError: 
     print >> sys.stderr, "SSL cert at %s:%d is invalid!" % (
      hostname, port) 
     raise 

class CheckedSSLUrlOpener(urllib.FancyURLopener): 
    '''A URL opener that checks that SSL certificates are valid 

    On SSL error, it will raise ssl. 
    ''' 

    def open(self, fullurl, data = None): 
     urlbits = urlparse.urlparse(fullurl) 
     if urlbits.scheme == 'https': 
      if ':' in urlbits.netloc: 
       hostname, port = urlbits.netloc.split(':') 
      else: 
       hostname = urlbits.netloc 
       if urlbits.port is None: 
        port = 443 
       else: 
        port = urlbits.port 
      check_ssl(hostname, port) 
     return urllib.FancyURLopener.open(self, fullurl, data) 

# Plain usage - can probably do once per day 
check_ssl('www.facebook.com') 

# URL Opener 
opener = CheckedSSLUrlOpener() 
opener.open('https://www.facebook.com/find-friends/browser/') 

# Make it the default 
urllib._urlopener = opener 
urllib.urlopen('https://www.facebook.com/find-friends/browser/') 

Một số nguy hiểm với mã này:

  1. Bạn phải tin tưởng vào tập tin CA từ dự án cURL (http://curl.haxx.se/ca/cacert.pem), đó là một phiên bản cache của file CA của Mozilla. Nó cũng trên HTTP, vì vậy có một cuộc tấn công MITM tiềm năng. Tốt hơn nên thay thế get_ca_path bằng cách trả về tệp CA cục bộ của bạn, tệp này sẽ thay đổi từ máy chủ lưu trữ sang máy chủ lưu trữ.
  2. Không có cố gắng để xem nếu tập tin CA đã được cập nhật. Cuối cùng, các chứng chỉ gốc sẽ hết hạn hoặc bị hủy kích hoạt và các thẻ mới sẽ được thêm vào. Một ý tưởng hay là sử dụng một công việc cron để xóa tệp CA được lưu trong bộ nhớ cache, để một tệp mới được tải xuống hàng ngày.
  3. Có thể quá mức cần thiết để kiểm tra chứng chỉ mỗi lần. Bạn có thể kiểm tra thủ công một lần cho mỗi lần chạy hoặc giữ một danh sách các máy chủ 'đã biết' tốt trong quá trình chạy. Hoặc, là hoang tưởng!
+11

Bạn đang kiểm tra danh sách các CA từ http://curl.haxx.se/ca/cacert.pem bằng mã này. Kết nối đó không vượt quá ssl để ai đó có thể làm người đàn ông ở giữa trang web đó để xuất bản CA gốc của họ tương ứng với mã này và ký vào cert của họ cho facebook hoặc bất kỳ trang web nào bạn đang cố gắng xác thực – Chris

+4

Sau khi suy nghĩ về nó hơn nữa, bạn không thể truy xuất từ ​​xa danh sách CA, bạn phải cung cấp một cửa hàng địa phương. Ngay cả khi bạn đã sử dụng https://www.digicert.com/testroot/DigiCertGlobalRootCA.crt (trên ssl), bạn sẽ xác nhận điều này như thế nào? – Chris

+2

Tất cả các điểm hợp lệ. Mã này tải xuống tệp cert từ internet nếu nó không có sẵn cục bộ. Nếu bạn có một trình duyệt được cài đặt trên máy chủ của bạn (tôi thường không), bạn có thể sử dụng tệp chứng chỉ của trình duyệt, khi bạn tìm thấy nó trên hệ thống tệp của mình. Tất nhiên, trừ khi bạn lái xe xuống Mountain View, bạn có thể tải xuống trình duyệt của mình qua internet. Bạn phải tin tưởng ai đó, tại một số điểm. – jwhitlock

Các vấn đề liên quan