Ji Xiang's blog

Walk step by step and learn everyday


  • Home

  • Archives

  • Tags
Ji Xiang's blog

数字证书基础知识

Posted on 2016-05-03

在为了更好地理解其中证书的特性,这里对数字证书以及相关的知识进行了整理和总结。

在讲数字证书之前必须要讲非对称加密算法和摘要算法,因为数字证书的基础就是各种加解密算法(非对称加密、
摘要算法),而其中的核心就是非对称加密算法了。目前而言加密方法可以分为两大类,一类是单钥加密
(private key cryptography)也可以称为对称加密,还有一类叫做双钥加密(public key cryptography)也可以称为非对称加密。
前者的加密和解密过程都用同一套密码,后者的加密和解密过程用的是不同的密码。

加密算法

1.对称加密

对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,
同时解密密钥也可以从加密密钥中推算出来。而在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为秘密
密钥算法或单密钥算法。

在应用该算法时,它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都
可以对他们发送或接收的消息解密,所以密钥的保密性对通信性至关重要。对称加密算法的特点是算法公开、计算量小、加密速度快、
加密效率高。对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中。不足之处是,交易双方都使用同
样钥匙,安全性得不到保证。

2.常见的对称加密算法

  • DES:数据加密标准(DES,Data Encryption Standard)是一种使用密钥加密的块密码,它基于使用56位密钥的对称算法,这个
    算法因为包含一些机密设计元素,相对短的密钥长度以及被怀疑内含美国国家安全局(NSA)的后门而在开始时是有争议的,DES现在
    已经不被视为一种安全的加密算法,主要因为它使用的56位密钥过短,导致容易被破解。为了提供实用所需的安全性,可以使用DES的
    派生算法3DES来进行加密,虽然3DES也存在理论上的攻击方法。

  • AES:高级加密标准(英语:Advanced Encryption Standard,缩写:AES),这个标准用来替代原先的DES,已经被多方分析
    且广为全世界所使用,2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。AES的区块长度固定为128比特,密钥
    长度则可以是128,192或256比特。

  • RC4:RC4加密算法是大名鼎鼎的RSA三人组中的头号人物Ronald Rivest在1987年设计的密钥长度可变的流加密算法簇。该算法
    的速度可以达到DES加密的10倍左右,且具有很高级别的非线性。RC4起初是用于保护商业机密的。但是在1994年9月,它的算法被
    发布在互联网上,也就不再有什么商业机密了。

  • 是旅居瑞士中国青年学者来学嘉和著名密码专家J.Massey于1990年提出的。它在1990年正式公布并在以后得到增强。这种算法是
    在DES算法的基础上发展出来的,类似于三重DES,和DES一样IDEA也是属于对称密钥算法。发展IDEA也是因为感到DES具有密钥太短
    等缺点,已经过时。IDEA的密钥为128位,这么长的密钥在今后若干年内应该是安全的。

3.非对称加密

与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey);并且加密密钥和解密密钥
是成对出现的。非对称加密算法在加密和解密过程使用了不同的密钥,非对称加密也称为公钥加密,在密钥对中,其中一个密钥是对外公开的,
所有人都可以获取到,称为公钥,其中一个密钥是不公开的称为私钥。

4.非对称加密的特性

  • 对于一个公钥,有且只有一个对应的私钥。

  • 公钥是公开的,并且不能通过公钥反推出私钥。

  • 通过私钥加密的密文只能通过公钥能解密,通过公钥加密的密文也只能通过私钥能解密。

通过公钥是极难推算出私钥的,只能通过穷举,所以只要密钥足够长,要想从公钥推算出私钥几乎不可能的。

5.非对称加密的主要用途

对信息保密,防止中间人攻击:将明文使用公钥加密,传输给接收者,这样确保信息只能被有私钥的拥有者解密,其他人无法获得明文信息,
因为没有私钥无法进行解密。该方法一般用于交换对称密钥。身份验证和防止信息篡改:私钥拥有者使用私钥加密一段授权明文,并将授权
明文和加密后的密文,以及公钥一并发送出来,接收方只需要通过公钥将密文解密后与授权明文对比是否一致,就可以判断明文在中途是否
被篡改过。此方法用于数字签名。

6.常见的非对称加密算法

  • RSA:1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。
    从那时直到现在,RSA算法一直是最广为使用的”非对称加密算法”。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。这种算法非常可靠,
    密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。
    因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。适用于数字签名和密钥交换。 该算法是目前应用最广泛的公钥加密算法,特别适用于通过 Internet 传送的数据。

  • DSA:数字签名算法 (Digital Signature Algorithm, DSA) 由美国国家安全署 (United States National Security Agency, NSA) 发明,
    已作为数字签名的标准。在DSA数字签名和认证中,发送者使用自己的私钥对文件或消息进行签名,接受者收到消息后使用发送者的公钥来验证签名的真实性。DSA只是一种算法,
    和RSA不同之处在于它不能用作加密和解密,也不能进行密钥交换,只用于签名,它比RSA要快很多。DSA 算法的安全性取决于自计算离散算法的困难。这种算法,不适用于数据加密,
    仅适用于数字签名。

  • Diffie-Hellman:一种确保共享KEY安全穿越不安全网络的方法。Whitefield与Martin Hellman在1976年提出了一个奇妙的密钥交换协议,
    称为Diffie-Hellman密钥交换协议/算法(Diffie-Hellman Key Exchange/Agreement Algorithm)。这个机制的巧妙在于需要安全通信的双方可以用这个方法确定对称密钥。
    然后可以用这个密钥进行加密和解密。但是注意,这个密钥交换协议/算法只能用于密钥的交换,而不能进行消息的加密和解密。双方确定要用的密钥后,要使用其他对称密钥操作
    加密算法实际加密和解密消息。该算法仅适用于密钥交换。

  • ECC:椭圆加密算法(ECC)是一种公钥加密体制,最初由Koblitz和Miller两人于1985年提出,与经典的RSA,DSA等公钥密码体制相比,
    椭圆密码体制有以下优点:160位的椭圆密钥与1024位的RSA密钥安全性相同;在私钥的加密解密速度上,ECC算法比RSA、DSA速度更快;存储空间占用小;带宽要求低;
    ECC算法的数学理论非常深奥和复杂,在工程应用中比较难于实现,但它的单位安全强度相对较高。

非对称加密算法可能是世界上最重要的算法,它是当今电子商务等领域的基石。非对称加密算法如此强大可靠,却有一个弊端,就是加解密比较耗时。
因此,在实际使用中,往往与对称加密和摘要算法结合使用。列如在实体之间交换对称密钥时,或者在签署一封邮件的散列时(数字签名)。

散列是通过应用一种单向数学函数获得的一个定长结果,对于数据而言,叫做散列算法。

7.摘要算法

摘要算法是一个神奇的算法,也称为散列或者散列值。是一种与基于密钥(对称密钥或公钥)的加密不同的数据转换类型。散列就是通过把一个叫做散列算法的单向数学函数应用于数据,将任意长度的一块数据转换为一个定长的、不可逆转的数字,其长度通常在128~256位之间。所产生的散列值的长度应足够长,因此使找到两块具有相同散列值的数据的机会很少。

8.摘要算法具有以下特性:

  • 只要源文本不同,计算得到的结果,必然不同(或者说机会很少)。

  • 无法从结果反推出源数据(那是当然的,不然就能量不守恒了)。

9.常见的摘要算法:

  • MD5:是RSA数据安全公司开发的一种单向散列算法,MD5被广泛使用,可以用来把不同长度的数据块进行暗码运算成一个固定位位的数值(通常是128位)。

  • SHA-1:与 DSA 公钥算法相似,安全散列算法1(SHA-1)也是由 NSA 设计的,并由 NIST 将其收录到 FIPS 中,作为散列数据的标准。它可产生一个 160 位的散列值。SHA-1 是流行的用于创建数字签名的单向散列算法。

  • MAC(Message Authentication Code):消息认证代码,是一种使用密钥的单向函数,可以用它们在系统上或用户之间认证文件或消息,常见的是HMAC(用于消息认证的密钥散列算法)。

  • CRC(Cyclic Redundancy Check):循环冗余校验码,CRC校验由于实现简单,检错能力强,被广泛使用在各种数据校验应用中。占用系统资源少,用软硬件均能实现,是进行数据传输差错检测地一种很好的手段(CRC 并不是严格意义上的散列算法,但它的作用与散列算法大致相同,所以归于此类)。

摘要算法用于对比信息源是否一致,因为只要源数据发生变化,得到的摘要必然不同。因为通常结果比源数据要短很多,所以称为“摘要”。

应用场景,如发件人生成邮件的散列值并加密它,然后将它与邮件本身一起发送。而收件人同时解密邮件和散列值,并由接收到的邮件产生另外一个散列值,然后将两个散列值进行比较。如果两者相同,邮件极有可能在传输期间没有发生任何改变。

10.数字签名

数字签名就是对非对称加密和摘要算法的一种应用,能够确保信息在发布后不会被篡改(摘要算法特性),保证数据的完整性和可信性;同时也可以防止数据被他人伪造(非对称加密算法特性);列如,我们有一段授权文本需要发布时,为了防止中途篡改发布的内容,保证发布文本的完整性,以及文本是由指定的发布者发布的。那么,可以通过摘要算法得到发布内容的摘要,得到摘要之后,发布者使用私钥加密得到密文(签名),这时候将源文本、密文(签名)以及公钥一起发布出去即可。

验证过程为:首先验证公钥是否是发布者的公钥,然后用公钥对密文进行解密,得到摘要,使用发布者对文本同样的摘要算法得到摘要文本,比对摘要是否一致即可确认信息是否被篡改或者是指定发布者发布的。

数字证书

1.现实生活中的证书

在现实生活中,证书顾名思义,就是权限机构颁发的证明。比如英语6级证书,就是教育部门颁发给通过了6级考核的个人的证明,证明这个人的英语能力。我们来看一下这个证书的组成:

  • 被证明人:老王

  • 内容:通过了英语六级

  • 盖章:教育部门的公章或钢印

当老王用这张证书找工作时,用人单位会通过查看证书的各项内容(尤其是公章),来验证证书的合法性和老王的能力。在现实生活中经常有假的6级证书,这些假证书最重要的就是有一个假公章。现实生活中使用法律法规来约束私刻假公章的行为,但是用人单位可能不能十分准确的判断公章是真是假。而数字签字可以来解决该类问题。

2.数字证书

数字证书就是通过数字签名实现的数字化的证书,在现实生活中公章可以被伪造,但是在计算数字世界中,数字签名是没办法被伪造的,比如上述证书中,在一个证书文件中写明了证书内容,颁发证书时,教育部门用他们的私钥对文件的摘要信息进行签名,将签名和证书文件一起发布,这样就能确保该证书无法被伪造。验证证书是否合法时,首先用教育部门的公钥(公钥是公开的谁都可以获取到)对签名进行解密得到一个摘要信息,使用教育部门同样的摘要算法得到证书的另一个摘要信息,对比两个摘要信息是否一致就能确定该证书是否合法。在一般的证书组成中部分中,还加入了一些其他信息,比如证书的有效期。

数字证书也有很多的签发机构,不同的签发机构签发的证书,用途也是不一样的,比如iOS开发中,使用到的ipa文件签名证书,需要到苹果申请。而在Web访问中为了防止Web内容在网络中安全传输,需要用到的SSL证书则需要向几家公认的机构签发。这些签发机构统称为CA(Certificate Authority)。

Web访问相关的证书可以向国际公认的几个机构:

  • WebTrust

  • GlobalSign

  • GTE

  • Nortel

  • Verisign

3.数字证书的验证

申请证书是为了验证,比如Web应用相关的SSL证书验证方是浏览器,iOS各种证书的验证方是iOS设备。因为数字证书是基于数字签名的,所有数字证书的合法性验证就是验证数字证书的签名是否正确,对于签名的验证在是需要签发机构的公钥才能验证;

对于iOS开发证书来说,申请完签名证书后,还需要安装苹果的公钥证书(XCode安装后会自动安装),这样才能确保我们申请的证书是可以被验证通过的(合法的),可用来进行ipa文件签名的。对于Web相关的证书签名的验证,则是由浏览器来验证,对于国际公认的几个证书签发机构浏览器会内置其公钥证书,用来验证数字证书的可信性。

当数字证书通过验证后,便可以用数字证书做对应的事情,iOS开发证书可以用来对APP进行签名,SSL证书可以用来做Web内容加密处理相关的事情。所以有了这些证书之后,能保证在数据的传输过程中,数据是不会被篡改的,并且信息来源也是不能不修改的,从而确保信息安全。

对于iOS,iOS系统已经将这个验证过程固化在系统中了,除非越狱,否则无法绕过

4.数字证书的授权链

数字证书还包含一个授权链信息,举个例子:如果你要申请休假1周,需要你的上司审批,你的上司需要他的上司同意,最终需要大老板同意,那么这一层层的授权,形成了一个授权链,大老板是授权链的根(root),中间这些环节分别是被更接近root的人授权的。

比如苹果开发者的APP签名证书,该证书可以用来对APP进行签名,该证书实际上是由苹果的Worldwide Developer Relations Certificate Authority(WDRCA)授权签名的,而它是由Apple Certificate Authority授权签名的。在这个关系链中苹果的CA是根。 苹果CA根证书默认是内置在苹果系统中的,所以WDRCA的可信性可以由苹果内置的CA根证书来验证其可信性。

Web相关的SSL证书顶部CA根,则就是上述提到的几家公认的签发机构,当我们需要Web做SSL的证书时,便可以向上述机构申请,通常向根机构申请费用都会比较高,也可以向一些二级授权机构进行申请,选择根机构证书签发的好处就是目前大多数的浏览器都会预装内置了这些权威CA的公钥证书,这样,在使用这些权威CA签发过的证书的时候,浏览器一般不会报风险提示。

总结

数字证书签名的基础是非对称加密算法,利用了非对称加密的身份验证和防止信息篡改的特性来实现的,在一些其他方面比如HTTPS中密钥交换用的就是非对称加密的保密特性来实现的,在非对称加密算法中RSA应用最广。非对称加密虽好,但却有一个弊端,就是加解密比较耗时,所以一般都是配合对称加密一起使用。

Ji Xiang's blog

信息系统管理与安全(3)

Posted on 2016-03-31

信息安全

资产管理:责任划分

编制资产清单:

  • 识别所有资产
  • 对资产的所有权、信息进行分类,并形成文件
  • 资产清单内容:资产类型、格式、位置、备份信息、许可信息、业务价值

明确资产所有权:

  • 与信息处理有关的所有信息资产都应当由指定的部门

资产的使用

  • 应当明确信息资产的使用规划,并形成文件,加以实施

风险因素评估:信息资产评估

根据客户的行业特点、应用特性的安全目标,信息资产的赋值形式:

  • 形式一:为机密性、完整性、可用性分别赋予不同的价值等级
  • 形式二:依据机密性、完整性、可用性赋予等级,经过综合评定得出资产价值
  • 形式三:用相对信息价值的货币来衡量

资产的机密性赋值参考

  • 3 高
  • 2 中等
  • 1 低
  • 0 可忽略

资产的重要性等级划分参考

  • 4 高 严重损失
  • 3 中 中等程度损失
  • 2 低
  • 1 很低

信息资产价值的货币化表示

威胁分析

  • 潜在威胁分析
  • 威胁审计和入侵检测
  • 安全威胁综合分析

威胁来源于识别

外在
环境因素

  • 自然环境
  • 物流环境
  • 人文环境
    人为因素
  • 无恶意内部人员
  • 有恶意内部人员
  • 第三方
  • 外部人员
    内在
    • 任务确定
    • 系统设计

威胁发生的可能性

  • 应根据经验和有关统计数据判断威胁发生的频率或概率
  • 影响威胁发生可能性的因素:
    • 资产的吸引力
    • 组织的知名度
    • 资产转换成利益的容易程度
    • 威胁的技术力量
    • 脆弱性被利用的难易程度
  • 有关统计信息获取的取到包括
    • 依赖历史纪录或安全事件报告
    • 通过各种设备,获取威胁发生的数据统计和分析结果
    • 各种日志中威胁发生的数据统计和分析结果
    • 近年来权威机构发布的报告

威胁产生的影响

  • 对威胁发生概率和产生影响的评估结论是识别和确定每种威胁发生风险的等级
    • 先确定没有控制措施条件下威胁所产生的影响,建立基本风险基线
    • 考虑已有控制措施对威胁可能产生的阻碍作用,确定风险级别

脆弱性分类

技术脆弱性:物理安全、网络安全、系统安全、应用安全
管理脆弱性:安全管理

Ji Xiang's blog

信息系统管理与安全(2)

Posted on 2016-03-28

信息安全风险基本要素

  • 信息资产 增加风险
  • 信息资产环境或其自身存在的脆弱性/漏洞 增加风险
  • 威胁 增加风险
  • 安全控制措施 降低风险
  • 影响 增加风险

信息安全风险模型

信息安全风险评估模型的作用

可以建立信息安全风险各个要素之间的相互关系,据此可以分析系统内部机制中所存在的危险性因素,可以发现系统与外界环境交互过程中存在的不正常和有害行为,从而完成对系统脆弱点和安全威胁的定性分析。
可以进一步采用其他方法来进行风险建模。

风险评估准备

  • 确定风险评估的目标
  • 确定风险评估的范围
  • 选择与组织相适应的风险判断方法
  • 建立风险…

资产及其价值

资产是组织赋予了价值,且需要保护的东西

  • 能以多种形式存在
  • 价值和安全属性具有很强的时间特性

    资产赋值是对资产安全价值的估价

    资产的价值与如下因素有关:

  • 自身的价值
  • 对业务的安全重要性
  • 在一定条件下的潜在价值
  • 与之相关的安全保护措施

资产管理

  • 根据不同的项目目标和特点,确定重要识别的资产类别
  • 明确所拥有和需要保护的信息资产,确定关键资产
  • 资产管理的目标是实现并保持组织资产的适当保护

    资产管理分类

    指导原则:
  • 组织价值、法律要求、敏感性、关键性
  • 权衡分类数量
  • 按保护级别进行
Ji Xiang's blog

JavaScript学习笔记(3)

Posted on 2016-03-27

JavaScript Closure

学习JavaScript,不能不知道闭包(closure)的概念和作用。闭包是JavaScript中重要的一个概念,对于初学者来讲,闭包很难理解和运用。但只有理解了闭包的基本概念,才能正确的使用它;同样的,只有配合正确的实践,我们才有更加深刻的理解。因此,这片文章借鉴了很多前人的总结和经验,只为更好的理解闭包。

闭包的概念

对于码农来说,学习一门新技术,除了看官方API和相关文档,示例代码的对我们的帮助可能更大,因为代码的运行结果更加直观,能加深我们的理解。下面贴出大牛的代码,号称世上最简单的闭包:

1
2
3
4
5
6
7
8
function A(){
function B() {
console.log('Hello closure!');
}
return B;
}
var c = A();
// c(); Hello closure!

确实,这个示例代码真的不能再简单了。这段代码“翻译”后可以表示为:

  1. 定义了一个函数A
  2. 在A中定义了内部函数B
  3. 在A中返回B(确切的讲,在A中返回B的引用)
  4. 执行A(),把A的返回值-函数B()的引用复制给变量c
  5. 执行 函数B(),输出结果

根据上述例子,闭包可定义为:
当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。

闭包的作用

在了解闭包的作用之前,我们先了解一下JavaScript中的垃圾回收(GC)机制:在JavaScript中,如果一个对象不再被引用,那么这个对象就会被GC回收,否则这个对象会一直保存在内存中。
在上述例子中,B定义在A中,因此B依赖于A,而外部变量c获得了内部函数B的引用,也就是说,A被间接引用了,所以A不会被GC回收,而是一直保持上下文,在同一个引用调用结束前,会一直保存在内存中,直到调用结束。
示例2:

1
2
3
4
5
6
7
8
9
10
11
12
function A() {
var count = 0;
function B() {
count++;
console.log(count);
}
return B;
}
var c = A();
c();//1
c();//2
c();//3

count是A中的一个变量,它的值在B中被改变,函数B每执行一次,count的值在原来的基础上累加1,A被变量c引用,不会被GC,因此,A中的count一直保存在内存中,c每执行一次,由于保留了上下文,count的值会在原来的基础上增加1。
这就是闭包的作用,有时候我们需要一个模块中定义这样一个变量:希望这个变量一直保存在内存中,但又不会“污染”全局的变量,这个时候,我们就可以用闭包来定义这个模块。

结语

上面的例子只是最简陋的写法,实际中不会这么写。这里只是为了加深理解。当然,如果要全面理解闭包,仅凭上面的文字和代码是远远不够的。在项目中不妨试着使用闭包,用的多了自然会有独到的理解。

Ji Xiang's blog

JavaScript学习笔记(2)

Posted on 2016-03-23

JavaScript内存管理

1.简介

低级语言,比如C,有低级的内存管理基元,像malloc(),free()。另一方面,JavaScript的内存基元在变量(对象,字符串等等)创建时分配,然后在他们不再被使用时“自动”释放。后者被称为垃圾回收。这个“自动”是产生混淆的源头,并给JavaScript(和其他高级语言)开发者一个印象:他们可以不用考虑内存管理。这是错误的。

2.内存生命周期

不管什么程序语言,内存生命周期基本一致:
分配你所需要的内存

  1. 使用它(读、写)
  2. 当它不被使用时释放
  3. 当它不被使用时释放
    第一二部分过程在所有语言中都很清晰。最后一步在低级语言中很清晰,但是在像JavaScript等高级语言中,最后一步不清晰。

3.JavaScript的内存分配

3.1 值的初始化

为了不让程序员费心分配内存,JavaScript在定义变量时完成内存分配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var n = 123; // 给数值变量分配内存
var s = "azerty"; // 给字符型
var o = {
a: 1,
b: null
}; // 为对象及其包含变量分配内存
var a = [1, null, "abra"]; // 为数组及其包含变量分配内存(就像对象一样)
function f(a){
return a + 2;
} // 为函数(可调用的对象)分配内存
// 函数表达式也能分配一个对象
someElement.addEventListener('click', function(){
someElement.style.backgroundColor = 'blue';
}, false);

3.2 通过函数调用的内存分配

有些函数调用结果是分配对象内存:

1
2
var d = new Date(); //分配一个Date对象
var e = document.createElement('div'); //分配一个DOM元素

有些方法分配新变量或者新对象:

1
2
3
4
5
6
var s = "azerty";
var s2 = s.substr(0, 3); // s2是一个新字符串
//因为字符串是不变量,JavaScript可能没有分配内存,但只是存储了0-3的范围。
var a = ["ouais ouais", "nan nan"];
var a2 = ["generation", "nan nan"];
var a3 = a.concat(a2); // 新数组中有连接数组a和数组a2中的四个元素。

3.3 值的使用

使用值的过程实际上是对分配内存进行读取与写入的操作。读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。

3.4 当内存不再需要使用时释放

大多数内存管理的问题都在这个阶段。在这里最艰难的任务是找到“所分配的内存确实已经不再需要了”。它往往要求开发人员来确定在程序中哪一块内存不再需要并且释放它。
高级语言解释器嵌入了“垃圾回收器”,它的主要工作是跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它。这只能是一个近似的过程,因为要知道是否仍然需要某块内存是无法判定的(无法通过某种算法解决).

4. 垃圾回收

如上文所述自动寻找是否一些内存“不再需要”的问题是无法判定的。因此,垃圾回收实现只能有限制的解决一般问题。本节将解释必要的概念,了解主要的垃圾回收算法和它们的局限性。

4.1 引用

垃圾回收算法主要依赖于引用的概念。在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。例如,一个Javascript对象具有对它 原型 的引用(隐式引用)和对它属性的引用(显式引用)。
在这里,“对象”的概念不仅特指Javascript对象,还包括函数作用域(或者全局词法作用域)。

4.2 引用计数垃圾收集

这是最简单的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。
例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var o = {
a: {
b:2
}
};
// 两个对象被创建,一个作为另一个的属性被引用,另一个被分配给变量o
// 很显然,没有一个可以被垃圾收集
var o2 = o; // o2变量是第二个对“这个对象”的引用
o = 1; // 现在,“这个对象”的原始引用o被o2替换了
var oa = o2.a; // 引用“这个对象”的a属性
// 现在,“这个对象”有两个引用了,一个是o2,一个是oa
o2 = "yo"; // 最初的对象现在已经是零引用了
// 他可以被垃圾回收了
// 然而它的属性a的对象还在被oa引用,所以还不能回收
oa = null; // a属性的那个对象现在也是零引用了
// 它可以被垃圾回收了

限制:循环引用

这个简单的算法有一个限制,就是如果一个对象引用另一个(形成了循环引用),他们可能“不再需要”了,但是他们不会被回收。

1
2
3
4
5
6
7
8
9
10
11
12
function f(){
var o = {};
var o2 = {};
o.a = o2; // o 引用 o2
o2.a = o; // o2 引用 o
return "azerty";
}
f();
// 两个对象被创建,并互相引用,形成了一个循环
// 他们被调用之后不会离开函数作用域
// 所以他们已经没有用了,可以被回收了
// 然而,引用计数算法考虑到他们互相都有至少一次引用,所以他们不会被回收

实际当中的例子
IE 6, 7 对DOM对象进行引用计数回收。对他们来说,一个常见问题就是内存泄露:

1
2
3
4
5
6
7
var div = document.createElement("div");
div.onclick = function(){
doSomething();
};
// div有了一个引用指向事件处理属性onclick
// 事件处理也有一个对div的引用可以在函数作用域中被访问到
// 这个循环引用会导致两个对象都不会被垃圾回收

4.3 标记-清除算法

这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。

这个算法假定设置一个叫做根的对象(在Javascript里,根是全局对象)。定期的,垃圾回收器将从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和所有不能获得的对象。

这个算法比前一个要好,因为“有零引用的对象”总是不可获得的,但是相反却不一定,参考“循环引用”。

从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。所有对JavaScript垃圾回收算法的改进都是基于标记-清除算法的改进,并没有改进标记-清除算法本身和它对“对象是否不再需要”的简化定义。

循环引用不再是问题了

在上面的示例中,函数调用返回之后,两个对象从全局对象出发无法获取。因此,他们将会被垃圾回收器回收。
第二个示例同样,一旦 div 和其事件处理无法从根获取到,他们将会被垃圾回收器回收
。

限制: 那些无法从根对象查询到的对象都将被清除

尽管这是一个限制,但实践中我们很少会碰到类似的情况,所以开发者不太会去关心垃圾回收机制。

Ji Xiang's blog

JavaScript学习笔记(1)

Posted on 2016-03-19

JavaScript中的apply(), call()和arguments对象

学习JavaScript,应该掌握函数式编程的特点和方法,为了做到这一点,详细理解函数调用和函数原型是非常有必要的。
打开浏览器,按F12打开浏览器控制台,选择console,让我们在console控制台里编写一些javascript代码来深入了解关于函数的一些知识。

函数原型

输入:

1
Object.getOwnPropertyNames(Function.prototype);

得到:

1
["length", "name", "arguments", "caller", "apply", "bind", "call", "toString", "constructor"]

这里的输出依赖于你使用的浏览器和JavaScript版本。以上属性里,我们将讨论以下这几个:

1
2
3
Function.prototype.length
Function.prototype.call
Function.prototype.apply

首先,我们定义一个 “test” 函数:

1
2
3
var test = function (a, b, c) {
console.log({this: this, a: a, b: b, c: c});
}

这个函数简单记录了上下文变量(context),即this的值,和输入参数的值。然后,我们输入不同的参数来调用这个函数:

test(‘a’);
得到:

1
Object { this: Window, a: "a", b: undefined, c: undefined }

test(‘this’, ‘is’, ‘cool’);
得到:

1
Object { this: Window, a: "this", b: "is", c: "cool" }

我们注意到,如果我们不输入第2、3个参数,浏览器将显示undefined。此外,我们注意到这个函数默认的上下文是全局对象Window。

使用Function.prototype.call

调用call函数时,需要把上下文变量this作为第一个输入的参数,然后传进其他参数。
syntax:

1
function.call(this, arg1, arg2, ..., argn);

因此,下面这两行是等效的:

1
2
test('this', 'is', 'cool');   
test.call(Window, 'this', 'is', 'cool');

使用Function.prototype.apply

函数apply比call更实用一些,和call类似,apply的调用方式也是把变量this设置为输入参数序列中的第一个参数的值,但输入参数序列的第二个参数也是最后一个,以数组(或者数组对象)的方式传入。
Syntax:

1
function.apply(this, [arg1, arg2, ..., argn]);

因此,下面三行全部等效:

1
2
3
tester("this", "is", "cool");   
tester.call(window, "this", "is", "cool");
tester.apply(window, ["this", "is", "cool"]);

能够以数组的方式指定一个参数列表在多数时候非常有用(我们会发现这样做的好处的)。例如,Math.max是一个可变参数函数(一个函数可以接受任意数目的参数)。

1
2
Math.max(1,3,2); //=> 3   
Math.max(2,1); //=> 2

这样,如果我有一个数值数组,并且我需要利用Math.max函数找出其中最大的那个,我怎么用一行代码来做这个事儿呢?

1
2
3
var numbers = [3, 8, 7, 3, 1];   
Math.max.apply(null, numbers);
//=> 8

apply方法真正开始显示出它的重要是当配上特殊参数:Arguments对象。

每个函数表达式在它的作用域中都有一个特殊的、可使用的局部变量:arguments。为了研究它的属性,让我们创建另一个test函数:

1
2
3
var tester = function(a, b, c) {   
console.log(Object.getOwnPropertyNames(arguments));
};

注:在这种情况下我们必须像上面这样使用Object.getOwnPropertyNames,因为arguments有一些属性没有标记为可以被枚举的,于是如果仅仅使用console.log(arguments)这种方式它们将不会被显示出来。

现在我们按照老办法,通过调用test函数来测试下:

1
2
3
4
5
test("a", "b", "c");
//=> ["0", "1", "2", "length", "callee"]

test.apply(null, ["a"]);
//=> ["0", "length", "callee"]

arguments变量的属性中包括了对应于传入函数的每个参数的属性,这些和.length属性、.callee属性没什么不同。
.callee属性提供了调用当前函数的函数的引用,但是这并不被所有的浏览器支持。就目前而言,我们忽略这个属性。
让我们重新定义一下我们的test函数,让它丰富一点:

1
2
3
4
5
6
7
8
9
var tester = function() {
console.log({
'this': this,
'arguments': arguments,
'length': arguments.length
});
};
tester.apply(null, ["a", "b", "c"]);
//=> { this: null, arguments: { 0: "a", 1: "b", 2: "c" }, length: 3 }

Arguments:是对象还是数组?
我们看得出,arguments完全不是一个数组,虽然多多少少有点像。在很多情况下,尽管不是,我们还是希望把它当作数组来处理。把arguments转换成一个数组,这有个非常不错的快捷小函数:

1
2
3
4
5
6
7
8
9
10
11
12
function toArray(args) {
return Array.prototype.slice.call(args);
}

var example = function(){
console.log(arguments);
console.log(toArray(arguments));
};

example("a", "b", "c");
//=> { 0: "a", 1: "b", 2: "c" }
//=> ["a", "b", "c"]

这里我们利用Array.prototype.slice方法把类数组对象转换成数组。因为这个,在与.apply同时使用的时候arguments对象最终会极其有用。

Ji Xiang's blog

信息系统管理与安全(1)

Posted on 2016-03-14

软件可信性问题:

  1. 空间技术
  2. 医疗系统
    原因:总体安全设计有缺陷
    软件编码错误
    
    取消了硬件安全联锁
    安全分析只考虑了硬件
    操作人员的差错
    对仪器的安全校验粗心大意

传统的定义:失效、故障

  1. 失效:电路(或系统)发生了违背设计规定功能的情况,便认为该电路(或系统)失效。
  2. 故障:有可能引起失效的一种物理缺陷(软件的缺陷也成为bug)

失效分析、失效模式和实效机理

  1. 失效分析:分析失效的发生和影响,确定失效模式,研究失效机理,尽可能提供改进的措施。
  2. 失效模式:系统失效的表现形式
  3. 失效机理:导致系统失效的内在原因

系统级软件异常(失效)的分类

  1. 操作系统挂起
  2. 程序挂起
  3. 程序失败
  4. 输入问题
  5. 未达到要求的性能
  6. 发现的整个产品失败
  7. 系统错误信息
  8. 输出问题
  9. 其他

差错/错误

. 系统处在如下情况下时会发生失效

  • 系统处于错误状态
  • 错误状态的一部分包含在系统的外部状态中
    . 错误状态: 它是一种可以导致服务失效的状态
    . 故障是产生差错的原因,但故障不一定总是立即会产生差错
    . 从故障发生到由于该故障而发生差错的时间间隔称为故障潜伏期
    . 故障潜伏(没有发生失效),差错潜伏,发生差错/故障

故障模型

指的是在系统的较高级别上(逻辑/门级、RTL、行为)描述物理故障的影响的模型

建模要求:准确性,可处理性

Ji Xiang's blog

Design Patterns

Posted on 2015-04-25

23 Design Patterns

Creational Patterns

1.Abstract Factory:

Creates an instance of several families of classes. Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定它们具体的类。

2.Builder:

Separates object construction from its representation. Separate the construction of a complex object from its representation so that the same construction processes can create different representations.
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

3.Factory Method:

Creates an instance of several derived classes. Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

4.Prototype:

A fully initialized instance to be copied or cloned. Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
通过复制(克隆、拷贝)一个指定类型的对象来创建更多同类型的对象。这个指定的对象可被称为“原型”对象,也就是通过复制原型对象来得到更多同类型的对象。

5.Singleton:

A class of which only a single instance can exist. Ensure a class only has one instance, and provide a global point of access to it.

Structural Patterns

6.Adapter:

Match interfaces of different classes.Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
适配器模式(Adapter Pattern),把一个类的接口变换成客户端所期待的另一种接口,Adapter模式使原本因接口不匹配(或者不兼容)而无法在一起工作的两个类能够在一起工作。

7.Bridge:

Separates an object’s interface from its implementation. Decouple an abstraction from its implementation so that the two can vary independently.
桥连模式:将抽象部分与实现部分分离,使它们都可以独立的变化。它是一种结构性模式,又称柄体(Handle and body)模式或者接口(Interface)模式。

8.Composite:

A tree structure of simple and composite objects. Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

9.Decorator:

Add responsibilities to objects dynamically. Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

10.Facade:

A single class that represents an entire subsystem. Provide a unified interface to a set of interfaces in a system. Facade defines a higher-level interface that makes the subsystem easier to use.
外观模式:为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。引入外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度。

11.Flyweight:

A fine-grained instance used for efficient sharing. Use sharing to support large numbers of fine-grained objects efficiently. A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an independent object in each context — it’s indistinguishable from an instance of the object that’s not shared.
享元模式(Flyweight):对象结构型模式运用共享技术有效地支持大量细粒度的对象。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。

12.Proxy:

An object representing another object. Provide a surrogate or placeholder for another object to control access to it.
代理模式: 为其他对象提供一种代理,并以控制对这个对象的访问。

Behavioral Patterns

13.Chain of Resp:

A way of passing a request between a chain of objects. Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。

14.Command:

Encapsulate a command request as an object. Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式又称为动作(Action)模式或事务(Transaction)模式。

15.Interpreter:

A way to include language elements in a program. Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
Interpreter是一种特殊的设计模式,它建立一个解释器,对于特定的计算机程序设计语言,用来解释预先定义的文法。简单地说,Interpreter模式是一种简单的语法解释器构架。

16.Iterator:

Sequentially access the elements of a collection. Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Iterator模式指对容器中包含的内部对象的访问委让给外部类,使用Iterator(遍历)按顺序进行遍历访问的设计模式。

17.Mediator:

Defines simplified communication between classes. Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
Mediator模式也叫中介者模式,是由GoF提出的23种软件设计模式的一种。Mediator模式是行为模式之一,在Mediator模式中,类之间的交互行为被统一放在Mediator的对象中,对象通过Mediator对象同其他对象交互,Mediator对象起着控制器的作用。

18.Memento:

Capture and restore an object’s internal state. Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.
memento是一个保存另外一个对象内部状态拷贝的对象.这样以后就可以将该对象恢复到原先保存的状态。

19.Observer:

A way of notifying change to a number of classes. Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

20.State:

Alter an object’s behavior when its state changes. Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
状态模式:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。

21.Strategy:

Encapsulates an algorithm inside a class. Define a family of algorithms, encapsulate each one, and make them interchangeable.Strategy lets the algorithm vary independently from clients that use it.
策略模式:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

22.Template:

Defer the exact steps of an algorithm to a subclass. Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

23.Visitor:

Defines a new operation to a class without change. Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。

Ji Xiang's blog

How to build your owner blog with HEXO

Posted on 2015-04-18

今天真高兴,涨了不少姿势。

1.学会了使用Hexo搭建一个静态博客
2.学会了使用MarkDown这种简单的标记语言编写文章

前几天看到学长在用MarkDown写博客,感觉逼格很高,程序员风格十足。今天终于入门了,现把一些主要步骤记录一下

1.首先要有一个github账号,然后建立一个repository(仓库),关键点在于 仓库名称要与你的账号名称相同,并在后面加上github.io
例如: 我的github叫做 jimxiang,那么就建一个名为 jimxiang.github.io的仓库。接下来要配置SSH,网上教程很多,这里不再赘述。**

2.使用node.js里的npm在命令行里进行接下来的操作

安装Hexo

 $ npm install -g hexo // -g  表示把hexo安装到全局,不限于当前文件夹,以后重建项目时不必再次安装

部署Hexo

 $ hexo init 
现在已经搭建好本地的hexo博客了,执行以下命令
 $ hexo g   // 生成静态页面至public目录
 $ hexo s   // 开启预览访问端口(默认端口4000,'ctrl + c'关闭server)

到浏览器输入 localhost:4000 看看

更换博客主题

github上有许多博客主题。现在clone一个你最喜欢的主题

 $ git clone https://github.com/...(主题地址)

例如

 $ git clone https://github.com/wuchong/jacman.git themes/jacman

启用主题

修改Hexo目录下的config.yml配置文件中的theme属性,将其设置为jacman。

 theme: jacman

注意:Hexo有两个config.yml文件,一个在根目录,一个在theme下,此时修改的是在根目录下的。

更新主题

 $ cd themes/jacman
 $ git pull

使用与调试

启动本地服务,实时查看你的blog

 $ hexo serve

到了重要的一步:把本地的博客部署到github上(有木有很激动)

配置 根目录下的config.yml 文件

 deploy:
 type: git
 repository: git@github.com/...(你自己的github地址)
 branch: master

npm命令

 $ hexo clean
 $ hexo generate
 $ hexo deploy  //这一步会让你输入你的github用户名和密码

到此为止,你可以登陆 xxx.github.io 查看你的博客啦!

Hexo修改blog主页内容:

修改根目录下的 config.yml 文件

新建文章

$ hexo new "(文章名)" //新建一个xxx.md的文件
使用 **记事本、sublime text、chrome插件** 等编辑 *source/_posts文件下的.md* 文件,借助[MakeDown](http://www.markdown.cn/)语言写入你的文章 ### 写完后,推送到服务器上
 $ hexo g
 $ hexo d

现在我们完成了用Hexo和github建立静态博客,是不是很有趣呢?赶紧动手吧!

Ji Xiang's blog

Quick Strat

Posted on 2015-04-18

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

12
Ji Xiang

Ji Xiang

20 posts
14 tags
© 2018 Ji Xiang
Powered by Hexo
Theme - NexT.Mist