安全最佳实践

如果你打算开发一个插件或者为Matomo(以前的Piwik) Core做出贡献代码必须是安全的

本指南包含对抗某些漏洞的方法列表。在开发插件或贡献时,请遵循所有这些原则。

防止XSS

XSS恶意脚本(如JavaScript)注入用户界面。它允许攻击者获得应用程序的控制权或窃取信息。

攻击者可以通过以下方式实现:

  • 在数据中存储恶意脚本(如Matomo的网站名称)
  • 传递恶意脚本作为HTTP请求参数/数据

获取请求参数常见的::getRequestVar ()

在PHP代码中,如果需要访问变量$ _GET$ _POST总是使用常见的::getRequestVar ()

getRequestVar ()将清除请求变量。如果攻击者传递一个包含脚本> <…> < /脚本,它将被消毒& lt; script>……& lt; / script>.这将有助于避免意外地在HTML输出中嵌入未转义的文本。

对于您知道可能包含特殊字符的文本,或者如果您需要以不需要XML/HTML处理的格式(如JSON)输出文本,请调用Piwik: unsanitizeInputValues ()解除消毒。

注意:可以使用。清除不在请求参数中的文本Piwik: sanitizeInputValues ()

使用正确的枝条逃逸策略

使用是很重要的正确的逃生策略这取决于打印值的位置。例如,当在HTML属性中打印“title”或“label”等值时,我们需要使用| e(“html_attr”)逃避策略。其他逃避策略包括jscssurl而且超文本标记语言(这是默认策略)。

使用|生在Twig模板中很少使用

当你写嫩枝模板,尽量避免使用|生尽可能进行筛选。作为一种替代方法,将希望重用的HTML放在单独的模板和中{% include %}它。

如果你使用|生,确保您插入的内容已正确转义。

如果你必须使用|生过滤器,您可能要考虑使用| rawSafeDecoded过滤器,可能更安全。

使用时要小心jQuery.html ()

在JavaScript中,使用美元. html方法将HTML插入到DOM中。确保您插入的字符串来自Matomo并且已经转义。

如果您知道您插入的文本不应该是HTML,那么不要使用$ . html (),而是使用美元。text ()$ .val ().例如:

var ajaxData = getDataFromAjax();$ (' # someLabel ')。text (ajaxData.labelToUse);

要转义JavaScript中的字符串,可以使用helper方法piwikHelper.escape例如:

var safeString = piwikHelper.escape(userInputUnsafeString);$ (" # someLabel”)。text(safeString);

使用限制性的内容安全策略标头

内容安全策略在Matomo中默认设置(从Matomo 4.6.0开始),插件可以根据需要使用$ this - > securityPolicy方法,例如:

$ this - > securityPolicy - > addPolicy(‘image-src’,‘自我’);

或者通过创建依赖项注入插件/编写MyPlugin / config / config . php像这样将更改应用到每个UI请求,而不仅仅是特定的请求:

返回array(\Piwik\View\SecurityPolicy::class => DI\ decoration (function ($previous) {/** @var \Piwik\View\SecurityPolicy $previous */ if (!\Piwik\SettingsPiwik::isMatomoInstalled()){返回$previous;} $previous->addPolicy('default-src', 'my-cdn.example.com');返回前一美元;}));

考虑使用默认值,或者在可能的情况下使用更严格的CSP,以防止某些XSS攻击。

另请参阅

MDN上的XSS

阻止CSRF

CSRF攻击是指攻击者让Matomo用户不情愿地执行某个操作。为了达到这个目的,攻击者向用户发送一个链接。例如,该链接可以指向一个Matomo控制器方法,该方法可以更改用户的密码,或者删除一个站点。

可以使用以下技术防止这种攻击:

检查token_auth

在你创建的每一个改变Matomo设置的控制器方法中,改变用户的设置或执行一些其他管理级别的函数,调用控制器:checkTokenInUrl ()方法。例如:

//方法在控制器公共函数doSomeAdminStuff() {$this->checkTokenInUrl();/ /……}

在执行某些管理级别函数的每个API方法中,请确保通过调用某个方法来检查适当的用户权限Piwik::检查…方法。例如:

//方法在API类公共函数changeSettingsForUser($userLogin) {Piwik::checkUserHasSuperUserAccessOrIsTheUser($userLogin);}

token_auth在浏览器中

你的JavaScript应该发送token_auth到需要它的控制器和API方法,但是你应该确保token_auth永远不会出现在URL中.这样,它将永远不会被浏览器保存或缓存。

为了保持token_auth在浏览器缓存中,你可以使用POST请求。

另请参阅

MDN上的CSRF

防止SQL注入

SQL注入是通过注入恶意SQL语句来操纵应用程序的SQL查询。攻击者可以通过应用程序的输入注入恶意SQL:表单字段、请求参数、…

例如,如果一个应用程序构建了这样一个SQL查询:

$sql = 'SELECT * from mytable where id = '$ _GET [' id '];

攻击者可以通过“1或1”idURL参数。这将导致执行以下查询:SELECT * from mytable where id = 1 OR 1,输出的每一行mytable

SQL注入可以通过做一件事来防止:

使用SQL准备语句

在编写SQL语句时,使用SQL准备语句,而不是直接在语句中插入变量。SQL准备语句意味着在SQL查询中使用占位符。

换句话说,不要这样做

$idSite = Common::getRequestVar('idSite');//不要这样做!!$sql = "SELECT * FROM "。Common::prefixTable('site')。"WHERE idsite = "。idSite美元;数据库::查询($sql);

相反,这样做

$idSite = Common::getRequestVar('idSite');$sql = "SELECT * FROM "。Common::prefixTable('site')。"WHERE idsite = ?";$rows = Db::query($sql,数组($idSite));

防止远程文件包含

远程文件包含包含和执行不属于web应用程序的源代码。它发生在PHP中包括需要使用用户确定路径的语句。

在Matomo中,防止远程文件包含攻击的最佳方法是永远不要需要/包括使用用户数据的文件。相反,把逻辑放到可以由Matomo的自动加载器加载的类中并根据从用户获得的数据实例化/使用不同的类。换句话说,不要这样做

$clientToUse = Common::getRequestVar('seoClient');//不要这样做!!require_once PIWIK_INCLUDE。“编写MyPlugin /客户/ /插件/”。clientToUse美元。“。php”;$client = new $ clienttuse ();/ /……使用$client…

相反,这样做

$clientToUse = Common::getRequestVar('seoClient');if ($clientToUse == 'mySeoProvider') {$client =新客户\ mySeoProvider ();} else if ($clientToUse == 'myOtherSeoProvider') {$client = new Clients\ myOtherSeoProvider ();} else{抛出新的异常("无效的SEO提供者客户端:$ clienttuse !");} //…使用$client…

其他编码指引

这里有一些其他的编码指南,将有助于使您的代码更安全:

  • PHP文件应该以<?php永不关闭的标签。

  • 使用. php扩展所有的PHP脚本。

  • 避免使用下列函数之一执行php代码:eval执行passthru系统popenpreg_replace(“e”修饰符)。

  • 确保直接访问您的文件不会执行任何可能影响您的Matomo安装的代码。

  • 确保您的代码不依赖于register_globals设置为.注:PHP5套register_globals默认情况下。

  • 用于定时攻击安全的相等比较常见的::hashEquals ()方法

  • 如果你的插件有管理功能(只有管理员或超级用户可以使用的功能),那么你的插件的控制器必须扩展Piwik \ \ ControllerAdmin插件

检查表

绝不低于一个完整的清单。你总是会被要求想出任何其他我们不希望它被使用的情况。这只是一个最常见的检查列表。

  • 授权检查:任何控制器动作或api方法都有访问/权限检查
  • CSRF检查:任何更改数据的表单、操作或api都有CSRF nonce或令牌检查
  • SQL注入检查:数据库参数使用绑定参数或将值转换为int
  • XSS检查:用户输入被转义(在JavaScript中也是如此)参见本指南中的XSS部分。确保正确的逃生策略使用
  • 定时攻击检查:用于敏感的相等比较常见的::hashEquals使用
  • 数据的公开:没有敏感数据被暴露(任何标记或密码,例如在HTML中作为系统检查或日志的一部分)
  • 安全的数据存储:密码或类似数据(如sessionId)采用安全散列存储
  • 蛮力攻击:如果有任何令牌或密码,如身份验证,那么我们使用我们的暴力预防功能
  • 外部链接有一个rel = " noreferrer noopener”(尽管新版本的浏览器会自动添加)。的noopener是出于安全原因。的noreferrer出于隐私考虑。看到rel = noreferrer而且rel = noopener
  • 发送电子邮件通知用于与登录凭证、令牌、2FA等相关的关键操作,理想情况下也用于任何其他关键配置更改,如蛮力更改等。
  • 不安全的方法:注意的方法:
    • 不安全的反序列化:非系列化用户输入不安全。考虑使用常见的::safe_unserialize或者可能用于用户输入JSON而不是
    • 函数不安全的时候,例如一个协议phar: / /能传递给它吗
    • Require |include(_once)不应该使用任何用户输入,除非它是白名单
    • 也参见egphpdangerousfuncs.md
  • 想想其他方法,如RCE等
  • 密码确认用于与登录凭证、令牌、2FA等相关的关键操作,以及其他关键/敏感更改,如安装/激活插件等。

了解更多

Baidu