在医疗健康领域引入软件开发安全实践

BSI简介

“Build Security in DNA”简称BSI,是在开发过程中内置安全的软件开发实践。 顾名思义,BSI是要将各种安全措施从早期就纳入到软件开发生命周期的每个阶段; 因此,安全是内建的,而不是事后补齐的。通过早期引入这些实践并在整个开发生命周期中进行审查,团队会更早地考虑到安全性的问题并尽早收到反馈。这让团队获得了更多的时间和选项来响应和预防安全问题。

下图描绘了BSI的实现。 我们将安全性作为敏捷开发过程的一部分,在每次迭代中逐步建立和完善我们的安全措施。

通过在软件开发生命周期中添加各种安全措施,安全风险的反馈渠道增加了,安全问题反馈周期缩短了,因此安全问题可以立即得到反馈且进入持续改进的闭环。 通过在业务分析过程中引入威胁建模,可以在某些潜在的安全问题出现之前就主动将其避免掉,从而做到防范于未然。

项目背景

与Clinton Health Access Initiatives(CHAI)合作,我们开发了Electronic Stock Management System(ESMS),这是一个安卓平板APP,其后端对接开源医疗物流平台OpenLMIS,致力于为莫桑比克的患者提供更好的医疗服务。 ESMS有两个主要目标:首先是通过提供用户友好的数字解决方案和自动计算表单来减少医疗工作者的工作量;二是及时、准确的收集药品库存信息,并生成报告,以协助卫生部门来规划、分配、运送药物给卫生站。

如果系统存在安全问题就可能影响到医疗机构运送药物的及时性,进而延缓病人的治疗; 所以确保系统安全是项目团队最重要的工作之一。

引入BSI实践

BSI可以从早期就开始提高软件的安全性,并确保安全问题能得到正确的处理。来看看我们在莫桑比克使用OpenLMIS为CHAI所做的项目的一些例子。该项目在BSI引入时已经处于第二阶段了,其大多数功能已经开发完成。基于这种情况,我们把BSI中的活动重新按优先级排了序,首要做了以下工作。

安全培训工作坊

BSI的主要思想之一是,安全性不仅仅是外部信息安全团队或安全顾问的责任,而是交付团队中的每个人都应该了解的事情。 我们针对Open Web Application Security Project (OWASP)的十大安全问题举办了为期一天的工作坊。ThoughtWorks的安全顾问为项目中的各种角色:开发人员,质量分析师和业务分析师都提供了培训内容。以下是我们向与会者介绍的问题。

在工作坊期间,安全顾问为每个问题解释了定义、概念、理论、行为和预防性解决方案,然后通过实例说明了这些内容,以便与会者理解这些问题产生的后果。工作坊的内容还包括与会者现场上手实操OWASP ZAP和Burp Suite等工具,以此来体验如何排查安全问题。 这次工作坊为开发阶段引入BSI实践打下了良好的基础。

安全性功能测试

安全性功能测试应该内建在质量保证流程中。安全性功能测试涉及身份验证和授权(登录/退出、忘记密码、用户管理等)。根据工作坊介绍、讨论的概念和工具,团队成员和安全顾问一起进行了安全功能测试,涵盖用户访问控制,会话到期等方面。这些测试是手动进行的,并添加了针对这些场景的自动化测试,以确保未来的改动不会再次引入这些问题。

我们发现在一些最常用的功能中存在安全问题,例如在用户注销后会话没有关闭,或非管理员用户能够查看管理员的内容等。

根据优先级排名中的位置,团队成员修复了这些安全问题,完成了一个问题检测和消除的闭环。

渗透测试

渗透测试用于分析系统以识别弱点、技术缺陷或漏洞。从攻击者的角度检查系统,了解什么可能危及系统的安全性。安全顾问与质量分析师合作分析了所有的用例,发现了更多的问题。 例如,登录功能可能会受到暴力攻击,或者可能会通过提交大量数据来攻击,导致拒绝服务。与安全功能测试活动类似,团队修复了这些发现的问题。

代码安全审查

基于安全顾问引入的安全编程原则和指导,团队进行了安全代码审查。 重点放在以下几个模块上:认证/授权,日志记录,密码保护。发现的所有问题都记录在了Mingle的技术卡或缺陷卡里。然后,团队给这些卡排列了优先级,并采取适当的措施来消除或减轻了问题;例如,如果我们发现密码是使用哈希算法存储但没有加盐(salt),那么团队会建一张技术卡,并给予其高优先级,以便在下一次迭代中首要修复该问题。

结论

每一个软件项目都应该从一开始就考虑安全性问题。现在大多数企业级软件都连接到了互联网上,安全性就尤为重要。联网应用的增多是一种趋势,这就增多了可被攻击的潜在目标,安全风险也会随之而来。在开发阶段没有足够的安全保护措施将对项目的长期运行产生负面影响。

反馈周期过长

一般来说,安全问题是在渗透测试阶段显露出来的,有时甚至是应用程序上线后才发现。这样问题的发现、报告和解决要花费很多的时间。

修复成本高

如果是在软件项目的晚期阶段才发现安全问题,软件体系结构已经定型并实现了,这时修复问题就变得额外困难。

BSI可以在开发阶段提高软件的安全性。BSI的目标是在软件发布前,通过业务与技术的手段来确保安全性。

没有绝对的安全,BSI并不能保证系统是完全安全的。然而,对于会向着更大更复杂方向演进的软件系统而言,BSI的安全软件开发过程肯定可以从源头控制安全风险,大大降低黑客攻击的可能性,并显著降低软件投产后安全问题所造成的损失。

作者:刘庆华、崔鹏飞


更多精彩洞见,请关注微信公众号:思特沃克

Share

职责链模式的别扭就像用门框夹核桃

职责链模式

责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。该模式还描述了往该处理链的末尾添加新的处理对象的方法。

以上是wiki对职责链模式的定义。

举个例子来说,我们的系统中需要记录日志的功能。日志需要根据优先级被发送到不同的地方。

低优先级的日志输出到命令行就好了。而高优先级的错误信息则需要通过邮件通知相关人员并且输出到命令行。

这个例子也是来自wiki的。

以下是wiki提供的Java实现:

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
abstract class Logger {
    public static int ERR = 3;
    public static int NOTICE = 5;
    public static int DEBUG = 7;
    private int mask;

    private Logger next;

    public Logger(int mask) {
        this.mask = mask;
    }

    public void setNext(Logger logger) {
        next = logger;
    }

    public void message(String msg, int priority) {
        if (priority <= mask) {
            writeMessage(msg);
        }
        if (next != null) {
            next.message(msg, priority);
        }
    }

    abstract protected void writeMessage(String msg);
}

首先定义一个Logger抽象类。从其setNext和message这两个方法可以看出,我们后面会把多个具有不同writeMessage实现的Logger链到一起,并且依次让它们处理某件需要被记录的事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class StdoutLogger extends Logger {
    public StdoutLogger(int mask) {
        super(mask);
    }

    protected void writeMessage(String msg) {
        System.out.println("Writing to stdout: " + msg);
    }
}

class EmailLogger extends Logger {
    public EmailLogger(int mask) {
        super(mask);
    }

    protected void writeMessage(String msg) {
        System.out.println("Sending via e-mail: " + msg);
    }
}

class StderrLogger extends Logger {
    public StderrLogger(int mask) {
        super(mask);
    }

    protected void writeMessage(String msg) {
        System.err.println("Sending to stderr: " + msg);
    }
}

然后有三个Logger的实现,分别为向命令行输出消息,发送邮件(当然是假的),向命令行输出错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ChainOfResponsibilityExample {

    private static Logger createChain() {
        Logger logger = new StdoutLogger(Logger.DEBUG);

        Logger logger1 = new EmailLogger(Logger.NOTICE);
        logger.setNext(logger1);

        Logger logger2 = new StderrLogger(Logger.ERR);
        logger1.setNext(logger2);

        return logger;
    }

    public static void main(String[] args) {
        Logger chain = createChain();
        chain.message("Entering function y.", Logger.DEBUG);
        chain.message("Step1 completed.", Logger.NOTICE);
        chain.message("An error has occurred.", Logger.ERR);
    }
}

最后,有一个main函数,创建三个Logger的实例,把它们通过setNext链在一起。 只需要调用一次message就可以让三个Logger依次工作。

如果以后再有更多的Logger呢,还是可以通过同样的方式把它们链接起来协同工作。

很好,很强大,很易于扩展,对吧?

不过再想一下

这三个Logger的实现类看起来都非常的单薄,弱不禁风。

一个接收mask的构造函数,其唯一职责就是把接收到的mask传递给父类的构造函数。

然后父类根据mask和所发生事件优先级的大小关系决定到底要不要调用子类实现的writeMessage方法。

也就是说,子类完全没有定义自己的实例级状态,其实例级方法的行为也就谈不上随着其状态的变化而变化了。

换句话说,这几个子类存在的价值就在于为父类提供writeMessage这个函数。

啊。。。。。。!

一说到提供函数,我就想到了。。。。。。

functions

我想到的自然是FP了,既然需要的是函数,那我们就使用函数好了。

何必用更重的抽象手段:类,去包裹函数呢?

下面就是比较偏函数式的Scala实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
object Loggers {
  val ERR = 3
  val NOTICE = 5
  val DEBUG = 7

  case class Event(message: String, priority: Int)

  type Logger = Event => Event

  def stdOutLogger(mask: Int): Logger = event => handleEvent(event, mask) {
    println(s"Writing to stdout: ${event.message}")
  }

  def emailLogger(mask: Int): Logger = event => handleEvent(event, mask) {
    println(s"Sending via e-mail: ${event.message}")
  }

  def stdErrLogger(mask: Int): Logger = event => handleEvent(event, mask) {
    System.err.println(s"Sending to stderr: ${event.message}")
  }

  private def handleEvent(event: Event, mask: Int)(handler: => Unit) = {
    if (event.priority <= mask) handler
    event
  }
}

这个代码已经简短到我不想解释的程度了。不过还是解释一下吧。

三个log的的等级ERR,NOTICE和DEBUG和之前Java的实现是一样的。

一个case class Event,用来包裹需要被log的事件。

type Logger则是声明了一个函数签名,凡是符合这个签名的函数都可以作为logger被使用。

然后便是三个函数实现,它们将mask通过闭包封进函数内。这三个函数共同依赖一个私有handleEvent函数,其作用和Java代码中的message类似,判断mask和正在发生的事件之间优先级大小关系,并以此决定当前logger是否需要处理该事件。

哎?等一下,这个是职责链模式啊,那个啥,链在哪儿呢?

很简单,这样就可以链起来了:

1
2
3
4
5
6
7
8
9
10
11
12
object ChainRunner {

  import chain.Loggers._

  def main(args: Array[String]) {
    val chain = stdOutLogger(DEBUG) andThen emailLogger(NOTICE) andThen stdErrLogger(ERR)

    chain(Event("Entering function y.", DEBUG))
    chain(Event("Step1 completed.", NOTICE))
    chain(Event("An error has occurred.", ERR))
  }
}

以上代码中的andThen就可以把三个logger链在一起。

这个andThen是个什么东西?何以如此神奇?

欲知详情,请参考我之前的另一篇博客: http://cuipengfei.me/blog/2013/12/30/desugar-scala-9/

而链接之后的结果本身也是一个函数,于是我们就可以调用chain并传入Event了。

这份代码和前面Java版的行为是等价的,输出是一致的。

门框夹核桃

最后回到标题上去:门框夹核桃,意即用不合适的工具解决问题。

职责链模式想要做到的事情其实就是把多个函数链起来调用。

该模式提出的时候FP并不如今日盛行,其作者选用类来包装需要被链接的多个函数,这无可厚非。

无论是class,还是function,都是为程序员提供抽象的手段。当我们想要链接的东西就是多个function,选择直接用function而非class就会显得更加自然,也更加轻量且合适。

当年design pattern的作者广为传播各种patterns,实为功德。

不过今天我们有了核桃夹,就无需一定要用门框了。

最后,依照惯例,羞辱Java一小下下。 以上wiki提供的实现有77行,偏FP风的实现只有38行,只有一个实体Event。

Share

职业女性确实处于劣势吗?

源起

前两天,在一个武汉本地程序员聚集的技术社区微信群里某位群友发了两张图片:

8b1ece2agw1eqsw4fbiytj20fe0a6q8i

8b1ece2agw1eqsw4dzf8ej20fe09v0z9

这是某个IT公司的招聘宣传,为程序员提供的鼓励师。

(由于图片出现在愚人节期间,不确定该公司是真的有这样的人员配备,还是恶作剧的,此处暂且存疑)

马上群里就有一位X君跳出来说这种事情就是混蛋啊,怎么女人就得给男人端茶倒水擦汗啊。

另外一位Y君就说没有啊,这就是开个玩笑啊,不要这么较真啊。

X君继续说:!@#¥%……&*啊

Y君回应:*&……%¥#@!啊

于是,你也可以猜到的,这中间X君就说了IT行业对于女性从业者存在歧视,收入不平等之类的话。

这让我颇为感慨:武汉也无非是这样。武大的樱花烂熳的时节,群中却有这样标致极了的讨论。其实,又何止武汉呢?

正当X君与Y君酣战之时,有另外一位群友问声称存在收入歧视的X君是否有数据支持其观点。

恰巧我这周正在看《胡适文选》。胡适之先生反复提醒读者要有怀疑精神,凡事要讲求证据,要用科学的手段得出科学的结论。

胡适之先生之言于我心有戚戚焉,于是我便想要搜罗数据,深入了解一下这个话题,算作是对胡适之先生的遥远致敬。

以上,为源起。

定题

近来我正尝试着自我疏离本性中近似于周树人先生的那一部分。

便不太愿用“歧视”这个颇为尖刻的词汇,因而本文的标题中用了“劣势”这一稍为中性的说法。

既然要考据,就不妨把话题放大些,不独观察IT行业的女性,莫若把视角扩宽到整个职业女性上去。

再加上我不是专业的考据家,并没有投入大量时间精力去搜索资料,交叉引证也不够详备,那就不能怕会过谦,也在标题上加上“不甚严谨”这几个字。

于是便有了这个颇显啰嗦的标题:《职业女性确实处于劣势吗?记一次不甚严谨的考据 – 向胡适之先生的遥远致敬》。

是为题目由来。

开篇

我是一个颇为庸俗的人,也时常会被称为理性的人。

于是,别人看待职业女性的眼光、上司是否会给小鞋穿、同事是否会区别对待等等这些无法量化,难以考量的因素均不采用。

我就只认准了:

在一个行业中具有某种特征的人群占多数就可以被称作是有优势的

在一个行业中具有某种特征的人群挣钱多就可以被称作是有优势的

这两条考校标准。

所以接下来通篇都围绕着人数多寡和挣钱多少展开。

什么行业收入高?

中华人民共和国国家统计局,中国统计年鉴(2014)中有一个条目:按行业分城镇单位就业人员平均工资,以Excel格式提供:

(这一行Excel实在是太长了,我把它分开截了两张图)

8b1ece2agw1eqsy6hday7j21wc090q76

8b1ece2agw1eqsy4ojncwj21dq09a0wn

 

其中收入最高的三个行业标记为了红色,分别为金融,IT和科研。

原数据可以在这里找到:
http://www.stats.gov.cn/tjsj/ndsj/2014/indexch.htm

点击左侧的“四、就业和工资”然后点击第“4-15”项,里面可以下载Excel。

或者也可以直接通过这个链接下载Excel:
http://www.stats.gov.cn/tjsj/ndsj/2014/zk/html/Z0415C.xls

那接下来就按图索骥,考量这三个行业中女性的状况。

(为什么只有三个?笔者精力有限,只求管窥,不求完全覆盖)

金融

搜寻良久,实在是找不到国内的资料,只好拿些英文的资料作为旁证了。

以下是来自美国的公平就业机会委员会(Equal Employment Opportunity Commission,缩写为EEOC)2006年发布的一份报告中关于女性金融从业者比例的图表:

8b1ece2agw1eqtfg16y00j210q0gg7ez

从最后一行的汇总信息可以看出,经理级别的职位,女性占18%左右。

专业从业者中,女性约为26%。

技术与销售类的职位则只有个位数的百分点。

但到了书记员,抄写员(Clerical,表中最后一列)这一类的职位,却有43%是女性。

由此不难观察到,在美国,金融这个高薪行业中女性在做着勤务工作,升到经理职位的甚少。

这份报告的出处:
http://www.eeoc.gov/eeoc/statistics/reports/finance/finance.pdf

公平就业机会委员会的wiki页面:http://zh.wikipedia.org/wiki/公平就业机会委员会

而另外一份来自于英国平等与人权委员会(Equality and Human Rights Commission,EHRC)2009年春季发布的报告则有些不同:

8b1ece2agw1eqtfj8tpjsj214010ahcb

从这张男女性别比例的图表可以看出,英国的金融行业男女从业人数基本一比一,差距不大。
从最后一行的汇总数据来看,女性还比男性多一个百分点。

而下面这张出自同一报告的关于收入差距的图表,则显露了另外的信息:

8b1ece2agw1eqtfg31dloj218c14qe6v

英国金融行业中,全职工作的男性年收入比全职工作的女性多55%。

而在全社会所有行业中,这个数字也有28%。

可见在英国女性虽然以同等的人数参与进了金融行业,但是却没有拿到哪怕是接近同等的薪水。

这份报告的出处:
http://www.equalityhumanrights.com/sites/default/files/documents/download__finance_gender_analyis_research.pdf

平等与人权委员会的wiki页面:http://en.wikipedia.org/wiki/Equality_and_Human_Rights_Commission

IT

接下来开始看三大高收入行业中的第二名:IT行业中女性的状况。

我找到了一份来自美国的非营利机构:National Center for Women & Information Technology (NCWIT)在2009年发布的报告。

(没找到这个机构确切的中文翻译,就保留原文吧)

报告中有一张女性IT从业人员比例随年份变化的趋势图

8b1ece2agw1eqszx7ctf5j20vc0jujte

容易看出,从上个世纪八十年代中期到九十年代初期,女性IT从业者比例在攀升,从30%增长到37%左右。

在此之后则一路下降,到2008年已经减少到了25%左右。

出自同一报告的还有另外一张男女收入差距随工作经验变化的趋势图

8b1ece2agw1eqszx63er1j20vk0h8jto

可以看出,入行初期男女收入没太大区别,但从第三年开始,逐渐拉开差距,由3%增加到12%。

好了,又是一个高薪行业。女性只占其中的四分之一,而且收入还比男性少。

报告出处:http://www.ncwit.org/sites/default/files/legacy/pdf/NCWIT_TheFacts_rev2010.pdf

NCWIT的wiki页面:http://en.wikipedia.org/wiki/National_Center_for_Women_%26_Information_Technology

科研

高薪行业之三,科研。

找到了两份来自欧盟的报告。

第一份报告中有一张科研行业中女性从业者比例的图表,数据采集自1999年:

8b1ece2agw1eqtgj4x3wdj20w80pcwhe

不难看出,其中希腊和葡萄牙的女性科研工作人员较多,占有41%和43%。

德国和匈牙利则很低,女性只有14%到19%。

其他八个国家大致是落在26%到33%这个区间。

第二份报告发布于2012年,其中有一张男女收入差距的图表:

8b1ece2agw1eqtgj4s92yj20ty0t6wl8

该图表数据统计于2002年和2006年,从中不难看出,女性在科研行业的各个分支中收入比男性低20%到40%。

由此可见,在欧洲,科研行业作为一个高薪行业,其中女性从业人员较少。
即便进入这个行业的女性,其收入也要较男性低。

第一份报告出处:https://ec.europa.eu/research/swafs/pdf/pub_gender_equality/wir_final.pdf

第二份报告出处:http://ec.europa.eu/research/science-society/document_library/pdf_06/meta-analysis-of-gender-and-science-research-synthesis-report.pdf

发布报告的欧盟网站:http://ec.europa.eu/index_en.htm

小结

以上观察了三个薪水最高的行业:金融,IT和科研,这三个行业中都呈现出了女性从业人员少于男性,且收入低于男性的态势。

如果这条结论和以上干巴巴的数据无法让您获得感性的认知的话,那我们再结合其他数据做个分析。

以下是来源于非营利组织National Association of Colleges and Employers (NACE)的一份报告中关于平均年工资涨幅的数据:

8b1ece2agw1eqtzeznwmwj21020eqwgt

可以从最后一行看出,平均工资涨幅是每年7.5%。

这意味着什么呢?

[1] pry(main)> Math.log(1.55,1.075)
=> 6.059885534213904
[2] pry(main)> Math.log(1.12,1.075)
=> 1.5670305391527257
[3] pry(main)> Math.log(1.20,1.075)
=> 2.5210161634544224
[4] pry(main)> Math.log(1.40,1.075)
=> 4.652504958776575

如果您不是IT行业的看不懂上面的代码没关系,我来解释一下。

这意味着,如果您是一名金融行业的女性从业者,您旁边座位上是一名和您同时进公司的男同事。
你们的关系很好,他甚至都不介意让您看他的工资单。这给在公司属于珍稀物种的您带来了不少宽慰。
但是经过分析自己历年的工资涨幅,您会发现如果您想要和他赚到一样多的钱的话,您还要再工作六年才行。

而这个数字在IT行业是一年半

在科研行业是两年半四年半

以上引用报告出处:https://www.naceweb.org/uploadedFiles/Content/static-assets/downloads/executive-summary/2014-september-salary-survey-executive-summary.pdf

NACE的wiki页面:http://en.wikipedia.org/wiki/National_Association_of_Colleges_and_Employers

然后呢?

以上仅仅是通过交叉引证来描述了职业女性的状况。是属于实证性的表述(positive statement)。

而关于职业女性应该处于何种状况,那是属于规范性的表述(normative statement),本文就不涉及了。

女性在这些高薪行业中人数少于男性,这是好事吗?这是坏事吗?

女性在这些高薪行业中收入低于男性,应该如何评价这件事呢?

金融,IT和科研,听起来都是理工宅男的专长啊,女的少不是属于正常现象吗?

女性的收入低于男性,那有可能是她们干活不给力啊,那收入低就是应该的吧?

所有这些问题,都属于价值判断。通过上面引用的数据,以及常识的积累,我对这些问题会有确定性的判断。
想来你也能猜到我的判断是什么。但是我不把它说出来,留待读者自己得出结论

最后

如果您觉得这篇博客写的还可以,请用手机支付宝扫描下面的二维码:

我会把收到的巨款用来置装,美容,健身。

然后穿的花枝招展,抹的五彩绚烂,露出两条人鱼线。

站在女程序员们旁边,给她们端茶倒水擦汗。

并且忘掉我也可以是一个独立的个体,也可以通过某种其他的方式体现自我价值。

成为一名雄性鼓励师,从此人生走上巅峰。

最后的后面

最后的后面怎么还有呢?因为标题已经啰嗦了,索性结尾也啰嗦一下。

说是不严谨的考据,但是还是用了十几个番茄钟,五六次git commit,三四次审校。

8b1ece2agw1eqtkcps0zaj21g60zejya

8b1ece2agw1eqtkec0012j21fq0ku7a1

七易其稿也不过是如此的两倍嘛。

不过从此以后,我要与这样的辛劳说再见了。我要成为一个靠性别,靠脸,靠身材吃饭的男人。

所以,你懂的,趁我还能靠智识谋生,扫码吧。

别跑,说的就是你,别骗我,我知道你余额宝收益好几十块钱一天呢。

难道你就不想为一位志存高远的未来雄性鼓励师提供一些帮助吗?

(胆敢说我最终还是免不了被周树人附体的善款要x2)

现在,请回到页面的最上端,再看一遍那两张图片,请问您现在看到的东西和读本文之前还一样吗?

原文链接:http://cuipengfei.me/blog/2015/04/04/women-in-finance-it-and-r-and-d/

Share