澳门1495

[译] 防守式编程的章程。防御性代码的方,对bug说再见。

十月 10th, 2018  |  球类运动

  • 初稿地址:The Art of Defensive
    Programming

怎开发人员不修安全代码?

  • 原稿作者:Diego
    Mariani
  • 译文出自:掘金翻译计划
  • 译者:GiggleAll
  • 校对者:tanglie1993
    , fghpdf

俺们于这边不再谈论“干净的代码”。
我们正讨论更多之东西,从纯粹的实施角度看,软件的安全性与稳定性。是的,因为一个免安全之软件几乎没因此。

为何开发人员不修安全代码? 我们不再在此讨论 “清的代码
。我们于一个彻头彻尾的角度,软件之安全性来谈谈再多的事物。是的,因为一个不安全之软件几乎是从来不因此之。让咱来探视不安全之软件意味着什么。

深受我们看不安全之软件带来的损失。

  • 欧洲航天局之 Ariane 5 Flight 501 在起飞后 40
    秒(1996年6月4日)被损坏。10
    亿美元的
    原型火箭由于机载导航软件受到的谬误而自毁。

  • 以 20 世纪 80 年代,一个治疗机中控制 Therac-25
    辐射的之代码错误,导致其给予用了量之 X 射线致使至少五叫病人死亡。

  • MIM-104 爱国者的软件错误导致其系统时钟在 100
    小时上内偏移三分之一秒,以至于无法稳定和阻止来袭导弹。伊拉克导弹袭击了沙特阿拉伯于达哈兰之一个兵马大院(
    1991 年 2 月 25 日 ),杀害了 28 名叫美国口。

欧洲航天局之Ariane 5 Flight 501每当起飞后40秒(1996年6月4日)被毁损。
10亿美元之原型火箭由于机载指导软件受到的谬误而自毁。

这些事例可以让咱们认识及编辑安全的软件,特别是在某些情况下是多重要。在旁以状态下,我们为应有知道我们软件错误会带为咱什么。

控制Therac-25放射治疗机的代码中之荒谬直接造成了在80年份,当该给用了量之X射线时,至少要五称患者身故。

防守式编程角度一

为什么自己当防守式编程在一些类型被凡一个意识这些问题的好办法?

防御不容许,因为无容许以可能出。

对防御性编程有无数定义,它还在安全性的级别和你的软件项目所用的资源级别。

防守式编程是一种防守式设计,旨在确保以飞之情形下软件的连绵功能,防守式编程实践时于用在高可用性,需要安全的地方

维基百科

自己个人觉得这种方式可当您处理一个百般的、长期的、有广大人口踏足的门类。
例如,需要大量护卫的开源项目。

为促成防守式编程方法,让我谈谈自己个人简陋的见解。

MIM-104爱国者的软件错误导致该系时钟在100钟头的内漂移三分之一,导致无法稳定与截留入射导弹。
伊拉克导弹袭击了沙特阿拉伯达哈兰一个兵马大院(1991年2月25日),造成28名叫美国人口死。

从没相信用户输入

如你总是会收下你意料之外的事物。这当是您作为防守式程序员的法门,针对用户输入,或者平常上而的网的各种东西。因为我们得预想到意想不到的,尽量做到尽量严格。断言)你的输入值是公愿意之。

澳门1495 1

The best defense is a good offense

出击就是最好好之防御

(将输入)列入白名单而不是将她坐黑名单中,例如,当证图像扩展名时,不检讨无效的花色,而是检查中的色,排除有其他的种。
在 PHP 中,也生过多的开源验证库来如果您的做事双重便于。

出击就是无比好之守护,控制而严格。

这该可以理解安全软件多么重要,特别是在某些圈子被产生差不多要。
但在旁以状态下,我们应有知道我们的软件错误将见面招致什么危害。

运数据抽象

OWASP
十杀安全漏洞

中的第一单凡是流入。这表示有人(很多口)还未曾下安全工具来查询他们之数据库。请动数据库抽象包和仓库。在
PHP 中你得应用
PDO
来保险基本的注入保护。

澳门1495 2

决不再过去轮子

您绝不框架(或微框架)?
你就是是爱好无理由的做额外的劳作。恭喜你!只要是通过完美测试、广受信赖的安澜的代码,你虽得尽管用于各种新特性(不仅是框架)的开,而休是仅仅以它们是已去好的车轮的缘故而又造轮子。你协调去轮子的唯一因是公得有未设有或者存在但切莫相符您的求(性能不优,缺少的机能等)。

那个(使用框架)我们遂它为智能代码用,它值得拥有。

守卫编程的首先征缴

甭相信开发人员

防守式编程可以和名防御性驾驶的物有关。在防御驾驶着,我们要我们周围的每个人都发生或发错误。
所以我们亟须小心别人的一言一行。这些平适用于我们的防守式编程,作为开发者,我们无应当相信任何开发者。我们啊如出一辙不应相信我们的代码。

于多人口踏足的死色被,我们好有好多不一的道来编排和社代码。
这为恐怕致乱,甚至还多之错。
这虽是胡我们归总编码风格与动代码检测器会要我们的生越来越逍遥自在。

何以我道防御性编程在少数种类的路遭到研这些问题之好方法?

写SOLID代码

这是对准一个防守式程序员困难的地方,writing code that doesn’t
suck
。这是诸多丁掌握和讨论的事务,但尚未丁真的关注或投入对的注意力和着力来实现
SOLID代码

让咱们来拘禁有的不好的事例。

绝不:未初始化的性能

<?php

class BankAccount
{
    protected $currency = null;
    public function setCurrency($currency) { ... }
    public function payTo(Account $to,$amount)
    { 
        // sorry for this silly example
        $this->transaction->process($to,$amount,$this->currency);
    }
}

// I forgot to call $bankAccount->setCurrency('GBP');
$bankAccount->payTo($joe,100);

每当这种情形下,我们要记住,为了发生付款,我们得事先调用 setCurrency

这是一个挺不好之作业,像这样的状态更改操作(发出付款)不该于点滴只步骤使用有限独(或多个)公共艺术。
我们仍可以有那么些法来付款,但是咱必须就生一个概括的国有措施,以变更状态(对象应当永远不见面处于不相同的状态)。

于这种状况下,我们得以做得重复好,将未初始化的性质封装到 Money
对象中。

<?php

class BankAccount
{
    public function payTo(Account$to,Money$money){ ... }
}

$bankAccount->payTo($joe,newMoney(100,newCurrency('GBP')));

假定她万无一失。 不用用无初始化的靶子属性

Don’t: Leaking state outside class scope.

甭:类作用域之外的暴露状态。

<?php

class Message
{
    protected $content;
    public function setContent($content)
    {
        $this->content=$content;
    }
}

class Mailer
{
    protected $message;
    public function__construct(Message$message)
    {
        $this->message=$message;
    }
    public function sendMessage(
    {
        var_dump($this->message);
    }
}

$message = new Message();
$message->setContent("bob message");
$joeMailer = new Mailer($message);

$message->setContent("joe message");
$bobMailer = new Mailer($message);

$joeMailer->sendMessage();
$bobMailer->sendMessage();

当这种情形下,消息由此引用传递,结果以当简单种情况下都是 “joe
message”
。 解决方案是于 Mailer 构造函数中克隆信对象。
但是咱相应总是尝试采取一个(不可变的)值对象错过替代一个简单的
Message mutable对象。当您得的时刻用不可变对象

<?php

class Message
{
    protected $content;
    public function __construct($content)
    {
        $this->content = $content;
    }
}

class Mailer 
{
    protected $message;
    public function __construct(Message $message)
    {
        $this->message = $message;
    }
    public function sendMessage()
    {
        var_dump($this->message);
    }
}

$joeMailer = new Mailer(new Message("bob message"));
$bobMailer = new Mailer(new Message("joe message"));

$joeMailer->sendMessage();
$bobMailer->sendMessage();

防御不可能,因为无容许也会见发生。

写测试

我们尚索要说几什么?
写单元测试将帮您遵守并之标准化,如高集,单一责任,低耦合和对的目标成
它不只帮您测试小单元,而且为会测试你的对象的布局的方法。
事实上,你晤面懂地视,为了测试你的小作用要测试多少只单元以及公待效法多少个目标,以实现100%底代码覆盖率。

防御性编程有那么些定义,它还取决于“安全性”级别及公的软件项目所需要的资源级别。

总结

冀而欢喜这篇稿子。
记住这些不过是建议,何时、何地采纳这些建议,这有赖于你。

防御性编程是同栽防御性设计,旨在确保以不足预见的状下软件之继承效力。防御性规划做法常用于需要高可用性,安全性还是稳定的地方

本人个人认为这种艺术可当你处理一个大,使用周期长的大都丁参与种。例如,对于要大量维护的开源项目。

受咱探讨有大概的基本点点,以实现防御性编程方法。

毫无相信用户输入

若你总是会接到你切莫指望的东西。那么您的章程应该当一个防御性程序,针对用户输入,或一般进入而系统用户。这就算是我们可预料到意想不到的结果。尽量做到尽量严格。断言您的输入值是您要的。

最为好之防御是攻打

列入白名单而无是私自名单,例如,当证图像扩展名时,不检查无效的品种,但检查中之花色,排除有其他的色。在PHP中,你呢出诸多之开源验证库,使你的行事再度易。

最好好的守卫是一个吓之抢攻。要三思而行。

采取抽象数据库

OWASP十非常安全漏洞中之首先个是流入。这表示有人(很多丁于那边)还并未运用安全工具来查询他们的数据库。请以数据库抽象包以及货栈。在PHP中,您可以PDO来确保基本的流入保护。

无须还发明轮子

乃无动框架(或微框架)?你欣赏开额外的劳作,没有理由,恭喜您!它不仅仅是框架,而且对于新的效果,你得十分轻地行使,经过测试,受到众多的开发人员和稳定之亲信,而未是只是为好做的物。你应该自己创造一个东西的唯一原因是你用有的非有或者在而未称你的内需(性能不理想,缺少的作用等)。

不用相信开发人员

防御性编程可以和防御性驾驶的事物有关。在看守驾驶负,我们而我们周围的每个人且发或发错误。所以我们务必小心别人的行事。同样的概念呢适用于防御性编程,开发人员不应当相信外开发人员的代码。也不该相信我们友好之代码。

在异常品种中,许多人参与,我们得来广大不同之不二法门来修和组织代码。这也说不定造成乱,甚至又多的错误。所以我们应当规范编码风格。

写入SOLID代码

当时是一个(防御)程序员的不方便有,编写代码不吸烟。这是成百上千人数清楚与讨论的政工,但未曾人的确关心或投入是的注意力和着力来实现SOLID代码。

吃咱们看有的坏之例证

未初始化的性质

class BankAccount

{

protected $currency = null;

public function setCurrency($currency) { … }

public function payTo(Account $to, $amount)

{

// sorry for this silly example

$this->transaction->process($to, $amount, $this->currency);

}

}

// I forgot to call $bankAccount->setCurrency(‘GBP’);

$bankAccount->payTo($joe, 100);

于这种情形下,我们须铭记,为了有付款,我们用调用第一个setCurrency。
这是一个不胜不好的事体,像这样的状态更改操作(发出付款)不该下有限(n)个国有艺术以少数单步骤。
我们仍然可以生出广大办法来会,但是我们得就生一个简易的集体艺术,以转状态(对象不应有处于无同等的状态)。

于这种景象下,我们举行得还好,将无初始化的性能封装到Money对象吃。

class BankAccount

{

public function payTo(Account $to, Money $money) { … }

}

$bankAccount->payTo($joe, new Money(100, new Currency(‘GBP’)));

绝不采用非初始化的靶子属性

项目范围以外的透漏状态。

class Message

{

protected $content;

public function setContent($content)

{

$this->content = $content;

}

}

class Mailer

{

protected $message;

public function __construct(Message $message)

{

$this->message = $message;

}

public function sendMessage(

{

var_dump($this->message);

}

}

$message = new Message();

$message->setContent(“bob message”);

$joeMailer = new Mailer($message);

$message->setContent(“joe message”);

$bobMailer = new Mailer($message);

$joeMailer->sendMessage();

$bobMailer->sendMessage();

于这种气象下,消息经引用传递,结果以在简单种情景下还是“joe message”。
解决方案是在Mailer构造函数中克隆信息对象。
但是我们相应总是尝试采取一个(不可变的)值对象,而无是一个略的Message
mutable对象。 尽可能使用不可变对象。

class Message

{

protected $content;

public function __construct($content)

{

$this->content = $content;

}

}

class Mailer

{

protected $message;

public function __construct(Message $message)

{

$this->message = $message;

}

public function sendMessage(

{

var_dump($this->message);

}

}

$message = new Message();

$message->setContent(“bob message”);

$joeMailer = new Mailer($message);

$message->setContent(“joe message”);

$bobMailer = new Mailer($message);

$joeMailer->sendMessage();

$bobMailer->sendMessage();

每当这种情形下,消息经引用传递,结果用以点滴栽状态下还是“joe message”。
解决方案是以Mailer构造函数中克隆音对象。
但是我们应当总是尝试利用一个(不可变的)值对象,而非是一个简便的Message
mutable对象。 尽可能使用不可变对象。

class Message

{

protected $content;

public function __construct($content)

{

$this->content = $content;

}

}

class Mailer

{

protected $message;

public function __construct(Message $message)

{

$this->message = $message;

}

public function sendMessage()

{

var_dump($this->message);

}

}

$joeMailer = new Mailer(new Message(“bob message”));

$bobMailer = new Mailer(new Message(“joe message”));

$joeMailer->sendMessage();

$bobMailer->sendMessage();

还待说些什么?
写单元测试将援助你坚持广泛的原则,如大凝聚力,单一责任,低耦合和不易的目标成。
它拉你测试工作的粗单位案例,你的对象的结构的方。
事实上,你会掌握地见到,当测试小作用时要测试多少只案例和急需效法多少个对象,以实现100%的代码覆盖率。

澳门1495 3

企你喜爱这篇文章。
记住这些仅是建议,下次你虽懂得呀时,在哪用他们。

转载请晓。

标签:, ,

Your Comments

近期评论

    功能


    网站地图xml地图