Недопустимый и/или отсутствующий сертификат SSL

Я пытаюсь создать хранилище данных в Google App Engine для сбора некоторых данных потока из StockTwits для группы компаний. Я в основном реплицирую то, что я сделал с Twitter, но это дало мне HTTPException: неверный и/или отсутствующий сертификат SSL-сертификата для одного из URL-адресов. Я изменил URL-адрес, чтобы посмотреть на другую компанию, но получил тот же результат.

Здесь код, который извлекает данные:

class StreamHandler(webapp2.RequestHandler):

def get(self):

    tickers = ['AAPL','GOOG', 'IBM', 'BAC', 'INTC',
               'DELL', 'C', 'JPM', 'WFM', 'WMT', 
               'AMZN', 'HOT', 'SPG', 'SWY', 'HTSI', 
               'DUK', 'CEG', 'XOM', 'F', 'WFC', 
               'CSCO', 'UAL', 'LUV', 'DAL', 'COST', 'YUM',
               'TLT', 'HYG', 'JNK', 'LQD', 'MSFT',
               'GE', 'LVS', 'MGM', 'TWX', 'DIS', 'CMCSA',
               'TWC', 'ORCL', 'WPO', 'NYT', 'GM', 'JCP', 
               'LNKD', 'OPEN', 'NFLX', 'SBUX', 'GMCR', 
               'SPLS', 'BBY', 'BBBY', 'YHOO', 'MAR', 
               'L', 'LOW', 'HD', 'HOV', 'TOL', 'NVR', 'RYL', 
               'GIS', 'K', 'POST', 'KRFT', 'CHK', 'GGP', 
               'RSE', 'RWT', 'AIG', 'CB', 'BRK.A', 'CAT']

    for i in set(tickers):

        urlst = 'https://api.stocktwits.com/api/2/streams/symbol/'
        tickerstringst = urlst + i + '.json'
        tickurlst = urllib2.Request(tickerstringst)
        sttweets = urllib2.urlopen(tickurlst)
        stcode = sttweets.getcode()

        if stcode == 200:
            stresults = json.load(sttweets, 'utf-8')
            if "messages" in stresults:
                stentries = stresults["messages"]
                for stentry in stentries:
                    sttweet = streamdata()
                    stcreated = stentry['created_at']
                    sttweetid = str(stentry['id'])
                    sttweettxt = stentry['body']
                    sttweet.ticker = i
                    sttweet.created_at = stcreated
                    sttweet.tweet_id = sttweetid
                    sttweet.text = sttweettxt
                    sttweet.source = "StockTwits"
                    sttweet.put()

И вот файл журнала, который показывает ошибку. Я запускаю это на локальном сервере разработки Python, btw:

WARNING  2012-12-06 23:20:12,993 dev_appserver.py:3655] Could not initialize images API; you are likely missing the Python "PIL" module. ImportError: No module named _imaging
INFO     2012-12-06 23:20:13,017 dev_appserver_multiprocess.py:655] Running application dev~jibdantestv2 on port 8088: http://localhost:8088
INFO     2012-12-06 23:20:13,017 dev_appserver_multiprocess.py:657] Admin console is available at: http://localhost:8088/_ah/admin   
INFO     2012-12-06 23:20:54,776 dev_appserver.py:3092] "GET /_ah/admin HTTP/1.1" 302 -
INFO     2012-12-06 23:20:54,953 dev_appserver.py:3092] "GET /_ah/admin/datastore HTTP/1.1" 200 -
INFO     2012-12-06 23:20:55,280 dev_appserver.py:3092] "GET /_ah/admin/images/google.gif HTTP/1.1" 200 -
INFO     2012-12-06 23:21:04,617 dev_appserver.py:3092] "GET /_ah/admin/cron HTTP/1.1" 200 -
INFO     2012-12-06 23:21:04,815 dev_appserver.py:3092] "GET /_ah/admin/images/google.gif HTTP/1.1" 200 -
WARNING  2012-12-06 23:21:07,392 urlfetch_stub.py:448] Stripped prohibited headers from URLFetch request: ['Host']
ERROR    2012-12-06 23:21:09,921 webapp2.py:1553] Invalid and/or missing SSL certificate for URL: https://api.stocktwits.com/api/2/streams/symbol/GIS.json
Traceback (most recent call last):
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2\webapp2.py", line 1536, in __call__
rv = self.handle_exception(request, response, e)
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2\webapp2.py", line 1530, in __call__
rv = self.router.dispatch(request, response)
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2\webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2\webapp2.py", line 1102, in __call__
return handler.dispatch()
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2\webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
  File "C:\Program Files (x86)\Google\google_appengine\lib\webapp2\webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
  File "C:\Users\Tank\Documents\Aptana Studio 3 Workspace\jibdantestv2\main.py", line 38, in get
sttweets = urllib2.urlopen(tickurlst)
  File "C:\Python27\lib\urllib2.py", line 126, in urlopen
return _opener.open(url, data, timeout)
  File "C:\Python27\lib\urllib2.py", line 400, in open
response = self._open(req, data)
  File "C:\Python27\lib\urllib2.py", line 418, in _open
'_open', req)
  File "C:\Python27\lib\urllib2.py", line 378, in _call_chain
result = func(*args)
  File "C:\Python27\lib\urllib2.py", line 1215, in https_open
return self.do_open(httplib.HTTPSConnection, req)
  File "C:\Python27\lib\urllib2.py", line 1180, in do_open
r = h.getresponse(buffering=True)
  File "C:\Program Files (x86)\Google\google_appengine\google\appengine\dist27\httplib.py", line 502, in getresponse
raise HTTPException(str(e))
HTTPException: Invalid and/or missing SSL certificate for URL: https://api.stocktwits.com/api/2/streams/symbol/GIS.json
INFO     2012-12-06 23:21:09,937 dev_appserver.py:3092] "GET /add_data HTTP/1.1" 500 -

Ответ 1

Я не знаю, почему у GAE возникла проблема с этим, но я заметил, что сертификат, возвращенный api.stocktwits.com, не совпадает с именем сервера в его общем имени темы (которое является ssl2361.cloudflare.com), но только на одном из его именных альтернативных имен ( "DNS Name= *. stocktwits.com" ). Возможно, альтернативы имен объектов не поддерживаются или не работают с именами подстановочных знаков, которые используются здесь. (Это будет ошибка Google/отсутствующая функция.)

Я смог воспроизвести вашу проблему и найти обходной путь, вызвав API GAE urlfetch.fetch. (Как вы знаете, на GAE urllib2 реализуется как оболочка для urlfetch.)

Начиная с строки с urllib2.Request до вашего jason.load, замените на:

sttweets = urlfetch.fetch(tickerstringst, validate_certificate=False)
stcode = sttweets.status_code

if stcode == 200:
    stresults = json.loads(sttweets.content, 'utf-8')

И ваша ошибка уходит вместе с любой гарантией, которую вы фактически принимаете с реальным сайтом (хотя трафик все равно должен быть зашифрован).

В настоящее время urlfetch.fetch GAE API docs говорят:

validate_certificateВ настоящее время базовая реализация по умолчанию имеет значение False, но в ближайшем будущем по умолчанию будет True.

Ну, добро пожаловать в будущее, потому что validate_certificate теперь по умолчанию не соответствует True.

Это, вероятно, ошибка (или отсутствие функции, если вы хотите быть добрым) в GAE urlfetch.fetch, и я рекомендую вам сообщать об этом Google как таковой.

Ответ 2

Я не слишком хорошо знаком с GAE, так что это может быть проблемой при доступе к конечным точкам API. Кроме того, может быть, вы не используете правую библиотеку Python для выполнения запросов SSL, но, поскольку вы сказали, что используете тот же код для запросов Twitter, возможно, это не так.

Не могли бы вы попытаться использовать тот же код локально или другой сервер, а не GAE?

Ответ 3

У меня была та же проблема, и я установил параметр validate_certificate в False в функции urlfetch.fetch().

    urlfetch.fetch(url, validate_certificate=false) #validates certificate

Это не помогло, и я узнал, что это внутренняя ошибка в способе обработки параметра validate_certificate. Он проверяет его, если он установлен в False, и он не проверяет сертификаты, если он True, или, по крайней мере, это то, что, по-видимому, делает.

    urlfetch.fetch(url, validate_certificate=true) #does not validate certificate