V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Nick2VIPUser
V2EX  ›  Python

[爬虫问题]请求 https 站点时, requests 中 verify 参数<CA bundle file>和<ssl client cert file>分别指的什么文件?如何获取呢?

  •  1
     
  •   Nick2VIPUser ·
    nickliqian · 2018-03-08 18:25:03 +08:00 · 7298 次点击
    这是一个创建于 2213 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用requests做爬虫(目标站点为 https 站点)时遇到以下问题:

    先贴上伪代码

    response = requests.get(url=self.url, headers=self.headers, params=self.params,
                            proxies={"https": self.get_proxy()}, timeout=5, verify=False)
    
    • 多线程访问
    • 做了 https 代理,每一段时间(约 10s )请求使用的 ip 都会不一样:

    现在的情况是

    • 使用上面的代码可以访问,但是部分请求会抛出如下异常。
    • 这部分异常请求约 30%,十分影响采集效率。
    <class 'requests.exceptions.SSLError'> HTTPSConnectionPool(host='xxxx.com', port=443):
    Max retries exceeded with url: xxxx.com
    (Caused by SSLError(SSLError("bad handshake: Error
    ([('SSL routines', 'ssl3_get_record', 'wrong version number')],)",),))
    

    网站在 chrome 上右上角具有绿色安全标识

    查找资料后

    1. 如果网站是<有效证书>,那么 verify=False 或者 True 都可以访问。
    2. 可以自己传入参数设置CA_BUNDLE文件或者具有CA 证书的目录。
    3. 可以指定一个本地证书作为客户端证书(client side certificate),可以是如下形式。
    # 设置`CA_BUNDLE`文件
    requests.get('https://github.com', verify='/path/to/certfile')
    
    # 指定一个本地证书作为客户端证书
    requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))
    requests.get('https://kennethreitz.org', cert='/path/client.cert')
    

    参考链接: http://www.python-requests.org/en/latest/user/advanced/#ssl-cert-verification

    requests 源码对 verify 和 cert 参数的注释

    :param verify: (optional) Either a boolean,in which case it controls whether we verify
    the server's TLS certificate, or a string,in which case it must be a path to a CA bundle
    to use. Defaults to ``True``.
    
    :param cert: (optional) if String, path to ssl client cert file (.pem).
    If Tuple, ('cert', 'key') pair.
    

    不理解的问题

    1. CA_BUNDLE文件或CA 证书是否就是第三方机构颁发的具有数字签名的证书?在什么情况下需要自己指定,如何获取此文件呢?
    2. ssl client cert file客户端证书文件的作用是什么?如何获取?爬虫过程中需要自己指定吗?
    3. 问题中提到的访问 SSLError 异常可能是什么导致的?

    对问题 3 的猜测

    • 使用代理 IP 一部分不支持 https。
    • 目标站点服务器对请求作了限制。

    接下来的动作

    • 了解 https 证书 /验证的基础知识
    • 读 requests 或 urllib3 关于 ssl 验证这块的源码
    • 在 github/request/issue 寻找答案

    如果您能看到这里,真的非常感谢
    如果各位老哥有了解或遇到过类似的问题可以帮忙一起讨论,灰常谢谢!

    第 1 条附言  ·  2018-03-09 10:40:48 +08:00

    补充一下我了解和分析得出的结论(关于requests的verify和cert参数):

    1. 一般情况下访问经过认证的https网站,由于verify默认为True,会从certifi库里面获取证书验证安全性。
    2. 如果将verify置为False,则不会验证https网站证书的安全性(无论是否在第三方机构认证都可以正常访问),并使用从源网站接收的公钥进行加密通信。
    3. 如果目标https站确认安全,但是证书不在certifi库里面,可以将其根证书base64编码信息添加到cacert.pem 文件末尾。也可以使用verify=/file/to/cacert.pem指定新的证书系统文件目录。
    4. 如果不需要进行SSL双向认证,也就不需要使用参数cert来自定双向验证的证书和key。
    第 2 条附言  ·  2018-03-09 11:35:00 +08:00

    在stackoverflow上看到,requests安装有两种方式:

    1. pip install requests(正常安装)

    2. pip install requests[security]

    2.1 会额外安装三个lib

    • pyOpenSSL
    • cryptography
    • idna

    2.2. 作用
    Using these packages as opposed to the default standard library options will allow for more secure SSL connections.
    使用此方式会允许更加安全的SSL链接。

    Also by default requests can't connect to some sites on OSX because of ancient OpenSSL. Using the above 3 packages makes it possible. (Donald Stufft)
    默认情况下,请求无法连接到的某些使用了老版本OpenSSL协议的站点,使用上述3个软件包即可连接。

    在Python 3.4+ 和 Python 2.7.9+版本中可能不需要。

    参考链接1:https://stackoverflow.com/questions/31811949/pip-install-requestssecurity-vs-pip-install-requests-difference
    参考链接2:https://stackoverflow.com/questions/29099404/ssl-insecureplatform-error-when-using-requests-package

    6 条回复    2018-03-09 09:54:57 +08:00
    rrfeng
        1
    rrfeng  
       2018-03-08 18:36:16 +08:00 via Android
    爬虫建议直接不验证证书
    客户端证书不需要。
    rrfeng
        2
    rrfeng  
       2018-03-08 18:36:56 +08:00 via Android
    不是 SSL 版本问题吗?还 SSL3 ?
    Nick2VIPUser
        3
    Nick2VIPUser  
    OP
       2018-03-08 21:04:21 +08:00 via iPhone
    @rrfeng 嗯,这个参数验证过,加不加上目前都没有影响。至于 ssl3 我还不太懂...
    Hardrain
        4
    Hardrain  
       2018-03-09 08:05:05 +08:00
    根据配置与调试 SSL 的经验:
    1. CA bundle file 是一个文件,包含 PEM(base64)编码的、被信任的所有根证书(CA Root)。Python 可能不使用操作系统的证书系统,就像 Mozilla 的 NSS。
    2. ssl client cert file 是用于 SSL 双向认证的客户端证书,通常还有一个对应的私钥。一般的网站不使用双向认证,故在大多数情况下无需配置。
    Hardrain
        5
    Hardrain  
       2018-03-09 08:06:09 +08:00
    @rrfeng 这个 ssl3 很可能是 OpenSSL 的代码 /API 中的命名空间。
    不表示正在使用 SSLv3
    Nick2VIPUser
        6
    Nick2VIPUser  
    OP
       2018-03-09 09:54:57 +08:00
    @Hardrain 谢谢老哥!有些懂了。
    python 访问 https 验证数字证书依赖的是 python 第三方库`certifi`(安装 requests 默认安装),`certifi`会在
    Linux 非虚拟环境路径
    ```
    /usr/local/lib/python2.7/dist-packages/certifi/cacert.pem
    ```
    或者虚拟环境路径
    ```
    /root/.virtualenvs/virName/lib/python3.5/site-packages/certifi/cacert.pem
    ```
    创建一个.pem 文件
    也就是说我去访问一个 https 网站 certifi 的 cacert.pem 文件会提供我需要验证的证书,所以能够正常访问。
    同理如果我去访问一个第三方没有授权证书的 https 网站(例如 12306 自己做的证书),我就把 12306 的 CA Root 添加到 cacert.pem 后面应该就可以正常访问了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2784 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 11:51 · PVG 19:51 · LAX 04:51 · JFK 07:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.