开发者学堂课程【高校精品课-上海交通大学-企业级应用体系架构:Security2.2】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/75/detail/15826
Security2.2
内容介绍
一、学前框架
二、消息摘要如何实现
三、非对称密钥对如何生成
四、对称密钥
五、single sign-on
一、学前框架
SECURITY
-DIGITAL SIGNATURES
- CODE SIGNING
-ENCRYPTION
Single Sign-On
-Overview
-.Kerberos protocol
·Design Tactics of Security
那这节课我们主要讲三部分,第一部分是延续刚才讲的完成体系。我们刚才讲的是有关培训机构的认证,然后上节课讲过 Godebuee。我们说,还剩一种 Signer:实际上所有内容围绕着这个。签名是比较复杂的问题,所以我们要讲所谓的签名是怎么回事儿,然后代码证书加密的方式来做,加密是怎么回事儿?然后谈谈 Single Sign-On
这个 count 这样的单点认证怎么实现,也就是所有的应用,较大的应用为什么都到 count 认证一下就可以。理解-.Kerberos protocol的意思。
·To give more trust to an appletwe need to know two things
- Where did the applet come from?
- Was the code corrupted in transit?
如果要对一个代码进行处理,那么前面在说做授授权时,都是说代码在哪里,或者是谁在执行代码。如果关心的不是这个问题,前两个都是说这个代码一定是可信的。只不过关心是谁在之前要把他带来。现在关心的是说这个代码从哪儿来?或者这个代码是谁开发的。这个代码,如果我信任他,比如这是顾客开发,但是这个代码再传递给我的过程当中有没有被毁坏的,比如有人故意的恶意在代码插入一些东西。我们想去验证这两个事情,验证这两个事情需要用到签名。
从最简单的来说。首先说一段信息给你,你怎么知道这一段信息有没有篡改过,他用到一个消息摘要。消息摘要就是你给我一块儿数据,小到一个 bit , 大到比如十个 T 。反正都要生成一个固定长度,也就160bit,就是20个字节,这个东西叫做它的一个数字指纹,那你可以用很多相关的这个算法来生成,比较常见的就是比较SHA多少,现在我们常用的是SHA 2 5 6。用这样的一个算法来做实验。SHA 2 5 6就是安全的哈希算法的一个缩写。不管你给我的这个数据库儿多大我都给你生成一个二的160次方多种当中一种的一个摘要。
有2的160次个,每一种有2个取值。理论上他应该有二的一百六十四方不同的指纹,足够分发到非常大,足够就表示不同的数据段。消息摘要有两个特点:
第一个是如果给10T的数据。你里面只改一个 bit 。按照安全哈希算法算出来的摘要完全不同。也就是这个摘要这20个字节。如果在实体的数据改一个地方,首先他绝对不会出现说这20个字的一模一样,其次,甚至都不会出现20个字节里面只有 1bit 或者 2bit 不一样。这里面可能有一半儿的变化。消息一旦被篡改,很容易从摘要判断出来。一段消息这块生成一个摘要,这块生成一个摘要,改了一个bit。摘要对不上,而且差异非常大第二。
第二:它是二的160次,这个摘要确实想改,但为了维持这个摘要不变。那我去想办法把这10bit里很多地方都改改,改后的摘要不一样。这个可能性很小,因为二的160次太大,想找出来两个几乎一样的摘要不太可能。
为什么一定要把摘要改成要保持摘要一样,想象一下场景:有一个百万富翁的老父亲。他要去世了,他写了遗嘱,这个遗嘱写了一遍,他会把他的遗产分配给他所有的孩子,但是照着这个小孩儿他可能不孝顺,告诉他里面专门说他是没有办得到任何东西。除此之外,还有一个他写完这个东西之后,他就会把这个给律师来保存。然后他会说对着这个具体的内容生成一个摘要。就是一个安全哈希算法的一个指纹。
他给另外一个作为公证员的另一个律师。律师 A 不认识律师 B ,当老头去世之后,A 和 B同时出现,一个拿摘要,一个拿遗嘱。大家算一下,看这两个能不能对上。如果对上这份遗嘱才有效,否则就无效。这时候对于孩子来说,他想要这个财产要重新分配,按照它的利润分配。于是找到律师,他说咱们改个地址。律师A可能受不了他的贿赂,同意。把里面这个名字修改。问题是公正人拿着这个摘要,改成他之后生成的摘要。上面完全不同。那对于他来说,他只有另外一种做法,就是除了把名字改成这个,还要改点儿其他东西,加点儿摘要,让最后生成的跟原来一模一样,这样在数学上做不到。所以就断掉她去修改遗嘱的念想。这就是消息摘要做的事情。
消息摘要如何实现
MessageDigest alg = MessageDigest.getInstance("SHA-1");
InputStream in = ... int ch;
while ((ch=in.readO)!= -1) alg.update((byte) ch);
bytel] bytes =...; alg.update(bytes);
byte[] hash = alg.digest0;
Java 有关加密解密的代码全部都使用工厂类的实例,第一个就是MessageDigest.getInstance 传递给他一个算法,这个算法拿过来之后生成一个摘要对象,然后把需要的加密的东西一个字节,一个字节的读取,生成的字节放进去之后。最后在上面生成一个 alg.digest0方法。就直接获取到了一个20个字节构成了这样的一个摘要。方法很简单。
消息摘要有两个问题,就是摘要的算法公开,比如后来提到的SHA256.如果这个人,他说把a和B都贿赂。把摘要也重新生产。摘要和遗嘱就可以对上。所以在这种情况下会发现,如果有人伪造消息,并且重新计算摘要。数字签名是必须要解决的问题。
数字签名什么意思?
界面里面用到的是非对称密钥对。有一个是公钥,要有一个是私钥。公钥和私钥呢的特点就是从公要想去推对应的资料推不出来。反过来,总公司要去推它对应的公钥推不出来,然后用公钥加密的东西。用私钥解就可以解开。公钥加密的东西,公钥自己解不开。反过来就像公钥加密的东西。私钥解可以解开。私钥加密的东西,私钥不可以解开。
它的工作原理必须是一个用一个加密,就要用另外一个解。自己加密,自己解不开。这样的一个特点放在这里,他俩互相推不出来,要生成这样的一个密钥对,私钥必须要保存本地,不能给任何人。公钥是公开的,给所有人。以后你发消息,我就用你的私钥去对这个消息做一下加密,然后别人拿公钥解开,如果一拿公钥解开,就能证明这条消息确实是你发的。
所以现在的事情会变成这样:
这个摘要在生成之后,我们刚才说如果直接给律师,律师A和B如果都被收买,就可以成功,摘要一旦生成。要用一个私钥去对它加密,这个私钥是老头儿的,在妻子手里,然后加密之后,将来这个东西用老头儿的公钥,公钥是任何人都有。私钥加密之后的摘要只能用公钥解开,而且只能是老头儿的私钥解开。一旦解开,就证明这个摘要确实是老头的。用去私钥加密过之后的摘要去给律师 B 。就算收买了律师 A 和律师 B 也没有办法,虽然篡改了消息也可以生成摘要,但没有办法拿到老头的私钥。就没有办法对摘要去做加密,未来就不可能拿老头儿的公钥解开。所以篡改不了摘要,遗嘱没法篡改。所以摘要需要再做一次加密。私钥加密,公钥解密。这种方式安全。
三、非对称密钥对如何生成
keytool -genkeypair -keystore alice.certs-alias alice
java有一个工具叫做 keytool 。下载那个JDK,genkeypair 这个要生成一个密钥,你比如说有family ,你是家里的密钥库。
alice.certs-alias alice的意思是要生成一个密钥,名字叫alice。alice有一对密钥,有公钥有私钥,密钥可以导出来,导出来是公钥,别人拿到之后会解密。发东西,验证这个人。用密钥的方式不是在加密信息。而是在证明这个信息是你写的,所以你要把公钥发出去,让别人能解密。你的资料加密之后。证明这个新的摘要。像刚才里面看到需要证明这老头写的,不是别人写的。这个公钥再导出来的时就要导出证书。就是在浏览器里面看到,你信不信任谁,比如说这个网站证书要不要放进去。这个公钥能以证书形式分发给别人,别人给你拿到公钥去做他的事情。就可以解密他的信息
运行代码:
发现信息。代码中会看到有这样的东西。根据你发送的消息。然后根据当前的时间,还有一些随机数。生成密钥,显然两次运行生成的密钥都不一样,因为他的长度很长。可能超过20个,两次运行生成的密钥的概率非常非常小。几乎不存在。
导出目录,在 alice.certs 创建,导出alice,文件名为 alice.cer。
- keytool-exportcert-keystore alice.certs-alias alice -file alice.cer
导出来之后,可以用证书去写alice 的信息,就知道是不是alice 发的,但是你可能会有这样的疑问,alice 通过邮件给你发这个邮件,会不会在传输过程当中被人改?所以可以把这个证书给他打印出来,打印出来如下图:
然后打个电话给alice。说把证书已经导入了,打印出来了,看了一下里面的信息,如果说明他有问题,就不要了,如果认为是合理的,它没有被修改过,没有被篡改过,就把它导入到系统去使用
现在浏览一个网站,这个网站说要给一个证书。经常会碰到这样的情况。只要给个证书,要不要,他们有没有问题,这个问题呢,一会儿解决。
- keytool-importcert -keystore bob.certs -alias alice -file alice.cer
假设alice把这个证书发给 Bob 。打印出来这些东西以某种方式去验证,比如打电话过来。而且 Bob 认识alice,她有意愿到才能去导入。导入之后指定他的库, 从 alice.cer 导。Bob有了alice的公钥以后,就可以用alice的公钥来解密爱丽丝,用私钥加密验证。
alice写了一个文件,jar文件就是 zip 格式的一个文件。有rar格式,并且用jarsinger工具来进行压缩,意思是要用alice的密钥来进行加密,注意目的不是消息要加密,是要让被人知道,然后BOB就去验证是谁发送过来,去密钥库寻找看有没有能解开的密钥,如果解开就是信任的人,反之不是,验证的时候会报这样的结果。
反之会报错。
Document.jar的意思不是不让看,签名的目的是证明这是一个可信任的jar,而不是不让别人看,里面是alice的公钥,本身不是为了加密,而是验证身份。
一个人给了公钥要问他的方式复杂,陌生人给的公钥不敢随意使用,假如虽然是陌生人,但是有共同认识且信任的人,那么就可以直接导入。这个问题所有的压力都在共同认识的人身上。就会发生下图情况:
这个人也有一对密钥,陌生人给你一个密钥导入时,会把公钥钥给共同的朋友,这个人用自己的私钥加密,指签名,签名的目的是在上面再产生一个私钥,就是证书,然后用朋友的公钥能解开,那么这个东西就是朋友发送的,所以可以信任,可以导入,证书就是一个信任的第三方的私钥加密后的东西,比如新浪提供一个证书给你导入,但是新浪没有听说过,但是有专门的担保公司,新浪会把公钥给担保公司,担保公司用私钥签名成一个证书,到处分发,你拿到证书后就可以导入与新浪进行通信。但是证书解开后会发现证书不是新浪造的,但是是信任的担保公司造的,所以导入后就有了新浪的公钥。以后每次新浪发信息就用它的私钥进行加密,然后用公钥解开后就会发现这是新浪发送的消息,这就是网络上满天飞的证书,证书就是一个公司的公钥在一个权威公司用私钥进行加密的证书,信任才可以导入,为何信任他,有专门的收费公司负责这种事情,但是这种公司有收费与免费,分1234类证书,会有提示收费级别证书,可以根据自己判断是否信任他,浏览器经常弹出信任不信任。免费的证书马上就给,但是没有担保,对面一份责任也不担。要不要用取决于自己。所以经常碰到证书有没有过期,要不要处理掉。
假如alice要给他同事cindy发一个签名之后的消息,但是cindy并不认识或他可能不知道alice是谁,但是满天飞的证书,他不可能都导入,只能有权威机构,所以就整个这公司里有一个部门,CA 就是证书的一个认证权威机构,这个机构发送过来的证书才导入。每个人都有 CA 的公钥,然后alice在想把他的密钥发给 cindy 时,CA 就会去对每一个员工的密钥进行签名,当签名之后的证书发给 cindy 之后,cindy就可以用 CA 的公钥去解开证书,解开后说明没有被篡改,可以信任,可以导入密钥库。
生成一个新的密钥库:
在 acmesoft.certs 生成一个密钥 acmeroot ,然后将密钥导入acmeroot .cer 文件 ,每个人都会把公钥导入自己的密钥库,然后以后只要是用 acmeroot 签名后的证书都信任,可以看到acmeroot 签名后的爱丽丝证书是被信任的,所以就可以把它导入到 cindy 的密钥库。
代码签名就是签名的对象是这个代码,就可以知道代码是不是某一个人开发?经过谁签名?只有这种代码可以信任。
在 acmesoft.certs 生成一个密钥 acmeroot ,将 acmesoft.certs 密钥导出,导到自己的库,将代码开发出来后,分jar包,对他进行签名:
jarsigner -keystore acmesoft.certs FileReadApplet.jar acmeroot用 acmeroot ,用 acmesoft.certs 密钥进行签名。
grant signedBy "acmeroot" {
签完之后别人就可以知道这个是 acmesoft 开发的。grant 是signdBy,意思是被谁签过名。被 acmeroot 签名之后就可以得到
permission java.lang.RuntimePermission "usePolicy";
permission java.io.FilePermission "/etc/*", "read",
就可以使用 usePolicy ,或者 "/etc/*", "read"。第三种授权方式是signdBy。
这是在访问网站时弹出的弹窗,一个你要不要信任的证书,如果信任可以进入,如果想看细节,第二个标记点点击就可以观看证书内容来决定要不要信任他,证书大家经常看到,基于证书的授权,要去看到底是谁用哪个证书对代码签过名。当 jar 包下载下来后,别人进行签名后,除非是他签名,不然其他代码没有权限。
上述过程主要叙述是谁开发。
四、对称密钥
比如 privatekey 对一个东西进行签名 publickey 进行解密。目的是让别人知道这个东西确实是我放出去的,如果不想让别人看见,就对这个内容进行加密,第一种用对称密钥,对称密钥指加密密钥和解密密钥是同一个密钥,与 privatekey 和 publickey 不一样。 对称密钥速度比较快。用同一套密钥,加载同一条程序,非对称密钥在数学上来说执行速度比较慢,虽然安全,但效率低下。
Cipher cipher=CiphergetInstance(algorithName);
- or Nfucton
Cipher cipher =Cipher.getInstance(algorithName, providerName); -The JDK comes with ciphers by the provider named"SunJCE".
-The algorithm name is a string such as "AES" or"DES/CBC/PKCS5Padding".
int mode = ...; Key key = .. .; cipherinit(mode, key);
- The mode is one of
CipherENCRYPT_MODE
CipherDECRYPT_MODE
CipherWRAP_MODE
CipherUNWRAP MODE
对称密钥仍然是工厂类 CiphergetInstance 。传递算法名字“algorithName”传递算法名后生成一个加密器,加密器得到之后就可以进行处理,加密上传:as "AES" or"DES/CBC/PKCS5Padding".
丢给他之后它就会对字节流进行处理,去进行加密或者解密,细节由
CipherENCRYPT_MODE
CipherDECRYPT_MODE
CipherWRAP_MODE
CipherUNWRAP MODE
来描述。
操作方法与上述类似,产生一个字节流,然后 update 将一个一个加入,或者把字节数给他,之后他做一下do.final。就产生了加密之后的字节,do.final 要做一个panding 的操作,他加密时每个算法都是每隔多少字节,比如每隔8次字节加一次密,最后文件长度不是8个字节,就会由下图:
进行处理,补充填齐8个字节,差7个补七个07,差6个补6个06以此类推,这就是用算法对输入的字节所有的数组做加密,加密的算法可以是上述方法,也可以是x=x+2这种类型的算法。保证加密后原始的字节流按照解密算法进行加密。注意:加密后的字节流的长度不需要与加密算法一样,可能不一样,可能变多,可能变少,取决于单列算法。
KeyGenerator keygen =KeyGeneratorgetInstance("AES)) SecureRandom random=new SecureRandom(); keygen.init(random);
Key key = keygen.generateKey(); Or
SecretKeyFactory keyFactory=SecretKeyFactorygetInstance("AES") byte[] keyData = ...; // 16 bytes for AES
SecretKeySpec keySpec =new SecretKeySpec(keyData,"AES"); Key key =keyFactorygenerateSecret(keySpec)
对称加密的密钥也是通过 keytool 或者编程的方式来得到,用代码的方式 KeyGeneratorgetInstance 生成一个 AES 密钥生成器,然后生成一个安全的SecureRandom()。用random随机数做种子, SecureRandom()做算法,拿这个算法与种子去生成对称密钥keygen.generateKey( ) ,之后就可以进行,得到之后就可以进行统计。
如果数据源源不断的来,该如何加密,对应的是一个流,而不是字节数组,大同小异,不讲解。
需要讲对称密钥的缺点,密钥如何分发,对称密钥加密与解密相同,密钥如果被拿到,但你不想让他在那个人手中,这是一个复杂的事情,别人可以解开你控制的东西。这时候可以将对称密钥和非对称密钥进行组合使用。注意里面方向是反方向,爱丽丝随机生成一个对称的密钥,要跟别人去通信,想把东西发给 Bob ,注意方向,爱丽丝不是自己的私钥对公钥进行加密,她手里只有 Bob 的公钥,他用 Bob 的公钥去加密私钥,这个密钥如果在网络上被人截获是没有办法被解开的,因为只有 Bob 的私钥才能解开, Bob 的私钥被 Bob 控制, 这个密钥在网络上分发没有安全问题,然后爱丽丝把加密后的对称密钥发给 Bob ,Bob 拿私钥去解密就得到了对称密钥,之后等于这一次对称密钥在网络上分发安全,只有爱丽丝和 Bob 有这个密钥,他俩就用这个密钥去进行通信,但这种密钥都有有效期,一段时间之后就无法使用。实际上与中国银行进行通信时就是使用对称密钥和非对称密钥组合进行通信,用非对称密钥效率低下,对称密钥分发安全问题,所以组合,用非对称的密钥去分发对称密钥的通信,而且对称密钥要有存活期,时间一长也会不安全,
五、single sign-on
刚才讲完这些全部是跟 Java 有关的。对称和非对称密钥和 Java 没什么关系 single sign-on 。实际上私钥公钥对 block change 是区块链的基础。哔哩哔哩有专门讲 blogchainblock chain 里面反复用的公钥私钥。所以区块链不特殊也不神秘。
公钥密钥对,这是公钥,这是私钥。
Cipher cipher = ...;
Cipher.init(Cipher.DECRYPT_MODE, key);
CipherInputStream in = new CipherInputStream(newFileInputStream(inputFileName), cipher);
byte[] bytes = new byte[BLOCKSIZE];
int inLength = in.read(bytes);
while (inLength != -1){
putData(bytes, inLength); / / put data to destination
in.read(bytes);
}
它的使用有两种方式,一种解密。因为公钥实际上人人都有,目的不是去加密内容,是要去验证身份,是告诉别人,这确实是你发出来。另外一个是用某一个人的公钥加密发东西给别人,别人用他自己的私钥去解密,才是真正的加密。因为用公钥加密,其他任何人在网络上拿到之后都解不开,只有能发送的人才能解开,这才是加密。所以公钥私钥对是公钥密私钥这一对的处理方式有两个用途,一个是在认证身份,一个是在加密。底下是指加密,上面是在认证,
它们的方向不同,即作用不同,到底谁加密谁解密不同。而这两种方式就是常见的就是所谓的认证和加密。认证和加密都属于安全领域的话话题,一个就是它属于要知道这是谁。另外一个是要把传输的东西要给加密。就是公钥私钥对的东西。
single sign-on 是什么意思
single sign-on 意思是有多个应用,就像较大的这 jaccount 一样,jaccount 是在单点认证的,即所有的应用无论是哪一个应用都需要 jaccount去认证,认证过之后就可以访问。那么这是怎么做到所谓 single sign-on 就单点去做认证,去做登录即可。
他要解决的问题即有大量的应用,每一个如果都有自己的一套登录认证的体系,首先这些系统开发起来非常复杂,其次对于用户来说也是一个很大的负担,即他会让每一次登录每一个系统中都要输入用户名密码。如果有些人他在不同系统里面密码还不一样,他容易记串。
所以希望到一个地方去认证,只要在这里认证成功之后,无论是研究生院还是财务处的网站,都是到 account 的认证就都可以访问。
single sign-on 如何做
single sign-on 他是怎么做到的?用单点认证,它的好处就是们不用去到处去做认证。
首先所有的系统可以把认证这件事情推到一个地方去执行。其次用户来说也比较简单,不用去记不同的用户名密码。
实现单点认证有什么方法?第一个是纯软件,叫 kerberos 协议。第二个是用硬件,智能卡、 U 盘还有其他的一些方法。
这种一次性的这种 token 带密码的 token 或者是其他东西,用其他的一些标记语言来定义的。
kerberos 是很多开源工具,哈佛大学有 CAS 统一认证的系统,它是基于 Kerberos 去实现的。协议是 MIT 提出来。那所谓 Kerberos 就是希腊神话里的三头狗。一个是做single sign-on ,一个是应用,一个,他在三方之间做安全控制,所以它起这么个名字。