安全指南
本页面的目标是为如何安全使用 APOC 提供指导。不安全地使用 APOC 可能导致许多常见的软件漏洞,包括安全配置错误、敏感数据泄露、服务器端请求伪造 (SSRF) 以及语言注入。
我们的准则建议在安全事务中采用基于原则的方法,并分为三个部分。在第一部分,我们将首先探讨我们的总体原则。在第二部分,我们将讨论如何在执行查询之前为 APOC 创建一个安全的环境。最后,在第三部分,我们将涵盖如何在查询中安全地使用 APOC。
安全原则
本节涵盖的安全原则为安全使用 APOC 提供了指导性规则。如果遇到本页面未涵盖的安全挑战,建议用户遵循下述原则。
最小权限原则
也称为最小特权原则,最小权限原则规定,工作负载应仅被赋予其运行所需的最小权限集。APOC 提供了广泛的功能,任何特定的 APOC 安装都不太可能全部用到。建议用户仅启用严格需要的那些过程和函数。建议用户禁用所有其他过程和函数。
通过仅启用最少必需的功能,用户可以降低因运行易受攻击的过程而产生的风险,同时也支持其功能需求。
纵深防御原则
也称为冗余原则,纵深防御原则规定,即使看起来多余,用户也应在软件栈的每个层面确保安装的安全性。
APOC 建立在由数据库和操作系统暴露并控制的接口之上。通过使用纵深防御方法保护 APOC 安装,安装环境将被多层保护所包围,从而减轻任何一层保护机制失效的风险。如果安装受到 APOC、数据库以及操作系统的共同保护,那么受保护的工作负载被单个漏洞利用的可能性就会降低。
安装
本节涵盖了为 APOC 创建安全环境所需的步骤。它关注的是在编写查询之前保护 APOC。
保护 Neo4j
由于 APOC 提供的功能构建在数据库之上,除非数据库是安全的,否则安装环境就不可能安全。因此,首要任务是确保数据库安装是安全的,这可以通过遵循现有的数据库安全检查清单来实现。本指南将更详细地回顾检查清单中涵盖的一些步骤。
保护 Neo4j 扩展
APOC 是一个 Neo4j 扩展,其功能远超任何特定工作负载的需求。正如任何 Neo4j 扩展的情况一样,有几种控制机制有助于确保仅将所需的功能和过程安装到数据库中。
通过配置设置保护 Neo4j 扩展
数据库暴露了配置设置,可以在 conf/neo4j.conf 配置文件中进行配置。配置文件控制哪些过程和函数可以被加载到数据库中并被取消限制。控制此行为的配置设置如下所示。
| 设置 | 描述 | 默认 |
|---|---|---|
要加载的函数和过程名称列表。 |
|
|
被允许对数据库拥有完全访问权限的函数和过程名称列表。 |
|
建议遵守现有的安装指南,其中规定了如何加载和取消限制工作负载所需的最小过程集。
通过 RBAC 保护 Neo4j 扩展
数据库暴露了一种基于角色的访问控制机制,以微调哪些用户角色被允许执行给定的操作。这是 Neo4j 企业版的功能,社区版用户无法使用。
存在有关用户执行任何给定过程能力的执行过程 (Execute Procedure) 权限。默认情况下,所有用户都有权以用户自己的权限级别执行任何过程。这意味着没有读取权限的用户无法通过过程读取数据,没有写入权限的用户无法通过过程写入数据。类似的权限也存在于执行函数 (Execute Functions) 中。
还存在有关用户以完全权限执行任何给定过程的能力的执行增强过程 (Execute Boosted Procedure) 权限。这意味着如果被授予了增强过程权限,即使原本不被允许读取或写入数据库的用户,也被允许这样做。这些权限等同于执行管理过程 (Execute Admin Procedure) 权限。类似的权限也存在于执行增强函数 (Execute Boosted Functions) 中。
|
执行增强权限是一项强大的功能,有可能被滥用。有几个强大的 APOC 过程能够针对数据库运行源自用户输入的完整查询。如果授予用户执行其中任何过程的增强权限并拥有完全特权,则等同于赋予用户运行任何 Cypher 查询的能力。 此类过程的示例包括 |
建议遵守默认行为,即用户仅被允许以其自身的权限级别执行过程和函数,并避免在 APOC 中执行增强过程。当角色需要权限来执行某些操作时,通常可以通过授予其他权限来实现所需的限制,而无需依赖增强执行。
保护文件系统
APOC 包含几个可以读取或写入文件系统上特定文件的过程。如果配置不当,这些过程可能导致高影响的漏洞,例如敏感数据泄露。如果工作负载需要,用户需要启用过程以能够与文件系统进行交互,但仅限于特定目录。如果工作负载不需要,用户应完全限制过程与文件系统的交互。
可以从文件系统读取的过程示例包括 apoc.load.。可以写入文件系统的过程示例包括 apoc.export.。允许数据库从文件系统读取的 Cypher 子句示例包括 LOAD CSV。
在操作系统层面保护文件系统
从操作系统的角度来看,只有一个进程在执行。APOC 并不是作为数据库进程之外的独立操作系统进程存在的。这意味着应用于数据库的所有操作系统限制也将应用于 APOC。因此,数据库的文件权限指南中规定的指导也适用于 APOC。
建议配置数据库进程,使其仅拥有执行工作负载所需的最小文件系统权限集。这意味着限制数据库进程,使其仅在需要时才能与文件系统交互,即使如此,也仅限于特定目标目录,而不是整个文件系统。
在数据库层面保护文件系统
APOC 暴露了控制是否允许与文件系统交互以及从哪个目录交互的配置设置。这些设置可以在 conf/apoc.conf 文件中配置,描述如下。
| 设置 | 描述 | 默认 |
|---|---|---|
启用将文件写入文件系统。 |
|
|
启用从文件系统读取文件。 |
|
|
APOC 在读取或写入文件系统时将遵守 Neo4j 配置设置。 |
|
数据库还暴露了控制是否允许从文件系统读取文件以及从哪个目录读取的配置设置。这些设置可以在 conf/neo4j.conf 文件中配置,描述如下。
| 设置 | 描述 | 默认 |
|---|---|---|
启用从文件系统读取文件。 |
|
|
将读取文件限制为给定目录。 |
|
当 APOC 验证文件系统交互时,它会进行一系列检查。它首先检查是否允许读取或写入。如果允许,它会检查可以执行该操作的目录。
在确定是否允许读取或写入时,APOC 首先验证其自身的配置设置是否已启用,然后检查数据库配置设置是否也已启用。仅当已启用 apoc.import.file_use_neo4j_config 配置设置时,APOC 才会检查数据库配置设置是否也已启用。
在确定允许读取或写入的目录时,APOC 会检查是否已启用 apoc.import.file_use_neo4j_config 配置设置。如果是,它将使用与数据库相同的目录限制。如果未启用此配置设置,则允许 APOC 读取或写入文件系统上的任何位置。
建议因工作负载是否需要读取或写入文件而异。某些工作负载不需要任何文件系统交互,其他工作负载仅要求数据库能够读取文件,而其他工作负载则要求数据库和 APOC 都能够读取文件。
如果工作负载不需要任何文件系统的读取或写入权限,则用户不应更改任一配置文件中的任何配置设置。默认情况下,Neo4j 和 APOC 查询都不被允许读取或写入文件。
如果工作负载仅要求数据库能够读取文件而不需要 APOC 也这样做,则用户应仅通过设置 dbms.security.allow_csv_import_from_file_urls=true 将此能力授予数据库。用户无需对 APOC 配置设置进行任何修改,因为默认情况下它们不允许 APOC 读取或写入文件系统。
如果工作负载要求数据库和 APOC 都能够读取和写入文件系统,则用户仍应尽量保持限制。虽然这将涉及在两个配置文件中启用读取和写入权限,但建议将 APOC 配置设置 apoc.import.file_use_neo4j_config=true 与 Neo4j 配置设置 server.directories.import=import 一起调整。
使用
上一节提供了在执行查询之前保护 APOC 安装的指南。本节将就编写包含高风险 APOC 过程和函数的查询提供建议。
Cypher 注入
Neo4j 知识库提供了关于防止 Cypher 注入的优秀入门指南,建议学习以更好地理解与 Cypher 注入相关的挑战。
许多 APOC 过程直接使用 Cypher,并且在底层,它们将构建并执行源自其接收到的输入的新查询。这些过程对 APOC 用户构成了额外的挑战,用户需要能够识别它们,并了解它们能够提供的有限安全保证。
在下面的第一个示例中,初始查询调用了 apoc.uuid.install 过程,该过程反过来在后台构建第二个查询并执行它。第二个查询获取所有节点,删除一个标签,然后重新附加一个不同的标签。
CALL apoc.uuid.install("Person", {})
// executes a query similar to this: `MATCH (n:Person) SET n.uuid`
在下面的第二个示例中,初始查询调用了 apoc.cypher.runFile 过程,该过程反过来在后台构建第二个查询并执行它。第二个查询获取所有节点并返回它们。
CALL apoc.cypher.runFile("test.cypher", {})
// executes `MATCH (n) RETURN n`
上述示例中的两个过程都构建并执行了源自其接收到的输入的新查询。这两个过程之间唯一的区别在于它们接收到的输入。在第一个示例中,过程知道输入代表 Cypher 字面量。在第二个示例中,过程知道输入代表整个 Cypher 查询。第一个示例中的输入可以进行清洗,而第二个示例中的输入则无法进行清洗。
APOC 保证会清洗对应于 Cypher 字面量的输入。但是,对于对应于整个 Cypher 查询的输入,APOC 无法提供相同的保证。在后一种情况下,清洗 Cypher 查询的责任委托给用户,建议用户仔细遵循上述的 Cypher 注入指南。