东亚银行、岚图汽车带你解锁 AIGC 时代的数字化人才培养各赛道新模式! 了解详情
写点什么

保护好你的秘密

  • 2013-12-02
  • 本文字数:10567 字

    阅读完需:约 35 分钟

在自由黑客和政府特工的两面夹击下,想要安全地交换数据很难。大多数安全数据交换都以公钥加密为基础,而公钥加密依赖于信任,可那些窃取数据的人都是滥用信任方面的专家。理应安全的连接也会被降级,安全级别和它最容易被攻破的薄弱点处于同一水平,并且即便最强的加密形式在私钥暴露后面对数据捕获和破解也非常脆弱。

但我们仍然有办法可以保护秘密,特别是在数据交换双方都可控的情况下。本文会介绍一些能够确保应用数据交换安全的办法,在眼下以及可预见的将来都能防止数据被泄露。还会给出应用安全技术的 Java 代码示例。此外你还将学会如何保护自己的在线访问。

信任管理机构

大多数数据交换都以公钥加密作为安全基础。公钥加密的基本原理是使用一对密钥,一把是需要绝对保密的私钥,一把是可以随意分发的公钥。这两把密钥要相互配合使用,任何持有公钥的人都可以对数据加密,而加密后的数据只能由持有私钥的你解密;并且你用私钥加密的数据只有持有公钥的人才能解密。

用公钥加密的作用很明显,因为这样其他人可以向你发送私密消息。而用私钥加密的作用不是那么显而易见,但它在保证安全方面的作用同样重要,因为它可以对消息签名。你能为任何你想发送的数据计算出一个安全摘要(一般是一个很难做逆向计算的哈希码),然后用私钥对摘要加密,并同时发送数据和经过加密的摘要。任何持有你的公钥的人都可以解密你发送的摘要,并在他们收到数据上重新计算摘要。这样他们既能确保他们收到的就是你发送的数据(如果摘要值相互匹配),又能保证确实是你发送的数据(因为用你的公钥解密了经过加密的摘要)。

公钥通常以证书的形式分发,也就是说它们会被封装在一个标明你是谁的信封内。这个信封由证书颁发机构签名,可以佐证你的身份。有些证书颁发机构是根机构,也就是说对他们自身的证书是可以直接信任的。其他机构用经由某些第三方机构签名的证书,形成了最终以某个根机构为基础的可信链条。

只要证书颁发机构完全值得信赖,这就是优秀的身份验证系统,所谓值得信赖是指证书颁发机构既要诚实又要够资格。在过去 20 年里出过一些事故,有些人能拿到冠以其他组织名称的证书,这表明某些机构达不到应有的资质水准。甚至还有更糟的情况出现,证书颁发机构本身都会受到损害,机构的密钥被盗,窃贼可以自己创建可信的证书。

Mozilla 产品 (包括 Firefox) 用 166 个受信根证书 表示至少 70 个不同的机构。看起来好像被授于这么高的信任程度的机构太多了,但这仅仅是冰山一角。还有很多机构凭借经由这些根机构签名的证书取得了信任,并且这种转授的信任还能扩展到更多层级。受信的证书颁发机构的总数量绝对数以百计,而且很可能有上千个 (没人真的知道,但 EFF SSL Observatory 在 2010 年从公共网站上找出了 650 多个)。

安全和中间人

所以浏览器(或者程序代码,比如在 Java 7 的标准版中有 81 个受信根证书)中有这么受信的证书颁发机构签发证书。这是什么情况?

当用 SSL 协议(实际上是 TLS,跟 SSL 原理相同的现代替代品)创建连接时,要依靠服务器提供的证书来保证初始数据交换的保密性。这个连接在到达服务器的路由中要经过一些中间介质,并且只要这些中间介质都是“诚实”可信的(即他们在往两边传输数据时都不会修改),那这个连接或多或少是安全的(我们后面再详细讨论或多或少)。

但如果中间介质中有一个不诚实,你就很容易遭受到中间人攻击。对 TLS 来说,最简单的中间人攻击是使用伪造的服务器证书,攻击者用由自己的私钥生成的证书冒充服务器的证书。狡诈的中间介质把这个伪造的证书发送到你的客户端,客户端就会连接到中间介质,然后中间介质再单独建立一个到服务器的安全连接。它在连接的两端中间转发数据,给你造成直接连接到服务器的假象。这样中间介质既可以看到你们发送的所有数据,也能根据需要篡改任何数据。

出现这种欺诈性中间介质的可能性有多大?很不幸,可能性非常大。路由器上经常会出现一些会被黑客(自由职业者或得到政府资助的人)攻陷的漏洞。信誉好的制造商在发现漏洞后会为路由器发布固件更新包,但我们大多数人不会更新家里或办公室里的路由器,所以它们可能会因为已知的问题被攻破。最近有报道暗示,路由器制造商在某些情况下甚至会故意在他们的路由器中制造后门 ,以方便政府部门访问(在美国讽刺性地指责中国制造商华为的所作所为中曾提到过)。

对企业级路由中的这类问题我们实在是无能为力,但对于家用和小型商用产品,我们可以用开源固件代替由制造商提供的固件。像 DD-WRT Tomato OpenWrt 之类的可选项能在大多数有线和 wifi 路由器上使用,它们既有经过强化的功能,又可以保证你运行的开源代码至少有很多人看过(不能保证没有漏洞,但至少没有那种可能是故意植入的明显漏洞)。

在某些情况下 (比如外交会议上的自由 wifi 访问),有些组织会故意使用欺诈性路由器,以便可以观察通过理应安全的连接交换的数据。规模更大的也有,互联网服务提供商可能会让政府直接访问他们的路由器

即便控制不了路由器,坏蛋们有时也能用DNS 欺骗实施中间人攻击。他们会用一个错误的主机IP 地址迷惑DNS 服务器,这个地址通常指向由坏蛋控制的系统。当你的客户端想要连接到某台主机时,它会要求DNS 服务器提供这台主机的IP 地址,而DNS 服务器就会从它的缓冲池中取出(错误的)地址给你。然后你就连到了错误的系统上,它或者直接假装成你想要连接的系统,或者自己再建立一条到初始目标系统的连接,充当欺诈性的中间介质。

所以在你每次建立安全连接时,有些人可能已经潜入到了你和服务器之间的数据交换环节中。如果真能靠证书保证数据交换双方的身份,这不是什么大问题,可惜证书做不到啊。取得客户端信任的证书颁发机构有上百(或上千)个,其中一旦有一个发出了冒充你的目标主机的证书,那他们就全都会遭受到中间人攻击。只要想到证书颁发机构的发行被黑,或者在验证身份时犯了错误就觉得相当恐怖了,但还不止这样,你还要考虑到这些证书颁发机构中有很多或者在独裁政府的直接控制之下,或者会受到他们的恐吓。所以公共认证系统实际上已经出现了破损,尽管我们还有继续使用它的必要,但绝不能认为它是安全的。

更安全的认证

你可以采取一些措施以免受到假冒证书的侵害。浏览器一般会毫无疑问地接受由受信机构签发的任何证书,但有些浏览器插件会在网站使用的证书发生变化时发出警告。以Firefox 为例, Certificate Patrol 插件 就是干这个的 (也有人提出了一个加强请求,要在 Firefox 核心代码中实现这个证书警告功能,但目前只能用插件)。用上这种浏览器插件后,当你回到之前访问过的安全网站,而它出示了一个不同的证书时,你最起码能察觉到可能出问题了,但你还要深入了解问题的细节,以决定是否相信新的证书,因为证书经常因为合法的原因而更换(包括变得太老了,因为证书也有有效期)。有些大型网站会有很多持有不同证书的服务器,访问这种网站时你也会受到警告。

在程序代码里可做的事情更多。比如你用 Java 写代码时,可以覆盖默认的证书处理机制,用更安全的技术绕过证书处理机制。这在客户端代码中很容易实现,只要把所期望的服务器证书放在密钥库中,在建立连接时只能使用这个特定的证书就可以了。下面是这种办法的样例代码,用 java.security 和 javax.net.ssl 包中的几个类来实现这种处理:

复制代码
public static void main(String[] args) throws IOException,
GeneralSecurityException {
// 打开密钥库
KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream(Constants.TRUSTSTORE_NAME);
keyStore.load(fis, Constants.TRUSTSTORE_PASS.toCharArray());
// 创建只信任这个服务器证书的信任管理器
String alg = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmfact = TrustManagerFactory.getInstance(alg);
tmfact.init(keyStore);
X509TrustManager tm = (X509TrustManager)tmfact.getTrustManagers()[0];
// 创建连接 (并确保它是安全的)
URL url = new URL(args[0]);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
if (!(conn instanceof HttpsURLConnection)) {
System.err.println("Connection is not secured!");
}
// 配置 SSL 连接,使用我们的信任管理器
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory sockfactory = context.getSocketFactory();
((HttpsURLConnection)conn).setSSLSocketFactory(sockfactory);
// 打开到服务器的连接
conn.connect();
conn.getInputStream();
System.out.println("Got connection to server!");
}

从注释中可以看到,这段代码读取包含证书的密钥库,创建一个只相信那个证书的 TrustManager ,在建立 SSL/TLS 连接时迫使它使用这个 TrustManager 。如果你试图连接到使用不同证书的服务器,认证会失败,连接被阻止。

完整的代码放在 github 代码库中的 com.sosnoski.certs.UseCert 类里。com.sosnoski.certs.GetCert 类获取由服务器提供的证书并保存在 UseCert 使用的密钥库里,所以你可以轻松地尝试一下。不过你要注意,大型安全网站可能有几台持有不同证书的服务器,所以你保存的证书有时可能不能用。

成为证书颁发机构

有时你要处理很多证书,比如当你提供了一种或多种服务,要求每个得到授权的客户端都使用各自的证书时(客户端经过 TLS 认证)。在这种情况下,为服务器维护能及时更新的信任库可能会变成巨大的管理负担,特别是在客户端证书到期需要更换时。好在你不用做这么多工作也可以维护访问控制,你可以自行建立一个证书颁发机构,并且只信任那个机构发行的证书。

有些商业或开源工具可以帮你创建这种定制的证书颁发机构。OpenSSL ( http://www.openssl.org/ ) 是其中用得最多的工具之一(尽管要实现功能完整的证书颁发机构还有更好的选择——见下一节)。从名字就能看出来,OpenSSL 是 SSL/TLS 协议的开源实现。它既能处理原有证书,也可以创建新证书,并且它可以运行在各种平台上,包括 Linux、MacOS X 和 Windows。

网上有几篇用 OpenSSL 搭建自有证书颁发机构的指南 (比如 这篇在 Ubuntu 上的),所以我们就不在这里介绍太多细节了。其基本过程相当容易,请看下面这些 Linux/Unix 终端命令 (有缩进的行,可能会因为页面宽度换行):

  1. 创建 OpenSSL 证书颁发机构的默认目录结构: ```

mkdir demoCA
mkdir demoCA/private
mkdir demoCA/newcerts
echo ‘01’ > demoCA/serial
touch demoCA/index.txt

复制代码
2. 为证书颁发机构创建公私密钥对,并把私钥导出到刚创建的目录中: ```
mkdir demoCA
mkdir demoCA/private
mkdir demoCA/newcerts
echo '01' > demoCA/serial
touch demoCA/index.txt
  1. 为证书颁发机构创建一个为期 10 年的自签名证书,并将证书导出到刚创建的目录中: ```

openssl genrsa -out ca-keypair.pem 2048
openssl pkey -in ca-keypair.pem -out
demoCA/private/cakey.pem

复制代码
4. 为用户创建公 - 私密钥对,并导出证书颁发机构发行证书的请求(在要持有证书的系统上运行): ```
openssl req -new -x509 -days 3650 -key ca-keypair.pem
-sha256 -out demoCA/cacert.pem
[respond to prompts with certificate authority identity]
  1. 对证书签名 (在证书颁发机构所在系统上运行): ```

openssl ca -out user-cert.crt -policy policy_anything
-md sha256 -infiles user-cert.req
[respond to prompts to sign and commit certificate]

复制代码
上面使用了 2048 位 RSA 密钥,目前一般认为是安全的。3072 位的密钥有更强的防护级别,而真正的偏执狂会用 4096 位的密钥。在建立安全连接时,比较长的密钥会增加一些系统开销,但除非是最繁忙的网站,否则一般不会有什么显著影响。要改变密钥长度,只要在两个“openssl genrsa ...”命令中换掉“2048”就可以了。
你自然要严格控制对证书颁发机构的访问,尤其要保证用来签发证书的私钥绝对不能泄漏。你还要建立一套管理流程,所有申请证书的人的身份和授权都要进行验证。
前面的 Java 代码很容易用到你的证书颁发机构中。只要用证书颁发机构的证书代替某个特定服务器的证书放到你的信任库中,那么任何经由那个机构签名的证书都会得到客户端的认可。根本不需要改代码。
## 机构给的,机构收回
要构建一个完备的证书颁发机构,实际上还有一项工作要做:在证书发出去之后,要能撤销。
证书撤销是指之前发行的证书不再有效,或者是因为你终止了证书持有者对服务的访问,或者因为你给他们发了新证书替换原来的证书。如果某个证书的持有者怀疑他们的系统被非法访问并且他们的私钥可能已经泄漏了,就需要做这种替换。在理想情况下绝不会发生这种事情,但为了以防万一,你应该公布一份 [CRL](http://en.wikipedia.org/wiki/Certificate_revocation_list) 并进行检查。
也可以不做直接 CRL 检查,采用比较新的替代方案, [在线证书状态协议](http://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol) (OCSP)。按照 OCSP,可以在代码中向与发行证书的颁发机构相关联的服务器发送一个请求,直接检查证书的当前状态。如果证书是用来建立安全连接的,OCSP 检查可以和建立连接同步进行,这样可以降低系统开销。连接建立好以后发现证书不对也没关系,只要在使用安全连接交换数据之前得到检查结果就行。 还有一种叫做 [OCSP 吻合](http://en.wikipedia.org/wiki/OCSP_Stapling) 的技术,服务器可以主动要求发行机构对它的证书进行检查,验证后能得到一个经过签名的时间戳,这样客户端就知道服务器的证书仍然是被证书颁发机构认可的。
如果你准备构建一个带有撤销处理的证书颁发机构,那么最好是使用 [EJBCA](http://www.ejbca.org/) 之类的工具。 EJBCA 是基于 EJB 技术的开源企业级证书颁发机构。它提供了生成和管理证书的全部功能,包括对直接 CRL 和 OCSP 的支持。
当前的大多数浏览器都默认实现了证书的 OCSP 检查。在 Java 代码中,你可以使用系统属性 **com.sun.net.ssl.checkRevocation=true** 启用证书检查, 启用 OCSP 检查的属性是 **ocsp.enable=true** ** 和 ** **com.sun.security.enableCRLDP=true** (或者非 Sun/Oracle JVM 上与之等价的属性)。
## 协商的弱点
对于欺诈性路由器或其他中间介质来说,假证书是伪造理应安全连接最直接的方式,但不是唯一的方式。客户端和服务器在建立连接时需要进行协商,而另一类攻击就是以破坏协商过程为基础。这类攻击的目标是将最终连接的安全性减弱到可以被轻易攻破的水平。
要了解这类攻击的工作原理,需要先掌握一点 TLS 的工作原理。TLS 连接使用的会话跟你在浏览器中登入网站后得到的东西类似。只不过在 TLS 中,会话在客户端和服务端是各自独立维护的,但它在两端都表示允许双方安全通信的共享状态信息。其中包括一个用来加密双方传递信息的密钥,还有用来维持安全性的序列和其他控制信息(因为 TLS 不仅有保密能力,还会做消息完整性检查,以检测信息在传输过程中是否被修改过)。
TLS 会话从一个被称做“握手”的消息交换开始。客户端先向服务器发起一个请求,告诉服务器它所支持的最高 TLS 版本、可用的加密算法套件列表(用来标识连接的安全算法),以及其他辅助信息。服务器从客户端所支持的协议版本和加密算法套件中选出一个作为响应,同时把它的证书发过去。客户端验证服务器的证书,生成一个密值,并用服务器证书中的公钥加密后发送给服务器。双方用以这个密值为基础计算出的密钥对通过安全连接交换的数据进行加密和签名。
欺诈性中间介质很可能会干扰握手的初始阶段,因为在交换第一个消息时是没有经过加密和签名的。特别是可以弱化客户端所期望的 TLS 版本和 / 或加密算法套件。比如中间介质可能会修改消息,只让客户端使用 SSL 2.0。
这个协议之所以有被降级的危险,是因为 SSL 协议的早期版本有一些众所周知的弱点。在确保连接使用了脆弱的协议后,欺诈性中间介质就可以利用一个或多个弱点来打破连接的安全性。
TLS 1.1 及更高版本对这类降级攻击做了防护,包括在握手末尾使用覆盖所有消息的签名。但这些防护有时会出现漏洞,不过至少在应用程序的数据交换中有更坚实的办法可以规避这种攻击。
## 协商强度
对付降级攻击最好办法很简单:只允许安全连接使用 TLS 协议的特定可信版本。可惜在使用浏览器时这个办法有点不切实际,因为你想用的“安全”网站可能没有及时升级它们所支持的协议。不过大多数浏览器至少还能让你把安全连接限制在比较新的协议版本上, 在狂野的 web 上也就只能这样了。
但如果连接的两端都在你的控制之下,限制协议版本这个办法非常管用,对于企业数据交换来说这是最佳实践。你应该确保无论是客户端代码还是服务端代码,两边都要强制采用这种办法。
在 Java 客户端代码中最简便的做法是用系统属性 **https.protocols=TLSv1.1** (或 **TLSv1.2**)。这种办法的唯一限制是所有安全连接都只能使用同一种协议。如果你想控制每个连接所用的协议,可以调整由 **javax.net.ssl.SSLContext** 返回的 **SSLSocketFactory** 。请参照 [github 代码库](https://github.com/dsosnoski/keep-secrets) 上的 **com.sosnoski.tls.ForceTls** 类实现。
在服务端一般用应用服务器上的选项做这个控制。比如在使用带 Java 连接器的 Tomcat 时,可以用 **<Connector>** 元素上的 **sslEnabledProtocols** 限制协议套件,所以跟上面客户端的配置相匹配的应该是 **<ConnectorsslEnabledProtocols="TLSv1.1" …/>**。而在用 APR 连接器时应该是 **SSLProtocol** 属性。
## 你说过或做过的任何事都能用来并且会被用来对付你
现在你已经见过一些让安全连接更难以被打破的技术了。但如果服务器的私钥受到损害,这些技术就全都失效了,因为任何可以访问私钥的人都可以在会话建立时解密消息查看会话密钥,然后用会话密钥解密会话中交换的所有数据。所以确保你的私钥绝对私密至关重要,千万不要把它们暴露在你自有的系统之外。
但有时私钥确实会受损,或者因为系统被黑,或者因为有访问权限的内部人士,或者因为政府的命令。如果你知道密钥已经暴露了,可以生成新的公私密钥对和新的证书,把旧证书撤销掉,这样客户端就不会再接受它(这一步很重要,否则拿到旧私钥的人仍然可以用旧证书冒充你)。但这样只是照顾到了将来的数据交换,如果窃取了私钥的人监测并记录下了以前的会话,他们仍能用旧密钥解密并查看以前会话中交换的数据。
有种安全连接的保护方法甚至连这种回溯性破解也可以防护。它被称为“完全正向保密(perfect forward secrecy)”,它为客户端和服务器端提供了一种为会话创建共享密钥的办法,而这个密钥不会暴露给任何监测数据交换的人(即便监测者能够得到服务器的私钥,只要它只是个监测者而不是中间人)。
正向保密的标准实现是采用某种 Diffie-Hellman 密钥交换。Diffie-Hellman 的基本思想是利用整数模素数群的乘法性质。计算某个数的幂在群中的值很容易,即便这个群和幂都很大也没关系。但用已知的数学知识做逆向计算非常困难,即给定一个数和一个值,很难根据这个群中的值算出这个数的幂是多少(这被称为离散对数问题)。Diffie-Hellman 密钥交换的双方都使用相同的群和原根,但所用的幂和生成的值不同,然后他们互相交换由各自的幂生成的值。最终双方都得到了一个结合了两个私密幂的共享值。任何监测数据交换的人要想得到私密幂,都要做逆向工作去解决计算困难的离散对数问题,并且只要值足够大,以现有的技术计算出结果所需要的时间让这种计算失去了实际意义。
但对浏览器来说有个坏消息,很多 web 服务器都不支持安全连接的完全正向保密。部分原因是这样会增加一些开销(用基于椭圆曲线的 Diffie-Hellman 变体代替离散对数可以降低这种开销),但经常仅仅是因为用了过时的安全实现。Google 在对正向保密的支持上非常积极主动,并且最近其他主流网站也开始支持它了。在 Chrome 浏览器中,你可以点击绿色锁图标查看某个安全站点是否使用了完全正向保密(可以在连接的详细信息中看看它是否给出了包含字母 "DHE" 的密钥交换,比如“ECDHE\_RSA”)。
{1}
在 Java 程序代码中要求使用正向保密相当容易。还是使用系统属性,**https.cipherSuites=TLS\_ECDHE\_RSA\_WITH\_AES\_128\_CBC\_SHA**。如果你想控制每条连接上的协议,可以采用跟控制协议版本号相同的办法,请参考 [github 代码库](https://github.com/dsosnoski/keep-secrets) 中的 **com.sosnoski.tls.ForceSuite** 类。
{1}
那个密码套件的名称看起来相当神秘,但如果你把它拆开来看就很好懂了。 “TLS” 自然是指 TLS 协议。 “ECDHE” 是说使用带有短暂性密钥的椭圆曲线 Diffie-Hellman 密钥交换(也就是说要为每个会话创建新密钥并且事后也不会记下来)。“RSA”表明用 RSA 非对称加密保护 TLS 握手的安全。 “AES\_128\_CBC” 是说在密码块链接模式中用带有 128 位密钥的 AES 非对称加密保护真正的数据交换。最后的 “SHA” 表明用 SHA 安全哈希算法。
{1}
这可能是在 Oracle 的 Java 7 上用 TLS 1.1 所能用到的最好密码套件。如果用 TLS 1.2 ,你可以升级成 **TLS\_ECDHE\_RSA\_WITH\_AES\_128\_CBC\_SHA256**,使用更强 (也更安全) 的 SHA2 摘要算法。理想情况下,用 GCM(伽罗瓦​​/ 计数器模式)之类的模式代替 CBC 更好,但 Oracle 的 Java 7 JSSE (Java 安全套接字扩展) 实现还不支持。
{1}
你可能还要考虑从 “**ECDHE**” 去掉“**EC**”。密码学大师布鲁斯·施奈尔现在 [推荐优先选用离散对数而不是椭圆曲线加密](http://www.theguardian.com/world/2013/sep/05/nsa-how-to-remain-secure-surveillance) (在这篇文章中还有很多非常棒的建议,教你如何保证自己以及你的数据交换的安全)。椭圆曲线技术更快,但可能会有政府组织故意引入的弱点。但大多数商业安全网站目前似乎只支持 Diffie-Hellman 的椭圆曲线版本,所以这个例子里就用它了。
{1}
在服务端一般用应用服务器上的配置选项控制密码套件。比如在使用带 Java 连接器的 Tomcat 时,可以用 **<Connector>** 元素上的 **ciphers** 属性限制密码套件,所以跟上面客户端的配置相匹配的应该是 **<Connectorciphers="TLS\_ECDHE\_RSA\_WITH\_AES\_128\_CBC\_SHA" …/>**。而在用 APR 连接器时应该是 **SSLCipherSuite** 属性。
{1}
关于 Diffie-Hellman 密钥交换还有一段有趣的历史, 它最初发表于 1976 年 (由 Whitfield Diffie 和 Martin Hellman 提出) ,但实际上几年之前英国 GCHQ(一个目前受到广泛关注的组织,因为他们对网上发生的,好吧,所有事情进行监测)就已经把它发明出来了。 GCHQ 由于某些原因不想把他们的发明成果公诸于众,于是就变成 Diffie 和 Hellman 独立发明并推出了这项技术。
{1}
## 时间与安全
{1}
安全总是相对的,并且随着密码学知识和计算机技术的不断进步,安全性会随着时间减弱。在 30 年前号称最先进的国家级安全性的东西现在可以轻松破解,并且我们有充分的理由相信这一原则在将来也同样适用。
{1}
如果能够正确实现,本文所讨论的技术可以帮你防护目前已知的最重要的攻击,包括要在合理的时间内找出会话密钥的暴力攻击(即便这种攻击来自在专用硬件上花了大钱的组织)。这应该能防止任何人成功篡改你的数据交换,并且(抛开在算法中隐藏的后门不谈)应该能够确保你的数据至少在接下来的 10 到 20 年,甚至更长的时间内是保密的。但它很可能无法保证数据在 100 或 200 年后还是保密的,如果数据被保存下来,并且有人有充分的动机要用那时侯的工具获取数据的话。对于大多数业务或个人数据来说那不是个问题,因为相对长期保密性而言,我们更加关心近期的保密性,但在考虑数据安全时记得这一点是件好事。
{1}
对于正在运行的程序,你需要每隔几年就审查一下安全协议和套件,并在恰当的时候按新标准升级程序的安全性。虽然那样仍然无法防止有人捕获并最终解密你的数据,但最起码在当前可以保护你的数据不被篡改,短期内也别人也无法查看你的数据。
{1}
## 收尾
{1}
如今数据通信安全受到的威胁很多,将来肯定还会变得更糟,尤其是考虑到政府层面的黑客行为后。一些发达国家已经有了大量的数据收集和网络破坏程序。随着网络军备竞赛不断热化,那些还没有这种程序的将来很可能也要构建了,所以即便相信你的政府不会觊觎你的数据,你也要考虑其他“不怀好意”的政府的行动。
{1}
本文介绍的办法可以让别人更难查看或修改你的数据交换。这种强化的办法是安全的重要组成部分,但远不是唯一的部分。比如说你在数据交换时用了完全正向保密机制,但如果数据只是保存在安全性很差的数据库里,那正向完全保密对数据安全也起不到多大作用。真正的安全要求围绕系统和程序做多层次防护。还要求你具备防御性思维,在证明其安全性之前,进入系统的任何东西都是可疑的。所以对你所信任的人和物一定要谨慎,保护好你的秘密!
{1}
## 关于作者
{1}
![](https://static001.infoq.cn/resource/image/91/da/910c519b991dc4d66d36ac50d092c3da.jpg)**Dennis Sosnoski** 是一名 Java 和 Scala 开发人员,有多年的数据通信和企业系统开发经验,并积累了很强的安全背景。他在全球范围内为客户提供咨询和培训服务,特别是在 web 服务领域 (包括他的 [Web 服务的安全性](http://www.sosnoski.com/security.html) 课程),他即将通过他的新网站 [Azdeo](http://www.azdeo.com) 推出保证个人数据交换安全的几个产品中的第一个。Dennis 在 Java 社区中也很活跃,经常在各种用户组和会议上演讲,为在线技术出版方供稿,为一些开源项目做贡献(包括 Apache CXF web 服务框架,他目前正在整合 WS-ReliableMessaging 和 WS-SecureConversation)。访问他的 [咨询和培训服务网站](http://www.sosnoski.com) 可以了解他的背景和服务的详细信息。
{1}
** 原文英文链接:**[Keeping Your Secrets](http://www.infoq.com/articles/keeping-your-secrets)
{1}
- - - - - -
{1}
感谢 [侯伯薇](http://www.infoq.com/cn/author/%E4%BE%AF%E4%BC%AF%E8%96%87) 对本文的审校。
{1}
给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 [editors@cn.infoq.com](mailto:editors@cn.infoq.com)。也欢迎大家通过新浪微博([@InfoQ](http://www.weibo.com/infoqchina))或者腾讯微博([@InfoQ](http://t.qq.com/infoqchina))关注我们,并与我们的编辑和其他读者朋友交流。
2013-12-02 07:335133
用户头像

发布了 45 篇内容, 共 24.3 次阅读, 收获喜欢 10 次。

关注

评论

发布
暂无评论
发现更多内容

记录:一个从0-1打磨演讲的技术专家

将军-技术演讲力教练

TypeScript 之常见类型(下)

冴羽

JavaScript typescript 翻译 大前端

我的应用 OOM 了,我该做点什么?

JavaEdge

JVM 签约计划第二季

模块五作业

心怀架构

Rust 元宇宙 12 —— 序列化和存储

Miracle

rust 元宇宙

架构训练营 - 模块五作业

VegetableBird

架构实战营 架构师实战营 「架构实战营」

模块五课后作业-设计微博系统中评论架构

断水风春

架构实战营

基于云的技术架构设计实践-第1篇

hackstoic

云计算 容器 云原生 CI/CD 签约计划第二季

Dubbo-Admin 正式支持 3.0 服务治理

阿里巴巴中间件

阿里云 云原生 dubbo 中间件 服务治理

如何掌握智识?

卢卡多多

28天写作 12月日更

模块五作业

小鹿

微博系统中”微博评论“的高性能高可用计算架构设计

stars

架构训练营

x

Nydia

自定义规则删除过期文件(linux)

liuzhen007

28天写作 12月日更

在线火星文转换器工具

入门小站

工具

模块五作业

panxiaochun

架构实战营

数据也需要滴血认亲?

Justin

大数据 数据治理 28天写作

有人问你什么是CAP?你就把这篇文章发给他

李子捌

redis CAP理论 28天写作 12月日更

架构实战营 - 模块5 - 作业

lucian

架构实战营

前端架构师神技,三招统一代码风格

杨成功

大前端 架构师 代码规范 代码格式化 签约计划第二季

架构实战-模块五

唐敏

「架构实战营」

微博系统中”微博评论“的高性能高可用计算架构

Geek_cb2b43

生产环境的线程池出问题了,我到底该如何正确使用线程池?

JavaEdge

Java java 并发 签约计划第二季

1.《重学JAVA》开篇

杨鹏Geek

Java Java 25 周年 28天写作 12月日更

从deadline和被狗追说起(2/28)

赵新龙

28天写作

Prometheus Exporter (十四)MySQL Server Exporter

耳东@Erdong

MySQL Prometheus 28天写作 12月日更

DDD 领域驱动设计落地实践系列:微服务拆分之道

慕枫技术笔记

后端 签约计划第二季

如何构建“深入浅出,喜闻乐见”的界面

Ian哥

28天写作 沟通界面 深入浅出 喜闻乐见

微博评论的高性能高可用架构设计

zjluoyue

架构实战营第五课作业微博评论高性能高可用架构

Geek_99eefd

架构实战营 「架构实战营」

微信小程序开发:新建文件报错Error:pages/xxx/xxx.json Expecting ’STRING’,’NUMBER’,’NULL’,’TRUE’

三掌柜

28天写作 12月日更

保护好你的秘密_Java_Dennis Sosnoski_InfoQ精选文章