zoukankan      html  css  js  c++  java
  • https如何使用python+flask来实现

    摘要:一般http中存在请求信息明文传输,容易被窃听截取;数据的完整性未校验,容易被篡改;没有验证对方身份,存在冒充危险。面对这些问题,怎么破?

    一、为什么要用https

    一般http中存在如下问题:请求信息明文传输,容易被窃听截取;数据的完整性未校验,容易被篡改;没有验证对方身份,存在冒充危险。

    HTTPS又有哪些优势?

    1、使用HTTPS可认证用户和服务器,确保数据发送到正确的客户机和服务器。

    2、HTTPS是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。

    3、HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。

    二、https中的证书是什么

    CA:证书授权中心( certificate authority)类似于国家出入境管理处一样,给别人颁发护照;也类似于国家工商管理局一样,给公司企业颁发营业执照。它有两大主要性质:

    • CA本身是受信任的,国际认可的;
    • 给他受信任的申请对象颁发证书。 和办理护照一样,要确定你的合法身份,你不能是犯罪分子或造反派。当然,你需要被收保护费,同时,CA可以随时吊销你的证书。

    CA 的证书 ca.crt 和 SSL Server的证书 server.crt 是什么关系呢?

    • SSL Server 自己生成一个 私钥/公钥对,server.key/server.pub 。server.pub 生成一个请求文件 server.req。 请求文件中包含有 server 的一些信息,如域名/申请者/公钥等。
    • server 将请求文件 server.req 递交给 CA,CA验明正身后,将用 ca.key和请求文件加密生成 server.crt由于 ca.key 和 ca.crt 是一对, 于是 ca.crt 可以解密 server.crt。
    • 在实际应用中:如果 SSL Client 想要校验 SSL server.那么 SSL server 必须要将他的证书 server.crt 传给 client.然后 client 用 ca.crt 去校验 server.crt 的合法性。如果是一个钓鱼网站,那么CA是不会给他颁发合法server.crt证书的,这样client 用ca.crt去校验,就会失败。

    三、生成证书与密钥

    shell脚本

    #!/bin/bash
    
    PROJECT_NAME="https Project"
    
    # Generate the openssl configuration files.
    cat > ca_cert.conf << EOF
    [ req ]
    distinguished_name     = req_distinguished_name
    prompt                 = no
    
    [ req_distinguished_name ]
     O                      = $PROJECT_NAME Certificate Authority
    EOF
    
    cat > server_cert.conf << EOF
    [ req ]
    distinguished_name     = req_distinguished_name
    prompt                 = no
    
    [ req_distinguished_name ]
     O                      = $PROJECT_NAME
     CN                     = 
    EOF
    
    cat > client_cert.conf << EOF
    [ req ]
    distinguished_name     = req_distinguished_name
    prompt                 = no
    
    [ req_distinguished_name ]
     O                      = $PROJECT_NAME Device Certificate
     CN                     = 
    EOF
    
    mkdir ca
    mkdir server
    mkdir client
    
    # 生成私钥
    openssl genrsa -out ca.key 1024
    openssl genrsa -out server.key 1024
    openssl genrsa -out client.key 1024
    
    # 根据私钥创建证书请求文件,需要输入一些证书的元信息:邮箱、域名等
    openssl req -out ca.req -key ca.key -new -config ./ca_cert.conf
    openssl req -out server.req -key server.key -new -config ./server_cert.conf
    openssl req -out client.req -key client.key -new -config ./client_cert.conf
    
    # 结合私钥和请求文件,创建自签署证书
    openssl x509 -req -in ca.req -out ca.crt -sha1 -days 5000 -signkey ca.key
    openssl x509 -req -in server.req -out server.crt -sha1 -CAcreateserial -days 5000 -CA ca.crt -CAkey ca.key
    openssl x509 -req -in client.req -out client.crt -sha1 -CAcreateserial -days 5000 -CA ca.crt -CAkey ca.key
    
    mv ca.crt ca.key ca/
    mv server.crt server.key server/
    mv client.crt client.key client/
    
    rm *.conf
    rm *.req
    rm *.srl

    一些命令的解释

    openssl genrsa [-out filename] [-passout arg] [-des] [-des3] [-idea] [numbits]
    
    选项说明:
    -out filename:将生成的私钥保存至filename文件,若未指定输出文件,则为标准输出。
    -numbits:指定要生成的私钥的长度,默认为1024。该项必须为命令行的最后一项参数。
    -des|-des3|-idea:指定加密私钥文件用的算法,这样每次使用私钥文件都将输入密码,太麻烦所以很少使用。
    -passout args:加密私钥文件时,传递密码的格式,如果要加密私钥文件时单未指定该项,则提示输入密码。传递密码的args的格式
    
    openssl req -out ca.req -key ca.key -new -config ./ca_cert.conf
    主要命令选项:
    -new :说明生成证书请求文件
    -key :指定已有的秘钥文件生成秘钥请求,只与生成证书请求选项-new 配合。
    -out :指定生成的证书请求或者自签名证书名称
    
    openssl x509 -req -in ca.req -out ca.crt -sha1 -days 5000 -signkey ca.key
    openssl x509命令具以下的一些功能,例如输出证书信息,签署证书请求文件、生成自签名证书、转换证书格式等。
    -in filename:指定证书输入文件,若同时指定了"-req"选项,则表示输入文件为证书请求文件,再使用"-signkey"提供自签署时使用的私钥。
    -out filename:指定输出文件
    -days: 指定证书的有效时间长短。缺省为30天

    四、安装flask

    需要安装python 的 openssl 的类库,使用pip 安装

    pip install pyOpenSSL

    五、https单向认证握手流程

    python实现

    server端:

    from flask import Flask
    app = Flask(__name__)
    
    @app.route('/login')
    def hello_world():
        return 'Hello World!'
     
    if __name__ == '__main__':
        app.run(host="0.0.0.0", port=8091, ssl_context=('server.crt', 'server.key'))

    客户端:

    import urllib.request
    
    import ssl
    
    if __name__ == '__main__':
        CA_FILE = "ca.crt"
        context = ssl.SSLContext(ssl.PROTOCOL_TLS)
        context.check_hostname = False
        context.load_verify_locations(CA_FILE)
        context.verify_mode = ssl.CERT_REQUIRED
        try:
            request = urllib.request.Request('https://127.0.0.1:8091/login')
            res = urllib.request.urlopen(request, context=context)
            print(res.code)
            print(res.read().decode("utf-8"))
        except Exception as ex:
            print("Found Error in auth phase:%s" % str(ex))

    六、https双向认证握手流程

    python实现

    客户端:

    from flask import Flask, request, Response
    import json
    
    app = Flask(__name__)
    @app.route("/login")
    def hello():
        return "Hello World!"
    @app.route('/login1', methods=['POST'])
    def login():
        username = request.form.get("username")
        password = request.form.get("password")
        login_config = {
            "name": "pwd1"
        }
        if username in login_config.keys():
            if password == login_config[username]:
                return Response(json.dumps(True), status=200, mimetype='application/json')
    
        return Response(json.dumps(False), status=200, mimetype='application/json')
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=8091, ssl_context=('server/server.crt', 'server/server.key'))

    客户端:

    import urllib.request
    
    import ssl
    
    if __name__ == '__main__':
        CA_FILE = "ca.crt"
    
        context = ssl.SSLContext(ssl.PROTOCOL_TLS)
        context.check_hostname = False
        context.load_verify_locations(CA_FILE)
        context.verify_mode = ssl.CERT_REQUIRED
        dict = {
            "username": "name",
            "password": "pwd1",
        }
        data = urllib.parse.urlencode(dict).encode('utf-8')
        try:
            request = urllib.request.Request('https://127.0.0.1:8091/login')
            res = urllib.request.urlopen(request, context=context)
            print(res.code)
            print(res.read().decode("utf-8"))
        except Exception as ex:
            print("Found Error in auth phase:%s" % str(ex))
        try:
            request = urllib.request.Request('https://127.0.0.1:8091/login1', data=data, method='POST')
            res = urllib.request.urlopen(request, context=context)
            print(res.code)
            print(res.read().decode("utf-8"))
        except Exception as ex:
            print("Found Error in auth phase:%s" % str(ex))

    参考链接

    openssl 命令(1): openssl req 命令详解

    openssl简介-指令x509

    openssl 命令(3): openssl x509命令详解

    OpenSSL命令—pkcs12

    十分钟搞懂HTTP和HTTPS协议?

    Https单向认证和双向认证

    python关于SSL/TLS认证的实现

     本文分享自华为云社区《https如何使用python+flask来实现》,原文作者:SNHer 。

    点击关注,第一时间了解华为云新鲜技术~

  • 相关阅读:
    Fetch超时设置和终止请求
    Base64编码
    H5与企业微信jssdk集成
    构建multipart/form-data实现文件上传
    WebWorker与WebSocket实现前端消息总线
    netty源码解析(4.0)-22 ByteBuf的I/O
    netty源码解析(4.0)-21 ByteBuf的设计原理
    netty源码解析(4.0)-20 ChannelHandler: 自己实现一个自定义协议的服务器和客户端
    netty源码解析(4.0)-19 ChannelHandler: codec--常用编解码实现
    netty源码解析(4.0)-18 ChannelHandler: codec--编解码框架
  • 原文地址:https://www.cnblogs.com/huaweiyun/p/14689416.html
Copyright © 2011-2022 走看看