选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……
很多争论其实是源于沟通和理解。人们的理解能力往往是有限的,这些限制很可能来自于不同的教育背景、知识面等等,因此,为了更好地理解对方,人们往往习惯于使用 自己熟悉的 知识去设法理解对方所说的。
这带来的一个现象,在技术人员之间的讨论中,就会是这样:例如,讨论应该怎么造一枚火箭,往往不会有人去随便做评论,因为他们很清楚自己并不是这个专业的人,而这件事明显需要许多非常专业的知识;而如果讨论火箭发射基地的车棚应该漆成什么颜色,则几乎每一个人都会去发表自己的意见,因为车棚的颜色是什么样子,在多数人看来往往没有造火箭那么重要,并且,似乎每个人都能够胜任这样的决策。
将讨论如何造火箭的话题,阴差阳错地变成一群人争论火箭发射场外面的车棚应该漆成什么颜色,就是我们所说的 Bikeshed 现象。
我在这一天时间里遇到了两次这种问题。第一次是我自己把冯牛说的税的算法问题想错了,第二次是我的关于什么时候该用线程的问题被另一个人活活 扯成了 线程 vs 进程的开销问题。
解决 bikeshed 是需要时间的。不过,每一个参与讨论的人,其实都可以尝试使用一些方法来减少这种情况的发生。例如:
头脑空白原则:如果对方讨论的是一个你认为自己很熟悉的话题,不要首先根据自己的理解去下结论,而要先看清楚对方到底在说什么。许多时候,我们自己的知识背景会限制我们能够看到的问题的范围,很可能对方想要讨论的并不是这些东西。
在发现争论持续了很长时间,双方各执己见时,暂时停止讨论,而不是继续论证自己的观点。一个观点的对错取决于观点本身,而不是争论双方所说的话。
避免情绪化的语言—-那不会增加你的说法的说服力。
Read more...很多事情都有Do’s and Don’ts,这里试着整理一下与安全有关的。
本文版权所有 © 2010 Xin LI delphij@FreeBSD.org 保留所有权利;非商业转载请注明出处 http://blog.delphij.net/, 谢绝商业转载。
安全不能建立在"别人不知道"的基础上
“别人不知道"是一种非常常见的安全 假象,举例来说,一种自己设计的山寨加密算法、一个系统中一般人不知道的位置等等,都属于这一类。
将安全建立在"别人不知道"的基础上是非常危险的。首先它会给设计者和用户带来"安全"的幻像,这会直接导致与系统交互的人放松警惕;其次,这样的设计往往留有"后门”,甚至是设计者不知道的后门(因为往往他们并不对这类设计进行充分的、专业的审计),容易被攻击者利用;最后,这种做法存在第三方泄密问题,即,使用这种系统的人,需要提防设计系统的人被其他人买通并泄漏一些秘密的情况。
延缓攻击的手段不能用来阻挡攻击
有许多延缓攻击的手段,例如改变服务的端口(比较常见的如将 ssh 改为 tcp/22 以外的端口),或禁止服务程序显示自己的版本等等,或仅仅简单地启用防火墙,这些手段起到的作用只是延缓攻击,而不应作为一种安全屏障。对于多层次式的安全设计来说,采取这些措施有助于提高检测到入侵的机会,但是它们本身并不会提高安全性。
与前一种情况类似,这种做法也只是让管理员放松警惕。例如以 ssh 为例,有人认为将端口改为一个非知名端口可以避免相关的攻击,但事实是,攻击者依然可以利用 ssh 实现或协议设计中存在的一些漏洞来攻破系统。拥有特定资源的攻击者甚至不需要直接对目标系统实施攻击。在较复杂的攻击手段中,包括简单的 port knocking 一类的保护手法,都可以使用类似分组重放这样的方法来逐步攻破。
采用层次式的安全设计
所谓层次式的安全设计,说的是在一套安全系统中包含不同层次的、存在层次式监控关系的安全结构。例如,将本地包含执行文件的那些文件系统通过一定的方式导出给监控网段的机器,就可以让那些机器在攻击者不知情,或至少不太容易注意到的情况下对入侵进行检测;通过将一些重要日志发到以不同的访问控制机制,甚至不同网络协议的记录设备上,则可以有效地检测入侵者的入侵行为,并为日后的分析留下更多的有用信息。
层次式安全在现实中也有应用。例如产品的质检,除了制造商自己进行的质量控制之外,有时分销商或政府也会进行一些抽样的检查。我们注意到,这些设计中的一个重要的特点是在不同的系统中使用不同的访问控制逻辑。例如,日志服务器必须从特定的客户端,甚至只能从某些隔离的内网登录。此时,延缓攻击的手段可以作为它的一项辅助设施,即其目的并不是阻止攻击,而是吸引攻击者在攻击目标上花费更多的时间,从而帮助入侵检测机制更容易地检测这些攻击。
不要轻信任何东西,包括X.509证书
安全系统的设计者必须对安全有全面的理解和认知。有一句很著名的话叫做 In God we trust, all others must submit an X.509 Certificate,需要注意的是,这里说的是 must submit,并没有说 submit 了就可以 trust 了。
和前面所说的层次式安全设计类似,我们的一个基本假定应该是,一个安全系统中的任何参与者,无论是用户还是计算机或程序,都是可能存在弱点的。安全系统,或用户,都不应轻信任何东西,例如,在特权隔离 (Privilege Separation) 这样一种设计中,特权进程除了完成那个非特权的子进程的请求之外,还有一个任务是维护一个"理性状态机"(Sanity DFA),这个状态机的作用是检测非特权进程的异常状况,如果发生这样的情况,则特权进程有拒绝提供服务,并杀掉非特权进程的责任。作为用户,对于系统给出的响应,除了验证对方的证书之外,也应有常识性的了解和适当的判断。
Read more...法师推荐的一个 短片,有关好爱情和不朽,我们还有很多不知道的。
Read more...欧盟日前正式无条件批准了Oracle收购Sun的交易,至此,有着28年历史(1982 - 2010)的Sun公司作为独立公司的历史正式宣告终结,今天,Sun的网站已经变成了301 http://www.oracle.com/。
“For 28 years, Sun has stood for courage, innovation, a willingness to blaze trails, to envision and engineer the future.”
Read more...口令是许多系统中用于判断用户身份的重要手段。当然,使用口令作为身份验证方法是很不靠谱的(例如,许多用户会使用弱口令,或者在多个系统中使用同样的口令,以及它存在对称失密问题,等等),不过因为口令便于携带(相对于私钥)和实现,因此仍然被广泛使用。
验证用户口令有很多种不同的方法。最原始的方法,就是将用户输入的口令与我们保存的口令相比较,如果相同,就认为是验证通过。但是这样一来,我们就必须保存用户的口令,而保存用户的口令会导致很多问题,例如,假如系统用于保存口令的数据库被攻陷,直接泄露用户的明文口令肯定不是一件好事。
于是,我们可以对前面的方法进行改进,即,只保存用户口令的散列(hash)字符串,而不是口令的明文。散列算法是一种单向的计算,即散列函数 H 对明文信息 p 计算出的结果 h:
H(p) = h
Read more...说明:这篇文章希望能够以比较通俗的方式介绍一下相关的概念。
端到端加密,通常是指两个通信实体之间在会话通道基础上进行的、由两个实体之间协商的密文会话。端到端加密的好处是能够减少会话通道本身的泄密或其他问题导致两个通信实体之间的通讯遭到第三方破译,并避免通讯的对方对通讯内容抵赖(即,不承认通讯内容来自自己)。相对而言,端到端加密的实施成本要比单独架设一条物理的通讯线路要便宜许多,因此有时它也用于架设这类通讯线路。端到端加密本身不能阻止由于使用的会话通道本身的丢包导致的干扰。然而,由于端到端加密可以工作在较高的抽象层次上,它可以使用多个实际的会话通道而提高抗干扰能力。
通常我们会希望在一个安全系统中设置多个层次的安全设施,或者说类似"洋葱"的模型,例如,在系统中,将所有与安全有关的信息记录日志并放到不可擦除的介质上、对连接进行加密,和对发送的消息进行加密,这几种方法分别考虑的是不同级别的信息安全,而这些方法可以在同一个安全系统中作为其不同的保护层次来使用。在这一类模型中,我们不仅视阻止入侵为目标,同时也将检测入侵做为目标,或者换言之,每攻破系统中的一个层次,入侵者都需要付出额外的努力,并冒更大的被发现的风险才能达到这样的目标。
以邮件系统为例,传统的电子邮件系统是完全不使用任何加密或签名的手段的。拥有接入层控制权的网络管理员,可以轻易地通过在网络上监听数据包来获知用户与自己所使用的邮件服务器之间交换的邮件内容。随后,当邮件到达了邮件服务器时,邮件服务器管理员也可以很容易地知道邮件内容;在邮件服务器将邮件传送到互联网上的另一台邮件服务器时,问题就更多了,每一跳路由,以及它们所经过的所有网络都可以被监听,并将邮件内容泄漏出去;最后,在另一台服务器和收件人之间,也有和发件人这一边一样的风险。
在Internet上传输电子邮件的过程,由于其经过的环节众多,并且几乎完全不受收发邮件的双方控制,因此很容易导致一些敏感信息的泄露。针对这种问题,人们设计出了一种叫做Transport Layer Security(TLS,用于替代SSL)的密码学协议来实现服务器之间,以及客户端到服务器的端到端安全。简而言之,这套协议首先使用公钥加密算法在通讯双方之间协商一个会话密钥,并用这个密钥完成之后的通讯加密/解密。公钥加密算法是一种加密和解密时使用不同密钥的加密算法,以对方公开密钥加密的数据,只能以(不公开的)解密密钥解密,而从公开密钥或已知明文、密文推算出解密密钥的代价非常大,因此它能够确保数据只能被"正确的"那个接收方解密。
Read more...大扇区(超过旧式标准的512字节扇区)是改善硬件工艺或访问方式以后的一种直接提高存储密度的方法。对于磁介质来说,其盘片被分成若干的磁道(通常是同心圆)、每个磁道分成若干的扇区或称扇段,扇区是磁盘读写时的最小操作单元。对于基于闪存的存储设备而言,扇区则是一种模拟传统磁盘的概念。
对于磁盘来说,由于它是一种机械和电子一体化设备,由于各种原因的限制,其寻址和持续读写的可靠性方面都有一定的限制,例如,马达维持同样的转速,且磁头能够稳定在同一个位置,并将数据可靠地连续读写,可能只能持续8KiB或16KiB,为了提高可靠性,我们往往会需要在这之后重新校准设备。另一方面,对于随机写入的情形,较小的数据块有时会更为有利,同时,避免对磁介质的不必要的反复覆写,也有助于提高其使用寿命。因此,在磁道的基础上又引入了扇区的概念。
现代磁盘的设计中,扇区除了用户可见的部分之外,其前后还有一定的空隙用于定位和校验。这些空隙和其附近的介质一样可以用来保存数据,只是制造商和操作系统的撰写者通常不推荐使用这些空间。软盘上的这些空隙在DOS时代可以通过对控制器直接编程并改变扇区尺寸的方式强制覆写,并用类似的方法读出,从而起到一定的保密效果。
随着制造工艺的改善,现今的硬盘在十年前就早已不必受限于512字节的限制。由于在每个扇区前后都需要添加一些信息会浪费一部分空间并增加潜在的定位开销,因此硬盘制造商开始推出4KiB扇区的磁盘。这种磁盘在系统检测时会仍然汇报扇区尺寸是512字节,但物理扇区则是4KiB,并保持现有的512字节编址方式不便,从而与现有的BIOS保持兼容。
另一种已经存在一段时间的大扇区是Flash设备。这类设备采用的方法类似,不过其大扇区更多地是出于制造和避免不必要的擦写而不是提高存储密度考虑。
最后一种大扇区是RAID。许多RAID级别是一次性操作一整个stripe的,此时这种stripe也可以视为一种大扇区。
对于大扇区的支持主要是操作系统,特别是文件系统的责任,而应用程序只需确保自己操作的记录尽量是对齐的整块(例如,16K的记录,在文件中的偏移量都是从16K的整数倍开始)。文件系统需要保证应用程序对于磁盘的这种预期是能够满足的,换言之,文件系统的数据结构不应在磁盘上导致新的不对齐问题,这类不对齐可能是由于分区格式引起,也可能是文件系统本身的设计问题,如果存在这样的问题,操作系统中都需要予以纠正:例如,传统上从第63个512字节逻辑扇区开始的分区,可以牺牲掉一个512字节单元来换取对齐4KiB物理扇区的目的,由于对齐写入和读出操作需要的实际物理操作要少一半左右,因此这样做能够显著地改善性能并提高设备的使用寿命。
FreeBSD 9-CURRENT中目前已经支持通过GEOM子系统的stripe信息来描述磁盘或RAID的物理扇区尺寸以及GEOM相对于物理扇区的偏移量。新的ahci(4)驱动目前已经能够提供相关的GEOM信息给更上层的驱动程序了。
Read more...前一段时间帮一个朋友做了一个非常简单的网址缩短服务,已经上线运行了一段时间,这里把当时设计的一些想法分享出来,等有时间我会把代码也发布出来,程序很简单,用 web.py 做的。
网址缩短服务需要考虑两个问题,第一个问题是如何有效地查询,即,作为约束条件,在访问"短网址"的时候,它必须能够迅速的将结果返回;第二个问题是如何有效地将写操作复制出去。还有一点就是,缩短形成的短网址要真的越短越好。
接口
整个服务包括两个主要接口:一个是请求短网址,输入为网址(作为HTTP回应),输出为短网址;另一个是请求重定向,输入为短网址,输出为到短网址对应的真实网址的HTTP 302重定向回应。
设计
__请求短网址的流程__大致如下:
首先,检测输入的网址是否有效。
然后,计算输入的网址的 SHA256 散列值(计算时增加一个系统全局的salt值)的 URL-safe base64,并查找此散列串是否已经存在;如果已经存在,但对应的网址不同,目前版本将返回一异常(由于SHA256设计中的雪崩效应,这种情况基本可以忽略)。
如果不存在,则从前3位开始逐字向后取散列串,在查找表中查找到找到相同URL,或找不到结果为止;如果找不到结果,则将目前散列串的子串以及网址插入。
__请求重定向的流程__大致如下:
首先检测输入是否有效(不超长或超短)。
然后,直接从Berkeley DB中查找字符串对应的URL(实际实现中,将db文件以散列串首个字符命名,以利于未来将负载分散到不同的服务器)。
返回302回应。
未来的改进
目前的设计假定存在 2^0或2^1或2^2 .. 2^6 个节点能够提直接提供转向服务。转向回应信息可以在前端代理上永久缓存,因此可以通过增加前端代理服务器,而不是后端转向服务节点的方式来进行扩展。目前设计中故障转移等机制比较简单(根据SHA256计算出来的优先权值轮转),未来版本需要解决集群的原子提交问题。
目前的设计没有考虑自定义短网址,比如 foo.com/survey 这样的情况。这个问题可通过在长域名表(完整SHA256 base64与URL映射关系)基础上再增加一个查找表的方法来解决。
目前设计没有考虑删除以及禁止访问某些短网址的情况。
Read more...什么乱七八糟的东西都往数据库里面硬塞,该做的索引不做,不该做的索引一大堆,这再不慢等什么呢,天理难容嘛……
Read more...buffer和cache是两个经常被混为一谈的概念。从直观上说,两者都具备改善系统 I/O 吞吐量的能力,但是这两个概念是有区别的,其提高系统I/O吞吐量的原因也不尽相同。
cache改善系统性能的主要原因是数据访问的 局部性,即,通常应用程序在一段时间内操作的数据集的某个有限的部分,通常是很小的一部分。硬件实现的cache通常会只使用一小块(与主存相比)访问速度很快,但相对比较昂贵的存储部件,并放置于距离CPU较近的位置。
buffer改善系统性能的主要原因是减少不必要的状态切换和设备I/O。由于制造工艺等个方面的原因,系统中不同部件的速度往往是不一样的,一次进行批量的操作(例如,预先读取,或者将写数据凑成一个整数之后再写),往往要比到需要时等待这些操作完成要节省时间,并且有效地降低状态切换导致的开销。
还有一个比较显著的区别是,cache通常是硬件或OS提供,用户程序不需要(多数情况下也没有办法)为其分配存储的机制,通常它在使用者,如用户程序看来是透明的,它属于提供cache的一方而不是其使用者;而buffer往往是由用户程序知道并且与OS共享(换言之,用户程序需要分配一块内存,并告诉OS这块内存将要用于某种操作),或由OS分配,并在主机和外设之间共享(例如网卡的DMA buffer),在使用者看来它通常不是透明的,这些内存往往属于控制内存的程序,如用户程序,或OS,而不是向其传递数据的OS,或硬件。
不过,这个区别主要是传统意义上的cache。最近几年引入的一些新概念,特别是Internet cache并不能用这种方法来区分。我认为最关键的区别其实在于,buffer主要作用是在于减少实际的I/O操作次数,即,将多次操作尽量合并成一次的成批操作,通常其中的数据在操作完成之后,buffer不会被继续使用;而cache的主要作用在于更好地利用局部性原理,减少不必要的I/O,避免代价昂贵(例如,速度很慢)的I/O操作。
Read more...