深入浅出 HTTPS:从原理到实战
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.1 对于密码学的认知

在学习密码学之前,对于密码学需要有个基本的认知,学习的时候才能事半功倍。换句话说,对于密码学,需要明白学习的目的、方法、范围和程度。

2.1.1 基本认知

1)密码学是科学

密码学是科学,有着严格的规范,设计密码学算法需要具备深厚的数学知识,一般情况下开发者不要自行设计密码学算法,因为这存在极大的风险。

2)密码学理论是公开的

密码学算法的实现原理是公开的,读者可能觉得这观点很奇怪,很多开发者喜欢设计千奇百怪的算法,窃以为别人并不知道,其实自行设计的算法根本不具备严格的数学模型,很容易被攻破。流行的密码学算法其算法实现是公开的,经过了长时间的考验。

3)密码学算法是相对安全的

随着时间的推移,计算机的处理速度越来越快,某个密码学算法的数学基础可能受到挑战,现阶段安全的密码学算法,未来可能就是不安全的了。世界上也没有绝对安全的密码学算法,对于算法应用者来说,确保目前使用的密码学算法是安全的就可以了,潜在也说明,应用者应该长期关注密码学算法的安全性,使用最安全、最合适的密码学算法。

4)密码学攻击方法是多样化的

大部分密码学算法需要密钥,最简单的破解方法就是获取密钥,除此之外攻击方式非常多,由于算法实现是公开的,一般不会攻击算法本身。

开发者在编写应用的时候,可能会错误地使用密码学算法从而出现一些安全漏洞,而这些漏洞是攻击者的分析目标,一旦攻击成功,应用就会出现安全风险。

判断是否真正掌握密码学知识的方法就是成为一个攻击者,因为只有完整地明白密码学原理才能发起攻击。

5)密码学应用标准很重要

很多开发者可能了解某个密码学算法的用途,但由于密码学算法应用有很多陷阱,一旦使用不当,会出现很多问题,为了正确地应用密码学算法,制定了很多应用标准(比如PKCS标准)。开发者可以不了解密码学算法的原理,但是必须掌握应用标准,这样才能编写出更安全的软件。

6)不具备很强的数学知识也能掌握密码学

密码学是基于数学模型的,要真正明白密码学原理,必须具备很好的数学知识,很多密码学算法的创建者都是数学家而非计算机编码专家,就说明了这一点。对于开发者来说,没有掌握密码学算法的原理并不妨碍应用密码学算法。

这有点像学习PHP开发语言一样,虽然并不知道PHP实现原理,但是基于PHP手册,仍然能够编写出好的应用,但如果明白PHP实现原理,能编写出更优秀的软件。

同理对于密码学也是如此,首先要明白特定密码学算法解决了何种问题,其次根据标准正确地使用密码学算法。

7)解决特定问题的密码学算法

世界上不存在一种密码学算法,能够解决所有的安全问题,每种算法有特定的应用场景,只能解决特定的问题。在思考安全解决方案的时候,必须具体问题具体分析,比如解决HTTP安全问题的时候,首先分析它存在的核心问题,然后思考每个问题是否能够通过某个算法解决,最终结合这些算法提出了一个解决方案,这个解决方案就是HTTPS,它是协议而非算法,是对多种密码学算法的工程应用。

在使用密码学算法的时候也不要画蛇添足,一个简单的软件为了保障安全性可能使用一种密码学算法即可,没有必要组合多种密码学算法。

对于读者来说,初次接触这些原则的时候,可能并不能很好地理解,希望读者读完本章,能够回顾这些原则。

密码学算法是安全的基石,当面对一个安全工具的时候(比如SSH、Shadowsocks),能够分析出其背后的密码学原理,那么就足够优秀,如果能编写出安全的应用,那就锦上添花了。

2.1.2 密码学的四个目标

在基于互联网通信的应用中,密码学主要解决四个问题,HTTP出现的三个核心问题就是要解决的目标,而掌握了HTTPS的原理,基本上就掌握了密码学知识。

1)机密性(隐私性)

在网络中传递的数据如果具备机密性,那么传输的数据就是一串无意义的数字,只有拥有密钥的才能解释这些数据,密钥是加密算法的关键。在密码学中,对称加密算法和公开密钥算法都能够保证机密性。

2)完整性

完整性表示接收方能够确保接收到的数据就是发送方发送的原始数据,假设数据被中间人篡改,接收方如果有策略知晓数据被篡改了,那么传递的数据就具备完整性。

在密码学中,主要使用消息验证码(MAC)算法保证完整性。需要注意的是互联网传输的数据即使是加密的也无法保证完整性,本章后续部分会进行详细的描述。

3)身份验证

互联网应用一般都有发送方和接收方,对于接收方来说,必须确认发送方的身份,才能确保收到的数据就是真实发送方发送的。反之对于发送方来说也是一样的,通信双方必须确保对端就是要通信的对象。在密码学中,一般使用数字签名技术确认身份。本章后续部分也会解释消息验证和身份验证的区别。

4)不可抵赖性

这个目标在第1章没有涉及,举个例子,A向B借钱了,并写了张借条,当B希望A还钱的时候,A抵赖说这张借条不是他写的,理由就是有人冒充他写了这张借条,A的行为可以抵赖。在密码学中,数字签名技术能够避免抵赖。

2.1.3 OpenSSL

密码学原理是公开的,在工程上需要实现各种算法,最著名的就是OpenSSL项目,包括了底层密码库和命令行工具,大部分Linux发行版都预装了OpenSSL库。

很多应用软件都不是自行实现各种密码学算法,一般都直接调用OpenSSL密码库。读者会问为什么很多大公司不基于原理自己实现算法呢?原因其实很简单,还是安全,虽然密码学算法原理是公开的,但是在实现算法逻辑的时候可能会有问题,从而出现安全问题,选择合适的密码学算法库很重要。

OpenSSL是密码学中一个非常流行的底层密码库,相对来说是值得信赖的,本章为什么会提到OpenSSL命令行呢?接下来会讲解各种密码学算法,笔者只会从应用的角度讲解密码学算法,不会深入内部细节,重点是正确地使用密码学算法,为了避免枯燥,会用OpenSSL命令行和PHP语言演示一些密码学算法应用的例子,PHP语言大部分内置的密码学函数也基于底层的OpenSSL库。

OpenSSL命令行也是不断迭代的,尽量使用最新版本,这样安全性和性能更有保障,读者在学习OpenSSL命令行的时候可能会很茫然,原因如下:

◎OpenSSL命令行功能非常强大,有很多的子命令和参数,如果不理解密码学算法,根本无法理解子命令和参数的含义,这是难学习的根本原因,也说明学习OpenSSL之前必须先掌握密码学算法。

◎不同版本的OpenSSL命令行工具在使用的时候有一些差别,同样一条命令,读者会发现在特定版本下可能无法正确运行。

◎OpenSSL命令行的帮助手册和文档描写得不是很通俗,很难进行系统的学习。

◎完成同样一个操作,OpenSSL命令行有许多方法实现,这可能会干扰读者的学习。

本章应用的OpenSSL命令行运行环境如下:

◎Ubuntu 14.04.5 LTS系统。

◎OpenSSL 1.1.0f。

如果读者没能成功运行示例,建议参考帮助文档,为了更好地学习OpenSSL命令行工具,下面讲解一些使用OpenSSL的技巧。

1)查看OpenSSL版本

    $ openssl version
    OpenSSL 1.1.0f  25 May 2017

2)查看所有OpenSSL支持的命令

    $ openssl help

    Standard commands
    asn1parse       ca              ciphers         cms
    crl             crl2pkcs7       dgst            dhparam
    dsa             dsaparam        ec              ecparam
    enc             engine          errstr          exit
    gendsa          genpkey         genrsa          help
    list            nseq            ocsp            passwd
    pkcs12          pkcs7           pkcs8           pkey
    pkeyparam       pkeyutl         prime           rand
    rehash          req             rsa             rsautl
    s_client        s_server        s_time          sess_id
    smime           speed           spkac           srp
    ts              verify          version         x509

可见OpenSSL命令行有非常多的密码学工具。

3)获取算法的帮助信息

如果要获取RSA算法的帮助信息,则可以输入如下命令,可以显示大部分可用的参数:

    $ openssl rsa --help

    Usage: rsa [options]
    Valid options are:
     -help              Display this summary
     -inform format     Input format, one of DER NET PEM
     -outform format    Output format, one of DER NET PEM PVK
     -in val            Input file
     -out outfile       Output file
     -pubin             Expect a public key in input file
     -pubout            Output a public key
     -passout val       Output file pass phrase source
     -passin val        Input file pass phrase source
     -RSAPublicKey_in   Input is an RSAPublicKey
     -RSAPublicKey_out  Output is an RSAPublicKey
     -noout             Don't print key out
     -text              Print the key in text
     -modulus           Print the RSA key modulus
        -check             Verify key consistency
        -*                 Any supported cipher
        -pvk-strong        Enable 'Strong' PVK encoding level (default)
        -pvk-weak          Enable 'Weak' PVK encoding level
        -pvk-none          Don't enforce PVK encoding
        -engine val        Use engine, possibly a hardware device

为了了解算法的详细使用信息,也可以输入如下命令:

        $ man rsa

4)构建特定版本的命令行工具

如果读者机器上的OpenSSL命令行版本不是OpenSSL 1.1.0f,但又不想升级操作系统内置的OpenSSL库,则可以在自己的工作目录编译,构建一个专属的OpenSSL库,避免和系统的OpenSSL库冲突。

        #下载二进制包并解压缩
        $ wget https://www.openssl.org/source/openssl-1.1.0f.tar.gz

        $ tar xvf openssl-1.1.0f.tar.gz
        $ cd openssl-1.1.0f

        #查看安装手册
        $ more INSTALL

        #查看config
        ./config --help

        #安装并编译,安装目录不要和系统目录冲突
        $ ./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl

        $ make
        $ make test
        $ make install
        $ make clean

        #运行安装的OpenSSL
        $ /usr/local/openssl/bin/openssl version
        OpenSSL 1.1.0f  25 May 2017

总结说来,使用OpenSSL命令行最忌惮复制粘贴,不同参数在特定子命令下含义也可能是不一样的,需要明白子命令和参数的内在共性,善于利用帮助手册才是正道。