翻译进度
29
分块数量
11
参与人数

2019 PHP 安全指南

这是一篇协同翻译的文章,你可以点击『我来翻译』按钮来参与翻译。

PHP

2019 年, 大多数的科技工作者—尤其是 Web 开发者—必须摈弃掉关于开发安全 PHP 应用的老一套. 这对那些不相信能够开发出安全的 PHP 应用的人来说尤其重要.

这篇指南应该作为 PHP: The Right Way 这本电子书强调安全部分的补充, 而不是作为代码风格一样的普通主题.

yuesir 翻译于 1个月前

PHP 版本

长话短说::除非你没有办法, 2018年你在最好使用 PHP 7.2 , 同时在2019年早些时候计划切换到7.3。

PHP 7.2 已经于2017年11月30号发布.

在撰写本文时,只有PHP 7.1和7.2会得到了PHP语言开发人员的积极支持,而PHP 5.6和7.0只会在大约一年的时间内获得安全补丁。

虽然一些操作系统为不受支持的PHP版本提供长期支持,但是这种做法普遍被认为是有害的。特别在于,他们会在不升级版本号的情况下提供安全补丁,这个坏习惯会使得仅通过PHP版本来判断系统的安全性变得非常困难。

综上,无论其他供应商做出什么样的承诺,只要你能够做到,都应该在任何时间内只运行获得积极支持的PHP版本。这样,即使使用了一段时间的安全版本,持续不断的升级工作也会让你的生活免于不愉快的意外。

乳娃娃 翻译于 1个月前

依赖管理

简而言之:使用 Composer .

Composer 是对于PHP生态系统最先进的依赖管理方案, 我们强烈推荐的 PHP: The Right Way 里有专门一整节用于如何开始使用 Composer .

如果你不使用 Composer 来管理你的依赖项, 你最终会 (希望延迟但可能事情很快发生) 出现这样一种情况, 你所依赖的库变得过时,旧版本的漏洞被黑客利用.

重点: 始终记得在开发软件时更新依赖项 . 幸运的是, 这是一条命令:

composer update

如果你正在做一些特别需要使用PHP扩展(用C语言编写)的东西, 你就不能用 Composer 安装它们. 您还需要 PECL.

qf-Z 翻译于 1个月前

推荐的包

无论您正在构建什么,您几乎肯定会从这些依赖项中获益。这是大多数PHP开发人员推荐的(比如:PHPUnit、PHP-CS-fixer)。

roave/security-advisories

Roave的安全报告 使用了名叫Friends of PHP 的包来保证的项目不会依赖任何已知的非健壮的包。

composer require roave/security-advisories:dev-master    

或者,你可以 上传你的 composer.lock 文件到Sensio Labs 作为常规自动漏洞评估工作的一部分,它会把所有使用的过期的包告知你。

乳娃娃 翻译于 1个月前

vimeo/psalm

Psalm是一个静态分析工具,可以帮助识别你代码中的bug。虽然还有其他很好的静态分析工具(例如: Phan and PHPStan ,它们都很好),如果您发现自己需要支持php 5,没问题,psalm是支持php 5.4+的。

Psalm是很容易上手的:

# 目前还没有Version 1 ,但是让我们拭目以待:
composer require --dev vimeo/psalm:^0

# 仅需这样操作:
vendor/bin/psalm --init

# 一如惯例的操作:
vendor/bin/psalm

如果你是第一次在现有的代码库上运行,可能会看到很多红色提示。这是正常的,除非你创造了一个如同Wordpress一样强大的应用程序,否则不太可能使全部测试通过以满足符合Herculean的要求。

无论您使用哪种静态分析工具,我们建议您将运用到持续集成工作流(如果适用),以便在每次代码更改后运行它。

zhangsen 翻译于 1个月前

HTTPS和浏览器安全

简而言之: HTTPS, which should be tested, and security headers.

在2018年,通过不安全的HTTP访问网站将不再被接受。幸运的是,得益于ACME协议和 Let's Encrypt certificate authority的存在,我们可以免费获取TLS证书并自动更新它们。

将Acme集成到Web服务器中简直就是小菜一碟。

你也许会想,“好吧,我有一个TLS证书。现在,我必须花几个小时来处理配置,然后才能保证它的安全和快速。”

Nope! Mozilla支持. 您可以使用配置生成器根据预期的访问群体构建推荐的密码套件 。

HTTPS (HTTP over TLS) 是绝对不可协商如果您希望您的网站是安全的。使用HTTPS可以立即消除对用户的几类攻击(中间建注入、窃听、重复攻击和多种形式的会话操作,否则将允许用户模拟)。

zhangsen 翻译于 1个月前

安全Headers

虽然将HTTPS连接到服务器上确实为用户增加了安全性和性能优势,但你可以通过利用其他浏览器安全功能更进一步的扩大这些优势。其中大多数都涉及在内容里发送HTTP响应头。

  • Content-Security-Policy

    • 你需要这个header,因为它可以对浏览器允许加载的内部和外部资源进行精度控制,从而为跨站点脚本漏洞提供强大的防御层。
    • 请参阅CSP-Builder,以便快速轻松地部署/管理内容安全策略。
    • 要进行更深入的分析,Scott Helme的Content-Security-Policy标题简介是一个很好的起点。
  • Expect-CT

    • 你需要这个header,因为它通过强制将不良居心的人的证书的证据发布到可公开验证的数据结构,从而为恶意/受损的证书颁发机构添加了一层保护。 了解更多关于“Expect-CT”的信息
    • 首先将这个header设置为enforce,max-age = 30,并增加max-age,如此操作让服务更稳定。
  • Referrer-Policy

    • 你需要这个header,因为它允许您控制是否将有关用户行为的信息泄露给第三方。
    • 再次深入了解 Scott Helme 深入探讨了 Referrer-Policy headers
    • 将header设置为“same-origin”或“no-referrer”,除非您有理由允许更宽松的设置。
  • Strict-Transport-Security
    • 你需要这个header,因为它告诉浏览器通过HTTPS强制所有将来的请求到同一个来源而不是不安全的HTTP。
    • 首次部署时将其设置为“max-age = 30”,然后当您确信没有任何内容会中断时,将此值增加到某个较大的值(例如“31536000”)。
  • X-Content-Type-Options
    • 你需要这个header,因为MIME类型混淆可能导致不可预测的结果,包括允许XSS漏洞的奇怪边缘情况。最好伴随标准的Content-Type 标题。
    • 设置为nosniff,除非您需要默认行为(例如,用于文件下载)。
  • X-Frame-Options
    • 你需要这个header,因为它可以防止点击劫持
    • 设置为DENY(或SAMEORIGIN,但仅当你使用<frame>元素时)
    • X-XSS-Protection
           - 你需要这个header,因为它启用了默认情况下未启用的某些浏览器Anti-XSS功能。
           - 设为1; mode=block

同样,如果你使用PHP的内置会话管理功能(推荐使用),你可能想要调用session_start(),如下所示:

session_start([
    'cookie_httponly' => true,
    'cookie_secure' => true
]);

这会强制你的应用在发送会话标识符cookie时使用仅HTTP和安全标记,阻止成功的XSS攻击窃取用户的cookie并强制它们分别仅通过HTTPS发送。我们之前已经在2015年的博文中介绍了安全PHP会话

zhangsen 翻译于 1个月前

子资源一致性攻击(Subresource Integrity)

在将来的某个时候,你可能会使用CDN将常用的Javascript / CSS框架和库放到一个集中的地方。

负责安全的工程师对这种操作表示有很明显的安全隐患:那就是,许多网站使用CDN来提供内容,那么攻击CDN并替换内容注入这些代码到成千上万数千的网站。

输入subresource integrity.

Subresource integrity (SRI)允许你固定你希望CDN提供的文件内容的哈希值。当前实现的SRI仅允许使用安全加密散列函数,这意味着攻击者生成与原始文件产生相同散列的相同资源的恶意版本是不可行的。

真实的案例: Bootstrap v4-alpha在他们的CDN示例片段中使用SRI.

<link
    rel="stylesheet"
    href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"
    integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ"
    crossorigin="anonymous"
/>
<script
    src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"
    integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn"
    crossorigin="anonymous"
></script>
zhangsen 翻译于 1个月前

文档关联

Web开发人员经常在超链接上设置target 属性(例如:target="_blank")实现在新窗口中打开链接。但是,如果您没有传递' rel="noopener"标记,则可能允许目标页面控制原始页面

不要这样做

<a href="http://example.com" target="_blank">Click here</a>

让example.com可以控制当前的网页。

替换成这样

<a href="https://example.com" target="_blank" rel="noopener noreferrer">Click here</a>

这将在一个新窗口中打开example.com,但不会将当前窗口的控制权交给可能怀有恶意的第三方。

延伸阅读

乳娃娃 翻译于 4周前

开发安全的PHP软件

如果应用程序安全性是一个新主题,请从应用安全性详解开始.

许多安全领域的专家都会向开发人员提供诸如 OWASP Top 10 之类的资源.

但是,大多数常见漏洞可以归类为同一类的安全问题(代码/数据没有完全分离,逻辑不健全,操作环境不安全或加密协议缺陷)。

给新手们说明安全问题是一个很简单的,容易实现的事情,但是如何解决这些安全问题将是更长远的安全工程。

因此, 我们只推荐类前10名或前25名安全检查清单.

zhangsen 翻译于 1个月前

数据库交互

深入了解: PHP防止SQL注入

如果您自己编写SQL查询,请确保您使用的是预备表达式,并且将网络或文件系统提供的任何信息都作为参数传递,而不是拼接查询字符串。此外,确保你没有使用模拟的预备表达式.

为达到最佳效果, 使用 EasyDB.

*不要这样做:

/* 不安全代码: */
$query = $pdo->query("SELECT * FROM users WHERE username = '" . $_GET['username'] . "'");

替换成这样:

/* 防止SQL注入: */
$results = $easydb->row("SELECT * FROM users WHERE username = ?", $_GET['username']);

还有其他一些数据库抽象层提供了同等的安全性(EasyDB实际上在底层使用PDO,但是为了防止安全隐患,它特意禁用准备好的语句模拟,而使用实际的准备好的语句)。只要用户输入不能影响查询的结构,您就是安全的。(这包括存储过程。)

乳娃娃 翻译于 4周前

文件上传

深入了解: 如何安全地允许用户上传文件

接受文件上传是一个冒险的主张,但只要采取一些基本的预防措施,就可以安全地执行此操作。也就是说,应当阻止意外地允许执行或解释上传文件的方式直接访问上传文件.

上传的文件应该是只读的或读写的,永远不能被执行.

如果你的站点根目录是 /var/www/example.com, 你不应该存贮上传文件在 /var/www/example.com/uploaded_files.

相反,你应该将上传文件存储在无法通过浏览器直接访问的单独目录中(例如, /var/www/example.com-uploaded/),以免它们意外地作为服务器端脚本执行,打开远程代码执行的漏洞。

更简单的解决方案是将站点根目录向下移动一级 (例如,移动到:/var/www/example.com/public)。

文件上传的另一个问题是安全地 下载文件 。

  • 直接访问SVG图像将在用户的浏览器中执行JavaScript代码。 这是真的,尽管SVG图像的MIME类型是以image\为前缀.
  • MIME类型嗅探可能导致类型混淆攻击。详情见前文安全HeadersX-Content-Type-Options响应头的介绍。
  • 如果你不采纳前面关于如何安全存贮上传文件的建议,攻击者可能设法上传.php或者.phtml的文件, 通过直接在浏览器中访问上传文件执行任意代码, 从而获得对服务器的完全控制。请安全地玩你的服务器。
tusi 翻译于 3周前
leo 审阅

跨站脚本 ( XSS )

深入阅读: 关于防止 PHP 中的跨站点脚本漏洞,您需要了解的所有内容

在理想的情况下, XSS 和 SQL 注入一样容易预防。我们有简单易用的 API ,用于将查询语句和数据进行分离。

不幸的是,大多数 web 开发人员的实际工作会涉及到将生成的一长串 HTML 文本并通过 HTTP 协议响应。这不是 PHP 独有的功能,它只是 web 开发的基本工作方式。

减少 XSS 漏洞并不是那么难做。但是,浏览器安全 的所有内容是至关重要。简而言之:

  1. 经常对输出转义,而不是对输入转义。 如果你在数据库中存储已过滤的数据,然后在一些地方发现 SQL 注入漏洞,那么攻击者可以通过恶意代码篡改可信的数据记录,从而完全绕过 XSS 保护。
  2. 如果你的框架中有一个提供自动上下文过滤的模板引擎,那可以使用它。它将会给你的框架的功能的安全性提供保障。
  3. echo htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8'); 是一种安全有效的方式,它可以阻止对 UTF-8 编码的 web 页面的 XSS 攻击,但它不允许任何 HTML 标签内容输出。
  4. 如果你的需求是允许你使用 Markdown 替代 HTML,不要使用 HTML
  5. 如果你需要允许一些 HTML 并且没有使用模板引擎(请参见#1),那么就使用 HTML 净化器。 HTML 净化器不适用于将内容转义成 HTML 标签属性的场景。
  6. 对于用户提供的 URLs ,你应该只允许使用 http:https: 协议模式;不要用 javascript: 。此外,使用 URL 编码方式编码用户的所有输入。
suhanyujie 翻译于 5天前

Cross-Site Request Forgery (CSRF)

Cross-Site Request Forgery is a sort of confused deputy attack, whereby you can trick a user's browser into performing a malicious HTTP request on the attacker's behalf, with the user's elevated privileges.

This is trivially solvable in the general case with two easy steps:

  1. Use HTTPS. This is a prerequisite. Without HTTPS, any defense you could hope to mount becomes brittle. However, HTTPS alone does not prevent CSRF.
  2. Add basic challenge-response authentication.
    • Add a hidden form attribute to every form.
    • Populate with a cryptographically secure random value (called a token).
    • Verify that the hidden form attribute was provided, and matches what you expect.

We wrote a library called Anti-CSRF that goes a step further:

  • You can make every token usable only once, to prevent replay attacks.
    • Multiple tokens are stored in the backend.
    • Tokens rotate once their capacity has been reached, oldest first.
  • Every token can be tied to a particular URI.
    • If one token leaks, it cannot be used in a different context.
  • Tokens can be optionally bound to a particular IP address.
  • Since v2.1, tokens can be reusable (i.e. for AJAX calls).

If you're not using a framework that takes care of CSRF vulnerabilities for you, give Anti-CSRF a spin.

In the near future, SameSite cookies will allow us to kill CSRF attacks with much lower complexity.

有 1 个译文正在审阅中...

XML Attacks (XXE, XPath Injection)

There are two major vulnerabilities that rear their ugly heads in applications that do a lot of XML processing:

  1. XML External Entities (XXE)
  2. XPath Injection

XXE attacks can be used as a launchpad for local/remote file inclusion exploits, among other things.

An earlier version of Google Docs famously fell to XXE, but they're largely unheard of outside of business applications that do a lot of heavy XML work.

The main mitigation against XXE attacks is as follows:

libxml_disable_entity_loader(true);

XPath Injection is very similar to SQL Injection, except for XML documents.

Fortunately, situations where you pass user input into an XPath query are quite rare in the PHP ecosystem.

Unfortunately, this also means that the best mitigation available (pre-compiled and parametrized XPath queries) is not present in the PHP ecosystem.

Your best bet is to use a whitelist of allowed characters on any data that touches the XPath query.

<?php
declare(strict_types=1);

class SafeXPathEscaper
{
    /**
     * @param string $input
     * @return string
     */
    public static function allowAlphaNumeric(string $input): string
    {
        return \preg_replace('#[^A-Za-z0-9]#', '', $input);
    }

    /**
     * @param string $input
     * @return string
     */
    public static function allowNumeric(string $input): string
    {
        return \preg_replace('#[^0-9]#', '', $input);
    }
}

// Usage:
$selected = $xml->xpath(
    "/user/username/" . SafeXPathEscaper::allowAlphaNumeric(
        $_GET['username']
    )
);

Whitelists are safer than blacklists.

Deserialization and PHP Object Injection

In-depth: Securely Implementing (De)Serialization in PHP

If you pass untrusted data to unserialize(), you're generally asking for one of two outcomes:

  1. PHP Object Injection, which can be used to launch a POP chain and trigger other vulnerabilities from misused objects.
  2. Memory corruption in the PHP interpreter itself.

Most developers prefer to use JSON serialization instead, which is a marked improvement to their software's security posture, but keep in mind that json_decode() is vulnerable to hash-collision denial-of-service (Hash-DoS) attacks. Unfortunately, the total fix to PHP's Hash-DOS woes has yet to be resolved.

Migrating from djb33 to Siphash with the highest bit of the hash output set to 1 for string input and set to 0 for integer inputs, with a per-request key provided by a CSPRNG, would totally solve these attacks.

Unfortunately, the PHP team isn't quite ready to let go of the performance gains they've been racking up with the PHP 7 series, so it's a hard sell to convince them to drop djb33 (which is very fast, but not secure) in favor of SipHash (which is also fast, but not as fast as djb33, but much more secure). A significant performance hit could even discourage adoption of future versions which would in turn be bad for security.

The best thing to do, therefore, is:

  • Use JSON, because it's safer than unserialize().
  • Where you can, ensure inputs are authenticated before deserializing them.
    • For data you provide to the end user, use sodium_crypto_auth() andsodium_crypto_auth_verify() with a secret key known only to the webserver.
    • For data provided by other third parties, arrange for them to sign their JSON messages with sodium_crypto_sign() and then verify them with sodium_crypto_sign_open() and the third party's public key.
      • You can also used the detached signing API if you need to hex- or base64- encode the signatures for transport.
  • Where you cannot authenticate JSON strings, employ strict rate-limiting and block IP addresses to mitigate against repeat offenders.

密码哈希

深入了解: 在2016年如何安全存储用户密码

密码安全的存储曾经是一个备受争议的话题,但现在实现起来相当简单,尤其是在PHP中:

$hash = \password_hash($password, PASSWORD_DEFAULT);

if (\password_verify($password, $hash)) {
    // 已验证
    if (\password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        // 刷新,更新数据库
    }
}

您甚至不需要知道后台使用的是什么算法,因为如果您使用的是最新版本的PHP,那么您也将使用最新的最新版本,并且一旦有新的默认算法可用,用户的密码将自动升级。

不管你做什么, 在 WordPress 不要这样做.
如果你对此感到好奇:从php 5.5到7.2,默认算法是bcrypt。将来,它可能会切换到Argon2,即[密码散列类型]https://password-hashing.net/).

如果您以前没有在API中使用加密,同时需要迁移旧散列,请使用这种方法. 很多公司在这方面做了错误的操作,其中典型就的公司有,雅虎。, Yahoo. 最近,错误地实现旧哈希升级似乎已经导致了苹果最近的 iamroot bug caused Apple's recent iamroot bug.

zhangsen 翻译于 1个月前

General-Purpose Cryptography

This is a subject we've written about at length:

Generally, you always want to use the Sodium cryptography library (libsodium) for application-layer cryptography. If you need to support versions of PHP earlier than 7.2 (as early as 5.2.4), you can use sodium_compat and basically pretend your users are on 7.2 as well.

In specific instances, you may need a different library because of rigid algorithm choices and interoperability. When in doubt, consult a cryptographer about the cipher choices and a cryptography engineer about whether or not the implementation is secure. (This is one of the services we provide.)

If you're working with ciphers/modes directly, consult this brief guide on cryptography best practices.

随机数

深入了解: 如何在PHP中安全地生成随机字符串和整数

如果您需要随机数,请使用 random_int(). 如果需要随机字节字符串,请使用 random_bytes()所以不要使用 mt_rand()rand(), 或 uniqid() .

如果你需要从一个密钥生成伪随机数, 不要用srand() 或者mt_srand(), 请查看 SeedSpring .

<?php
use ParagonIE\SeedSpring\SeedSpring;

$seed = random_bytes(16);
$rng = new SeedSpring($seed);

$data = $rng->getBytes(1024);
$int = $rng->getInt(1, 100);
zhangsen 翻译于 1个月前

服务器端 HTTPS 请求

简而言之: 确保没有禁用 TLS 证书验证。

请随意使用你熟悉且兼容 PSR-7 规范的 HTTP 客户端,大多数人喜欢使用Guzzle库。也有一些人喜欢直接使用 cURL。

无论你用哪一种, 你可以 使用 Certainty 库来确保你拥有最新的证书包,这进而允许你启用最严格的TLS证书验证设置,并保护服务器的出站HTTPS请求。

安装 Certainty 库非常简单:

composer require paragonie/certainty:^1

使用 Certainty 库也很容易:

<?php
use ParagonIE\Certainty\RemoteFetch;

$latestCACertBundle = (new RemoteFetch())->getLatestBundle();

# 使用 cURL:
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_CAINFO, $latestCACertBundle->getFilePath());

# 使用 Guzzle:
    /** @var \GuzzleHttp\Client $http */
    $repsonse = $http->get(
        'https://example.com', 
        [
            'verify' => $latestCACertBundle->getFilePath()
        ]
    );

这将保护你免受Web服务器与你集成的任何第三方API之间的中间人攻击(man-in-the-middle attacks)。

tangq 翻译于 1周前

Do We Really Need Certainty?

Certainty isn't strictly necessary to protect your systems. Its absence is not a vulnerability.

But without Certainty, open source software has to guess where the Operating System's CACert bundle lives, and if it guesses wrong, it often fails hard and causes usability problems.

Historically, this incentivized a lot of developers to just disable certificate validation so their code "just works" without realizing how vulnerable they just made their application to active attacks.

Certainty removes that incentive by making CACert bundles up-to-date and in a predictable location. Certainty also provides a lot of tooling for enterprises that wish to run their own in-house CA.

谁来禁用证书验证?

常见的内容管理系统(WordPress,Magento等)的插件/扩展开发人员可以做到! 这是我们在生态系统层面试图解决的一个巨大问题。 它不是孤立于任何特定的CMS,你会发现插件等。 因为所有这些都是不安全的。

如果您正在使用这样的CMS,请在插件中搜索CURLOPT_SSL_VERIFYPEERCURLOPT_SSL_VERIFYHOST ,您可能会发现有几个将这些值设置为FALSE

zhangsen 翻译于 1个月前

Things To Avoid

Don't use mcrypt, a cryptography library that hasn't been developed in over a decade. If you're following our PHP version recommendation, this should be an easy pitfall to avoid, since mcrypt is not provided with PHP 7.2 and newer.

Configuration-driven security advice should be mostly disregarded. If you're reading a guide to PHP security and they tell you to change a php.ini setting rather than writing better code, you're probably reading very outdated advice. Close the window and move onto something that doesn't bloviate about register_globals.

Don't use JOSE (JWT, JWS, JWE), a suite of Internet standards that codify a series of error-prone cryptographic designs that for some reason attracts a lot of evangelists in spite of the foot-bullets written into the standards.

Encrypting URL parameters is an anti-pattern that companies often employ to obfuscate metadata (e.g. how many users do we have?). It carries a high risk of implementation error while creating a false sense of security. We propose a safer alternative in the linked article.

Don't implement "I forgot my password" features unless you absolutely must. To not mince words: Password reset features are a backdoor. There are ways to implement them that are secure against a reasonable threat model, but high-risk users should be given the opportunity to opt out of it entirely.

Avoid using RSA if you can help it. Use libsodium instead. If you must use RSA, make sure you specify OAEP padding.

<?php

openssl_private_decrypt(
    $ciphertext,
    $decrypted, // Plaintext gets written to this variable upon success,
    $privateKey,
    OPENSSL_PKCS1_OAEP_PADDING // Important: DO NOT OMIT THIS!
);

If you're forced to use PKCS#1 v1.5 padding, whatever you're integrating with is almost certainly vulnerable to ROBOT, so report it to the appropriate vendor (or US-CERT) as a vulnerability allowing plaintext disclosure and signature forgery.

Specialized Use-Cases

Now that you have a grasp on the basics of building secure PHP applications in 2018 and beyond, let's examine some of the more specialized use cases.

Searchable Encryption

In-depth: Building Searchable Encrypted Databases with PHP and SQL

Searchable encrypted databases are desirable, but widely considered nontrivial to implement. The blog post linked above attempts to walk the reader through the development of our solution incremenetally, but in essence:

  1. Design your architecture so that a database compromise doesn't give attackers access to your cryptography keys.
  2. Encrypt the data under one secret key.
  3. Create multiple indices (with their own distinct secret keys), based on either HMAC or a secure KDF with a static salt (e.g. Argon2).
  4. Optional: Truncate the output of step 3, use it as a Bloom filter.
  5. Use the output of step 3 or 4 in your SELECT queries.
  6. Decrypt the results.

At any step in the process, you can make different trade-offs based on what makes sense for your use case.

Token-based Authentication without Side-Channels

In-depth: Split Tokens: Token-Based Authentication Protocols without Side-Channels

Speaking of databases (previous section), did you know that SELECT queries can theoretically be a source of timing information leaks?

Simple mitigation:

  1. Cut your authentication tokens in half.
  2. Use one half in your SELECT queries.
  3. Validate the second half in constant-time.
    • You may optionally store a hash of the second half in the database instead of the half-token itself. This makes sense for tokens that will only be used once; i.e. password reset or "remember me on this computer" tokens.

Even if you can use timing leaks to steal half the token, the remainder will require a brute force attack to succeed.

Developing Secure APIs

In-depth: Hardening Your PHP-Powered APIs with Sapient

We wrote SAPIENT, the Secure API ENgineering Toolkit, to make server-to-server authenticated messaging a no-brainer.

Sapient allows you to encrypt and/or authenticate messages, using shared-key or public-key cryptography, in addition to the security that HTTPS provides.

This allows you to authenticate API requests and responses using Ed25519 or encrypt messages to a target server that can only be decrypted by the recipient server's secret key, even if a man-in-the-middle attacker is present and armed with a rogue/compromised Certificate Authority.

Because each HTTP message body is authenticated by secure cryptography, it can be used safely in lieu of stateful token juggling protocols (e.g. OAuth). However, when it comes to cryptography, one should always be sure their implementation is studied by experts before doing anything non-standard.

All of the cryptography used by Sapient is provided by the Sodium cryptography library.

Further reading:

Paragon Initiative Enterprises already uses Sapient in many of its products (including many open source software projects), and will continue to add software projects to the portfolio of Sapient users.

Security Event Logging with Chronicle

In-depth: Chronicle Will Make You Question the Need for Blockchain Technology

Chronicle is an append-only cryptographic ledger based on a hash-chain data structure that has a lot of the properties that attract companies to "blockchain" technology, without being overkill.

Aside from the more creative use cases of an append-only cryptographic ledger, Chronicle shines brightly when integrated into an SIEM, because you can send security-critical events to a private Chronicle and they become immutable.

If your Chronicle is set to cross-sign its summary hash onto other Chronicle instances, and/or if there are other instances configured to replicate your Chronicle's contents, it becomes extremely difficult for attackers to tamper with your security event logs.

With Chronicle, you can get all the resilience that blockchains promise, without any of the rampant privacy, performance, or scalability problems.

To publish data to a local Chronicle, you can use any Sapient-compatible API, but the easiest solution is called Quill.

A Word From the Author

An astute reader may notice that we reference a lot of our own work (both blog posts and open source software), but we don't only reference our own work.

This was not accidental.

Our company has been writing security libraries and participating in efforts to improve the security of the PHP ecosystem since we were founded in early 2015.

We've covered a lot of ground, and our security engineer (whose recent pushes for more secure cryptography in the PHP core just landed in PHP 7.2) is, self-admittedly, not very good at generating hype or interest in the work he has done. It is very likely that you haven't heard of even half of the tools or libraries we've developed over the years. Sorry about that.

However, we also can't be the forerunners in every direction, so where ever possible, we opted to link to the work of industry experts whom we believe are aligned more with the public good than petty selfishness. That is why much of the section dedicated to Browser Security references the work of Scott Helme and company, who have done great work in making these new security features accessible and understandable for developers.

This guide is certainly not exhaustive. There are nearly as many ways to write insecure code as there are to write code in the first place. Security is a mindset more than it is a destination. With everything written above, and the resources that follow, we hope that this serves to equip developers the whole world over to write secure software in PHP from this day forward.

Resources

If you've followed everything on this page, and you want more, you may be interested in our curated reading list for learning application security.

If you think you've written adequately secure code and want us to critique it from a security engineer's perspective, this is actually a service we provide to our clients.

If you work for a company that is set to undergo compliance testing (PCI-DSS, ISO 27001, etc.), you may also want to hire our company to audit your source code. Our process is way more developer-friendly than other security consultancies'.

What follows is a list of resources provided by the PHP and information security communities that help make the Internet more secure in their own way.

  • PHP: The Right Way, the de-facto guide to modern PHP development, online for free.
  • Mozilla's SSL Config Generator
  • Let's Encrypt, which is the Certificate Authority doing the most to create a more secure Internet by providing TLS certificates for free.
  • Qualys SSL Labs provides a quick and easy test suite for TLS configuration. Virtually everyone uses this to troubleshoot their ciphersuites and certificate problems, for good reason: It does its job well.
  • Security Headers lets you verify how well your website fares in terms of utilizing browser security features to protect your users.
  • Report-URI is a great free resource for kickstarting initiatives to implement security headers. They give you a Report-URI, which you can pass to your users' browsers, and they will in turn complain to Report-URI if something breaks or someone finds an XSS attack vector. Report-URI aggregates these errors and allows you to better troubleshoot and triage these reports.
  • The PHP Security Advent Calendar by the team behind RIPSTech.
  • Snuffleupagus, a security-oriented PHP module (and the spiritual successor to Suhosin, which appears to be largely abandoned).
  • PHP Delusions, a website dedicated to using PHP better. Much of the tone is very opinionated, but the author's dedication to technical accuracy and clarity makes it worth a read, especially for anyone who doesn't quite grok many of PDO's features.
  • Have I Been Pwned? helps users discover if their data has been part of past data breaches.

本文章首发在 LearnKu.com 网站上。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://paragonie.com/blog/2017/12/2018-...

译文地址:https://learnku.com/php/t/27412

参与译者:11
讨论数量: 2
zhangsen

建议大家在翻译的时候,注意一下语义,不要直接copy翻译,比如:“只要用户输入不能影响查询的结构,您就是安全的”。

3周前

大佬们!
psalm安装好了在window上怎么使用呀!运行就报:“不是内部或外部命令,也不是可运行的程序“,怎么破!

5天前

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!