Becomin' Charles

算法 | LNMP | Flutter | Mac

Becomin' Charles

昨天,我在一台 CentOS 6.10 上面编译 PHP 7.4.7 和编译前几个版本有很大的区别,PHP 7.4 开始使用了一个叫 pkg-config 的东西,有点先进,但是在老旧的系统上,真是无比痛苦的一个体验。

今天我尝试一下在 CentOS 7.8 上面编译一下,之前没有干过,我就记录一下过程,虽然无聊得很,但是记录下来,可以给以后节省点时间。

阅读全文 »

话说,不作死就不会死。

上一篇文章讲解了怎么老旧的 MacBook Pro 重新安装 MacOS 操作系统,我安装成功了,但是跑了一会儿以后,我发现我犯了一个严重的错误,我还是把固态硬盘当作了启动盘来安装系统。

当年,我自己动手,拆掉了 MacBook Pro mid 2009 的光驱,使用光驱位硬盘盒给自己扩展了一块 SSD 固态硬盘,镁光 M4,现在 10 年过去了,我自己密集使用了两年,转送老爸又用了两年多,然后又放了好几年,这块硬盘的可靠性已经是 0 了,就在上篇文章写完,我装成功 MacOS 后,运行不到 30 分钟,我发现 System Preferences 这个 App,也就是系统设置,无法正常打开了。虽然不知道哪里坏了,我猜就是硬盘,另外我想启动个 SSH 服务,发现也连不上去…… 当然了,这不能怪硬盘,还是我自己没设置对,可是设置 App 又不能正常运行,一怒之下关机拉倒了,懒得琢磨了,又萌生了再安装一次 Linux 的想法,不折腾不作死,就不会死啊。

阅读全文 »

话说,不作死就不会死。

我的第一台 MacBook Pro,是一台 2009 Mid,真是有年头了,后来我换了电脑,就给了老爸,后来我又换了电脑,就把第二台给了老爸,老爸说第一台也没用了,还你吧,于是我现在多了一台闲置的 MBP 出来,还是 2009 Mid。

我之前就在家里跑了个树莓派 1 代,挺 Happy,想着,用 MBP 这逆天的性能,跑个 Linux,岂不是无敌了,于是开始了我作死之旅。

阅读全文 »

写这个话题,我是忐忑的,因为我讲不清楚,其实比我一开始以为得要复杂一些,不过,迫于压力,我还是得尝试去说清楚这个问题,如果看到不对地方,希望读者可以不吝赐教,谢谢~

之前写了一篇文章讲《什么是 POS 机》其实也没讲清楚,不过说了个大概。清分这个问题,首先涉及到银行卡收单这个业务,是否可以衍生到网络支付上面,我还没有想得很清楚。不管如何,我们可以从银行卡线下收单业务来看这个问题的性质。

简化情况下的一清和二清的区别

什么是一清

申请 POS 机的,在交易流程里叫特约商户,一般特约商户在收单机构注册开户,然后,安装 POS 机,持卡人刷卡后,通过 POS 机将交易上送到收单机构,再从收单机构通过清算机构发往发卡行,如上图左侧的蓝色线条,这个蓝色线条,叫交易的信息流。发卡行确认信息后,通知收单机构,然后反馈给 POS 机,持卡人就看到了交易成功。

这个时候,特约商户,也就是零售的卖家,其实还没有收到现金。但是因为交易已经被确认,所以,这次购买销售行为可以正常完成。一般清算机构,每天会进行一次日终清算,通过清算,资金会划拨给收单机构,然后收单机构再划拨给特约商户,所以 POS 机经常就是 T+1 到帐的,这我们在《什么是 POS 机》也提到了。

什么是二清

我们再来看看什么是二次清分,看上面图的右边,有一些特约商户,申请到 POS 机以后,再向收单机构申请增机,然后这家商户就有很多台 POS 机,然后将增设的 POS 机租给更小的商户,当完成清算后,钱都会被结算给同一个特约商户,这家商户再通过支付的信息,将资金结算给租用 POS 机的商户。完成一个二次的清分。特此说明一下,二次清分在当下是违规行为。

上面不难看出一个问题,就是 POS 机 理论上都是直接向收单机构去上送交易信息的,那么二次清分机构是怎么做到二清 POS 机 展示正确的商户信息,以及怎样在二次清分时候,做到正确分账呢?

POS 机的安装部署和线下拓展商户,都是一个繁重和细致的工作,也有很强的地域性,所以,收单机构,不一定可以自己经营所有的线下商户,就不得不依赖代理商,代理商很多都是 POS 机设备的生产厂商,注意,他们没有收单的资质,但是生产一台电子设备是合法的。这里,二清机构其实很多都是 POS 机设备的代理商,或者跟 POS 机代理商合作。

这里一个显著的风险点就是,二清机构,并不持有支付牌照,也不受监管,如果捐款跑路,就给租用 POS 机的商户带来很大的风险。

以上说得,都是比较简单的二次清分,比较形象,具体,容易理解。其实真正的二次清分,不是这么定义的。上面的案例,集中在二清清分机构,获得了下属机构的资金,然后二次划拨资金,对资金安全产生了很大的危害。

信息二清

于是,就产生了一种新的形态,二清机构说,我不把下属客户的资金拿到我自己的账上,不碰资金,是不是就行了?于是,产生了二清机构和持牌收单机构合作,在持牌收单机构的账户内,开设虚拟账户,将二清机构的待结算资金停留,通过二清机构的指令(清算依据),直接从收单机构的账户,结算给下属的商户。

这种情况,看起来,资金已经不是从二清机构的账户上结算给下属的商户账户了,但是,在当前,这仍然构成了二次清分,也是央行重点禁止的业务。这里比较重要的一个界定标准,不是资金从哪个账户流出,也不是资金受谁控制,关键在于,谁可以事实上决定的资金的流向,第二种模式,也被业内叫做是“信息二清”,现在的一个趋势是,“资金二清” 也好,“信息二清” 也好,都被称作二清,都是监管打击的对象。

虽然,不合法,但是市场上还是非常需要二清这个方案,这是为什么呢?抛开一开始就诈骗、套现抱有恶意动机的行为不看。合法经营的是否需要二清?

二清存在有其刚性需求

依据我个人的理解,信息中介型的企业,都潜在有二清的使用场景。我们常见的案例是电商平台。电商平台本质上是一种信息中介行为,这种平台往往相比于单个电商卖家,有更多的客户,所以,电商卖家更希望通过平台来获得客户,形成交易。

电商平台的建立,能提供一个虚拟的规模化的交易市场,上面入驻的商户,一般都依托平台的支付体系,所以往往就是消费者把钱先划转到了电商平台的账户上,再由平台结算给每个入驻的商户,这就构成了事实的二清。

我们再抽象点来看,一个信息中介,掌握着交易双方一方的资源,或者两方资源。这是中介赖以生存的核心优势,肯定不愿意将自己的资源直接输送给另一方,必然是愿意自己经营一个平台(市场),让双方在上面完成交易。这个平台不可能允许每个参与者自带一套支付体系,这样对买方极其不友好,而且,不掌握交易数据,对中介方来说,也不能建立长期有效的竞争壁垒。

所以,最后,这个商业模式都会导向二清这个行为。中介方有很强动机掌握交易的具体信息,完成资金的清算结算。所以,抛开违法的部分看,二清有其存在的必然需求。

国家现在打击二清,当然是整顿了市场,规避了系统性风险和信息安全,但是一种很有活力的商业模式,也受到了发展的制约。从长远看,是不能持久的,现在市场上就在提出各种各样的二清解决方案。本质上,需求还是刚性的,大家还在想各种办法来在监管的夹缝里求生存。

不过,终究不是长远的解决办法,还是希望监管政策层面,能推出比较明确的细则,区分对待,让正常做生意的人,有个出口。

POS 的英文是 Point of Sales,字面意思是销售点,百度百科也说是“销售点情报管理系统”,本质上来说,是一套系统,有很多的组成部分。

POS 系统

这套系统,大家见得比较多,主要用于零售点的收银,是零售业门店管理的重要组成部分。

这里面融合了库存,价格,收银,出纳等等功能。基本原理是这样的,门店的商品和信息被录入到系统中,然后需要一个条码读取器,可以扫描商品,统计订单金额,然后生成收银请求,配合银行卡读卡器,完成交易(无现金),也可以弹出一个抽屉,完成现金交易的收钱,找零等。

不过,咱们一般提到 POS 机,指的都是桌上那个小东西,就是 POS 刷卡机。因为这个东西能够从银行卡进行扣款转账,是一次销售行为中最重要的部分,所以刷卡机就往往被称作是 POS 机了。当然,众所周知的,也可以脱离开这个场景使用 :) 具体用途就不解释了。

POS 刷卡机,简称 POS 机,背后对应的业务,专业上叫银行卡线下收单业务。主要是银行类机构,以及第三方支付公司(又称非金融机构)经营的业务。对银行来说,不是主要的业务,但是对第三方支付公司来说,是主要经营的一种业务。

POS 机的持有者,专业上叫特约商户,一般来说,是一个零售型企业。他们为什么要安装 POS 机呢?主要是因为顾客是上帝,顾客更喜欢使用 POS 机进行支付。顾客在专业上叫持卡人,主要持有银行机构发行的储蓄卡,信用卡。银行机构,在这个场景里,叫发卡行。POS 机的作用就是从发卡行发行的卡账户上,将资金扣转并转移到特约商户的账户上。

如果,持卡人持有的卡,不是本行发行的卡,那么需要通过跨行结算组织,完成跨行资金结算,这个跨行结算组织,就是银联。

对于银行来说,去对接海量的线下零售型商户,显然是一个低效益并且也不可能完成的任务,所以,更多的 POS 线下收单业务,都由第三方支付公司经营。第三方支付公司,需要持有经营此项业务的牌照,也就是支付牌照。

对于第三方支付公司来说,经营 POS 线下收单业务,是其特许经营的业务,需要处理好与各种银行机构或者清算组织的业务,以及保障好交易的安全。拓展线下商户的任务,对其来说,是一个低效益的事情。所以,这里又出现了一个角色,就是代理商。

代理商的主要业务是,拓展线下商户,安装和部署 POS 机,维护客户的关系。代理商公司,不具备经营线下收单业务的资格,也即没有支付牌照。所以,其业务得以开展,主要还是依托支付公司的牌照。通过通信技术和计算机系统,完成与支付公司的对接,并在自己的信息系统上管理海量的特约商户客户。

因为涉及到跟清算组织的连接,所以,第三方支付公司的结算,也要符合清算组织的规则,所以,往往,POS 机都是 T+1 结算的。这主要受限于银联的业务规则。当然,这体验不好。于是,代理商公司为了优化自己客户的体验,就想出一个办法,自己设立一家特约商户,然后,生产很多 POS 机,然后把这个 POS 机分发给自己的客户商户,这样客户商户不需要跟支付公司签约,支付给每个商户的钱,都会支付给代理商公司,这个代理商公司再根据每个订单,把钱分给客户商户。这个过程就叫做“二清”,是二次清分的意思。

在二清的场景下,第三方支付公司会把所有的订单支付都结算给代理商公司,然后代理商公司再次把钱分给底下的商户。这里,如果代理商公司,垫付一笔资金,就可以先行将资金垫付给商户,然后等 T+1 的时候,支付公司自然会结算这笔钱。这就优化了客户的体验。

当然,这里存在巨大的安全隐患,如果代理商公司不给客户商户结算,自己拿着支付公司结算的款项跑路,这就带来了巨大的风险。所以,二清是不合规的。对于特约商户来说,如果安装使用了二清的 POS 机也是有巨大的风险的。

使用 POS 机进行收款,是需要支付手续费的。手续费的主要分成方是发卡行,银联,第三方支付公司,以及代理商。手续费的费率是不一样的,到了特约商户这里,可能各不相同。就是因为这里面,第三方支付公司,或者代理商有一定的费用融合在里面,尤其是代理商,其不是金融机构,不接受监管。费用的设置,主要是依赖市场竞争来调节。所以特约商户拿到的 POS 机费率各不相同。各个行业也有不同,一般消费类的场景,现在的行情是 0.6% 左右,如果特别低,可能存在猫腻。

以上知识,主要来自搜索、知乎,不确保准确无误。下面附上一幅图解释一次 POS 机刷卡的业务流程,原图来自网络,不清楚,进行了重绘。

一次完整的POS机刷卡流程

上图中,蓝色的线条代表信息流,红色的线条代表资金流。绿色的是参与方。收单行,也叫收单机构,可以是银行,也可以是第三方支付公司。商户在收单机构处开设有结算账户。如果收单机构是银行,则结算账户本身就是银行账户,但是也极可能是专用的。如果是第三方支付公司,则结算账户可能是某种虚拟账户,在第三方支付公司的托管系统中。从结算账户到商户的一般企业账户,可能还需要一次提现,在图中都被省略。

图中清算账户管理系统是个比较神秘的系统,我猜可能是银联这样的清算组织管理各方结算账户的系统。值得一提的是,这个图里说明,从收单行进行大额清算结束后,再把钱清算到商户的账户,使用的是央行小额系统完成的。对这一点,并没有进一步的信息以印证,大家就看个意思就行了。

在移动支付领域,经常会听到这个术语,I 类户,II 类户,III 类户,这个称法,据说最早开始于 2015 年,中国人民银行的发文(银发[392]号文),内容是《关于改进个人银行账户服务加强账户管理的通知》。

里面规定了各类各级银行,要对客户账户施行实名制管理,以及账户分类管理。通知里,规范了三类账上的名称,功能和限制。

I 类户II 类户III 类户
主要功能全功能储蓄存款和投资理财
消费支付
绑定支付账户
消费支付
绑定支付账户
账户余额无限制无限制少于1000元
使用限额无限额储蓄存款和投资理财无限额
消费支付每日 < 10000 元
消费支付每日 < 5000 元
账户形式借记卡及储蓄存折电子账户电子账户
开户柜面开设
银行工作人员现场核验下,自助机具也可以开设
柜面开设
自助机具不需要现场核验
电子渠道(需要绑定 I 类户 作为身份核验)
柜面开设
自助机具不需要现场核验
电子渠道(需要绑定 I 类户作为身份核验)
转账限额无限制非绑定账户,日 存入/转入 资金累计限额 1 万,年累计限额 20 万;消费、缴费和向非绑定账户转出资金,日累计限额1万,年累计限额20 万非绑定账户,日 存入/转入 资金累计限额 5000 元,年累计限额 10 万;消费、缴费和向非绑定账户转出资金,日累计限额 5000 元,年累计限额 10 万

此外,关于三种账户的发文还有《关于加强支付结算管理防范电信网络新型违法犯罪有关事项的通知》(银发 2016 [261] 号文),以及 《关于落实个人银行账户分类管理制度的通知》(银发 2016 [302] 号文)。进一步规范了三类账户的使用限制和限额。

新增了诸如 I 类户一个客户在一家银行只能开设一个,II 类户年累计限额 20 万,III 类户年累计限额 10 万,日累计限额 5000 元,等规定。

三类账户的限制是从小到大,使用的便捷程度则是从困难到简单。基本可以认为是为移动支付时代定制的规则。

II 类户的一个例子

下面通过一个小例子说明一下 II 类户的现实运用情况。微众银行是中国第一批的互联网银行,是由腾讯牵头成立的,于 2014 年 12 月 16 日成立。

在微众银行的手机 App 中,每个人可以申请一张虚拟银行卡。其实这张卡,就是上文提到的 II 类户,这个账户的开户过程,不需要用户亲自到银行柜面核验,但是开设过程中,需要绑定一个 I 类户才能进行身份验证。

微众银行的储蓄卡,上面有II类户标记

根据上面 II 类户的说明,这个账户可以用于理财投资,所以,微众银行 App 里面是可以使用微众银行卡,购买理财产品的。不过将资金转入到微众银行,是比较麻烦的,如果你尝试往里面转账,你会注意到,有两个不同的转账功能。一个是从绑定卡直接扣转,这个显然要符合 II 类户的转账限额,也就是 1 万元一次的限制。这边可能会有另一个限制,就是代扣的单次限额限制。

另一个转账进入的途径是大额转账,是从你的其他银行的 I 类户的手机银行,直接给微众的卡号转账汇款。但是,你发现,如果没有事先将出账卡登记绑定到微众银行 App 的话,转账也会失败的。这也是来源于 II 类户的限制。如果未进行事先与 I 类户绑定的操作,也会受到单次 1 万,累计 20 万的限制。

如何查询自己的卡是否 II 类户?

  • 工行-中国工商银行app-我的账户-查询明细(1类卡没有提示,2类卡会标明是2类卡账户)
  • 中行-中国银行app-账户管理(1类卡标明1类账户,2类卡会标明是2类卡账户)
  • 建行-中国建设银行app-登陆后点击首页卡号下方,进去之后会有提示1类卡还是2类卡
  • 农行-中国农业银行app–我的账户-借记卡-人名币可用余额-进去后卡号前方有提示1类卡还是2类卡。
  • 交行-交通银行app-搜索“银行卡管理”,(1类卡标明1类账户,2类卡会标明是2类卡账户)
  • 招行-招商银行app-我的-银行卡(1类卡没有提示,2类卡会标明是2类卡账户)
  • 兴业-兴业银行app-我的-银行卡-选择银行卡后在账户类型可查看

在看一些印度支付相关的文档时候,发现各种英文缩写出现得自然而然,仿佛人尽皆知一般,可惜对我们来说,还是太过陌生,本文收集一批,便于查阅。

缩写全称备注
RBIReserve Bank of India印度储备银行(印度的央行),于 1935 年 4 月 1 日作为私人实体设立,于 1949 年国有化,使用货币政策来维持国家金融稳定,负责监管国家货币和信用系统。机构位于孟买。
IBAIndian Banks’ Association印度银行联合会,成立于 1946 年 9 月 26 日,位于孟买。目前有 237 家银行业机构成员。致力于发展、合作和强化印度的银行业,在新系统实现和标准采纳方面给予成员协助。
NPCINational Payments Corporation of India印度国家支付公司,零售支付和结算系统组成的伞形组织。由 RBI 和 IBA 在支付和结算系统法案(Payment and Settlement Systems Act, 2007)要求下设立,致力于建设一个健壮的支付和结算基础架构。
IMPSImmediate Payment Service即时支付服务,于 2010 年 11 月 22 日发布,在多种渠道上可供访问的,健壮的跨银行实时全天候资金传输服务。目前,该服务有 243 个成员,包括银行和 PPIs。由 NPCI 提供。致力于构建基于移动设备的银行业务基础。
UPIUnified Payments Interface在一个移动 App 中使用多家银行账户的统一支付接口。首次发布于 2016 年 4 月 11 日,有 21 家成员银行,由 NPCI 开发。使用支持 UPI 的 App,可以绑定多家银行的卡片。UPI 支持双因素(2FA)和一次性密码(OTP)。是 P2P 的生命线。支持代付和代扣。IMPS 之上的接口封装
PPIsPrepaid Payment Instruments
PSPPayment Service Provider支付服务提供商
VPAVirtual Payment Address虚拟支付地址

本文内容是研究印度网络支付行业的一些笔记,主要是便于自己记忆和理解,内容不一定准确,请自行甄别。

什么是数字钱包?

数字钱包(Digital Wallet)也被称为是电子钱包(e-Wallet),从概念上来说,就是一个字面意义的钱包,只不过是电子版的。不像普通钱包,存储的是“物理意义上的”的纸币和硬币,数字钱包使用数字表示货币。

对比中国的概念来看,更像是支付宝的余额,微信支付的钱包零钱。里面的数字就代表现金。

可以使用信用卡、贷记卡,网络银行,或者 UPI 往数字钱包里充钱,但是停留在数字钱包里的钱没有任何利息。这和国内的情况也是一样的,支付宝发明了余额宝,微信支付发明了零钱宝,来解决没有利息的问题。

电子钱包里面,内置了很多账单支付功能。对比支付宝,例如“生活缴费”功能,就是支付宝内置的账单支付功能。数字钱包里,存储的金额是有限的,在印度的限制是 20,000 卢比。

什么是普通银行?

这个概念其实很简单,放在这里主要是对比另外两个概念的。受到高度监管的金融机构,除了能储蓄以外,还可以给个人和企业提供信贷服务。对储蓄的现金支付固定或者浮动的利息。

银行可以发行 ATM卡、借记卡(Debit Card)、信用卡(Credit Card),支票(Cheque),可以开设网络银行(Internet Banking),移动银行(Mobile Banking),可以进行 UPI 交易。存钱最安全的地方,是一国经济的核心构成。

什么是支付银行?(Payments Bank)

是一种由 RBI(Reserve Bank of India)开发的一种新型银行模型。基本就是银行,但是不能进行信用和贷款服务,此外还有一些限制。依据 RBI 最新的条例,支付银行可以存储 Rs. 1 lakh 的现金(10万卢比)。可以依据银行的业绩表现来进行升级。

支付银行可以发行 ATM、借记卡,本票,但是不能发行信用卡。很快也会放开网络银行,移动银行和 UPI 交易业务。你可以往你的账户上放钱,也会收到利息。目前有八家机构可以开设支付银行(拥有牌照):

  • Paytm(马上)
  • Airtel M Commerce Services(已经开设)
  • Vodafone M-Pesa
  • Reliance Industries(把 JioMoney 钱包,转化成支付银行)
  • Aditya Birla Nuvo
  • National Securities Depository
  • Department of Posts
  • FINO PayTech

「注」以上内容大部分翻译自:

Digital Wallet vs Normal Bank vs Payments Bank – Clearing The Confusion

当年,刚开始玩网站的时候, SSL 证书还是很难获得的,只有少数几个机构支持颁发免费的证书,所以我们只能自己签名一个证书,来部署 HTTPS,但是,自签名的证书不会被浏览器承认,12306 刚上线的时候像个骗子网站,就是因为它用了自签名的证书。

后来,有了救世主,就是 Let’s Encrypt,面向全网颁发免费证书,无条件的。截止目前,全网已经有 1.9 亿网站部署了 Let’s Encrypt 的证书。我以为,我这辈子再也用不到自签名证书了。哪知道,还是让我碰到了,用自签名证书更方便的场景。

场景

这里也顺便说说我的场景好了。第一次遇到非要自签名场景是公司里部署企业内网安全的时候。咱们访问一个网站的时候,一般是服务提供商,需要部署证书,我们作为个人用户,需要通过公信力机构,认定我们在访问的服务,使用的是合法获得的证书,且我们的通信是加密的。在公司,内网网站,还需要对访问者进行验证,不是谁都能看公司内网的,必须是公司的员工才行,怎么确认这一点呢?一般我们使用密码,更进一步,只有登记在册的设备才能访问公司的内网网站,那么就需要用到客户端证书。大家,平日里用的客户端证书的场景很少,一般只有访问网银的时候,才用客户端证书,也就是 UKey,原理是一样的。

颁发客户端证书,目前,全网免费的服务非常少,既要免费,又要可以信任的,就更难找了。所以,我们当年采用这一方案的时候,不得不使用自签名证书。

第二次就是最近,我是一个个人开发者,想要做一个 Telegram 机器人,这就需要跟服务器通信,比如,设置 Webhook 之类的,现在这类需要去服务端注册的回调,都要求强制 HTTPS 了,微信的公众号也是需要 HTTPS 的。这里,其实 Let’s Encrypt 是可以解决的,不过我想在本地电脑搭建一个开发环境,让服务器的回调发到我的本地,这样,我开发调试起来非常容易,那就不那么容易解决证书的问题。所以,我想到了,还是弄个自签名证书方便,反正只是在开发环境用一下。

EasyRSA

EasyRSA 是 OpenVPN 社区旗下的一个自项目,专门用来搭建一个 CA 的全部命令行套件。其本质是一套 shell 脚本,里面真正起作用的是 OpenSSL 的命令。如果,你非常熟悉的话,直接用 OpenSSL 也是可以的。

现在进入主题了,接下来本文介绍如何使用 EasyRSA 创建一个 SSL 证书。

下载安装 EasyRSA

因为是一款 shell 软件,本质上下载后解压就是安装完毕了:

1
2
3
4
5
# 去 GitHub 下载最新 Release 现在是 v3.0.6
curl -OL https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.6/EasyRSA-unix-v3.0.6.tgz
# 解压缩
tar xf EasyRSA-unix-v3.0.6.tgz
cd EasyRSA-v3.0.6

然后,我们可以看到一个 easyrsa 可执行文件在目录里,已经安装完毕了。

创建证书颁发机构 CA

接下来就要创建证书颁发机构了,这里有个小技巧,介绍一下,就是等下可能会在目录下生成很多文件,你可能会搞不清楚,生成了哪些,可以现在提前把整个目录变成本地 git 库,提交所有文件,然后一旦有新文件生成了,就很容易分辨。

1
2
# 第一个命令,初始化公钥基础设施(Public Key Infrastructure)
./easyrsa init-pki

公钥基础设施(PKI),是一个安全体系,也是咱们整个互联网的安全基础,我们接下来要讨论的一些概念,都是这个体系内的角色,所以,无论要扮演哪个角色,都需要先拥有一个 PKI。

PKI 简易版流程

图注:PKI 的简易版流程

初始化好 PKI 后,我们会发现,多了一个目录,叫 pki/ 里面有两个目录,一个是 private 显然,里面将要存储私钥了,另一个目录叫 reqs/ 看起来,要存储申请(request)了。

第一个,要扮演的角色是证书颁发机构(Certificate Authority)也就是我们说的 CA:

1
2
# 创建 CA 的时候,可以不使用选项,这里开启了一个 nopass 的选项,作用是,创建的 CA 不使用密码保护自己最重要的私钥,因为咱们是在玩开发环境嘛,如果是用于生产,还是需要密码保护的。
./easyrsa build-ca nopass

创建过程中,会问你要 Common Name,你可以输入一个英文句号 . 来表示留空,我输入了自己的名字 Charles,哈哈 :D

创建好 CA 后,我们在 pki/ 目录下,看到一个 ca.crt 这是 CA 的公钥,在 private/ 目录下,有 ca.key 这是 CA 的私钥,也是一个 CA 最要命的东西了。还有其他一大堆的文件,先不要管了。

创建申请表 CSR

刚才也简单介绍了 PKI 是怎么回事,也说到,在这个体系内,会有好多个角色,第一个角色,就是证书颁发机构 CA,然后,我们的目的是得到一张服务器证书,现在就要扮演另一个角色,就是证书申请人

1
2
3
4
# 作为证书申请人,也是需要先初始化 PKI 的,当然,因为咱们全在同一台电脑上,就没必要这么做了,因为上一个步骤,已经有初始化好了一个 PKI 了
./easyrsa init-pki
# 接下来,要创建证书签名申请 CSR(Certificate Signing Request),咱们这里又用了一个 nopass 的参数,开发环境噢。Demo 只是一个名字而已,无所谓是什么。
./easyrsa gen-req DEMO nopass

这里应该比较容易理解吧,有一个证书颁发机构,申请人,先填写一个申请表,接下来拿去机构盖章(签名),于是就签发了一个证书出来。

这个脚本的执行过程中,会问及你的 Common Name,这个时候,如果证书是要用于网站的域名证书的时候,应该在这里填写上网站的域名。

导入申请

继续咱们的角色扮演游戏,咱们现在又要扮演回 CA 的角色了。申请人已经填写了申请表,接下来,提交了申请。作为 CA,我们收到了申请人的申请,需要将申请导入系统:

1
2
# 还记得上面初始化 PKI 的时候,我们说了一个 reqs/ 的目录吗?申请表在那个目录里
./easyrsa import-req ./pki/reqs/DEMO.req HelloDemo

上一个步骤,我们把 CSR 取名为 DEMO 了,所以,这次我们把第二个参数取名为 HelloDemo,为了跟刚才那个名字不一样,然后你就能看到比较好玩的,pki/ 目录下,除了 DEMO.req,又多了一个文件叫 HelloDemo.req,我有一个大胆的想法不知道当讲不当讲,哈哈哈,你猜对了,这两个文件一模一样,因为一般来说,证书申请的时候,CA 都不会是你自己的电脑,现在同一台服务器,扮演两个角色,就搞笑了,左手导入到右手,根本一回事嘛,所以,上面这步,在同一台电脑上是多余的。可以根本不做。只要你记得,你想签名的那份申请是叫 DEMO 就可以了。

签发证书

既然演戏,我们就演到底,咱们现在继续扮演 CA,需要给刚刚导入的 HelloDemo 签名了:

1
./easyrsa sign-req server HelloDemo

命令倒是简洁而且干脆啊…… 执行完毕后,证书就签发完毕了,在 pki/ 目录下,多了一个叫 issued/ 的子目录,里面存放了签发的证书,HelloDemo.crt,有效期默认是 1080 天。私钥就是前面生成 CSR 的时候,在 private/ 目录里的 DEMO.key。到此,我们需要的自签发网站证书就生成完毕了。

证书部署

生成好证书以后,我们就要把证书部署到本地的 Web 服务器上了。

Apache 证书部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SSLEngine on

# Uncomment the next line if Apache should not accept SSLv3 connections, to learn more google for "POODLE SSLv3".
# SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:-SSLv3:+EXP:+eNULL

# Comment the next line (and uncomment the line above) if Apache should not accept SSLv3 connections, to learn more google for "POODLE SSLv3".
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL

SSLProtocol -all +TLSv1.2 +TLSv1.1 +TLSv1
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
SSLHonorCipherOrder on
SSLCompression off

SSLCertificateFile "/path/to/cert.crt"
SSLCertificateKeyFile "/path/to/cert.key"
SSLSessionTickets on

<VirtualHost/> 区段内,添加上述 SSL 有关的配置,关键是 14,15 行,证书文件和私钥的配置。因为,这个例子里面是顶级 CA 直接签发,所以,也不需要配置 Chain 了,否则真正的 SSL 证书还需要配置 SSLCertificateChainFile。因为一般颁发证书的,都不会是顶级 CA,所以,需要 Chain 来描述整个证书链,让浏览器可以确认安全。

Nginx 证书配置

在 nginx 服务器上,配置大概是这样的:

1
2
3
4
5
6
7
8
9
10
11
ssl on;
ssl_certificate /path/to/cert.crt;
ssl_certificate_key /path/to/cert.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:DES-CBC3-SHA;

ssl_prefer_server_ciphers on;

上面这一段,配在 server 区段里。咱们的例子里,生成的证书对是 HelloDemo.crt 和 DEMO.key 一个是公钥,一个是私钥,我重命名为 cert.crt 和 cert.key,主要是为了好看,这里说明一下。

根证书导入

使用了私自签发的证书后,用浏览器访问本地的站点,会发现浏览器报不安全,要点好几次,才可以真的进入,还会有一个红色的警告。如果嫌麻烦的话,可以把跟证书,导入到系统的信任证书中。就是咱们在创建 CA 的时候,生成的 CA.crt ,在各种操作系统里,基本双击就可以激活导入程序了,询问的时候,都点“信任”就可以了。你自己生成的证书,也没什么可怕的了。

总结

以上这些,其实都可以使用 OpenSSL 里面自带的命令完成,不过,那个命令的参数非常多,也非常不友好,比较起来就好像是用 C 语言编程和用 Python 语言编程的区别。后者对用户更加友好,隐藏了更多的底层细节,生产力更加高。

本文介绍了 EasyRSA 的基本使用方法,以及穿插介绍了 PKI 的基本流程和几个关键角色。如果想要深入的了解,还是敬请阅读《HTTPS权威指南》by Ivan Ristic。

—全文完—

Update:

今天用了这个自签名证书,部署 Telegram 和 Potato 的机器人的 Webhook,发现,土豆是正常能用的,但是电报竟然一直说证书验证错误。这里贴一个电报官方给的生成自签名的方法:

1
openssl req -newkey rsa:2048 -sha256 -nodes -keyout YOURPRIVATE.key -x509 -days 365 -out YOURPUBLIC.pem -subj "/C=US/ST=New York/L=Brooklyn/O=Example Brooklyn Company/CN=YOURDOMAIN.EXAMPLE"

注意一下,它用的是 openssl 套件,调用了 req 命令,根据上面的介绍,这个命令本质上是生成签名请求用的,文档里说,也可以用于生成自签名证书,场景是生成 root 证书的时候。

使用隧道搭建开发环境数据库

最近,我在写一个小的项目,用到了 MySQL 数据库,然后我发现一个非常烦恼的问题,我在家里电脑的本地环境改了数据库,到了办公室,代码里的变更通过 GitHub 同步过来了,但是数据库里的变更则完全没有。虽然,也有类似 Migration 之类的解决方案,但是,毕竟是密集开发的阶段,都使用 Migration 太过麻烦了。每次记住自己的操作,重放一遍,或者导出整个数据库,也一并提交到 GitHub 未尝不可,可比起一个真正的两边都能连接的开发环境数据库服务器来说,体验还是差多了。

我自己有腾讯云和阿里云的 VPS,于是就想到了何不搭一个开发环境的数据库来用呢?因为腾讯云服务器上部署了本博客,本来就有数据库,于是我就直接选择了使用腾讯云。别的云原理也是一样的。

安全起见,数据库一般都是侦听本地端口,如果在公网开放端口,则非常不安全。但是,想要从家里和办公室都能连到云端的数据库,则必须解决网络联通性的问题。

于是我想到了隧道。

通过构建隧道,可以将服务器的端口映射到本地,用起来就像在本地开了侦听端口一样。能做到这个效果的非常多,比如 SSH 就是最常见的一种隧道软件。Google 搜索能找到很多的 SSH 建立隧道的范例,本文就不赘述了。

这次我使用的是 KCP 协议隧道。我使用了 kcptun 这个软件。首先在服务器下载软件最新版本,然后,使用如下命令,开启 KCP 服务器侦听:

1
screen -dmS KCPSERVER ./server -l :60331 -t 127.0.0.1:3306 -key "pwd@123456" -mtu 1400 -sndwnd 2048 -rcvwnd 2048 -mode fast2

然后,在客户端本地,同样下载好,使用如下命令开启客户端连接:

1
screen -dmS KCPCLIENT ./client -l :3306 -r 128.142.11.11:60331 -key "pwd@123456" -mtu 1400 -sndwnd 2048 -rcvwnd 2048 -mode fast2

如此,就建立了一个从本地到服务器的连接,并将服务器的 3306 端口,映射到本地的 3306 端口,中间使用的隧道协议还是加密的,这样就不用担心被黑客扫到 MySQL 服务器的端口了。

本地数据库的配置时候,Host 填写 127.0.0.1,端口 3306,这里比较需要注意的是服务器的用户授权:

1
GRANT ALL ON db_dev.* TO dev@localhost IDENTIFIED BY "Dev@demo1";

这样写就不对了,因为一般来说,我们都在本地连接,使用 localhost 作为连接来源的 host 是没问题的,现在通过隧道转发到 server 来的连接,来源 host 到底是哪里呢?

在腾讯云的 CVM 上,我实测下来,应该使用 CVM 服务器的内网 IP 地址,怎么确认这一点呢?其实用客户端尝试连接时候,看报错就知道了。如果我们选的 host 不对,那么连接时候鉴权无法通过,从报错信息里,可以看到应该授权的 host IP 地址。

这样我就相对安全地搭建了为两个本地环境共享的云端开发环境数据库。

这里有个小的技巧,就是善用同步网盘的功能。刚才说到了 KCP 隧道需要在本地安装客户端,启动命令里是有 key 的,密钥不能提交到 GitHub 去的,这是基本常识,包括服务器的 IP 地址也不能暴露到 GitHub,那样就被黑客看到了。

所以,我用的是平时同步文件用的网盘。因为我是 Mac 系统,实际上我用的就是 iCloud,把启动客户端的命令,写在一个 shell 文件里,然后放在 iCloud 网盘上,去了办公室,直接执行就行了,可以直接连接到服务器,在本地映射出服务器上的 MySQL 端口。

另外,在服务器上,可以把启动 Server 的命令也写入一个 shell 脚本,然后配置到 crontab,每 10 分钟重复执行一次,如果 KCP 的服务器端意外退出,就会被 crontab 拉起。非常简单粗暴地实现了可靠安全的 C/S 架构隧道。