REST APIs与微服务:关键差异
Rails XML外部实体指南:示例及预防
在本文中,我们将讨论 XML 外部实体这一主题。我们将简要定义什么是 XML 外部实体,向您展示如何发现它们,并演示如何保护 Ruby on Rails 应用程序免受此漏洞的影响。此外,我们将检查您在实施缓解策略时可能遇到的常见错误,并帮助您相应地解决它们。
如果您恰好没有使用 Ruby on Rails 进行开发的经验,或者您只是在试水,我们强烈建议您花一些时间浏览本文 并熟悉它。
我们将讨论一些可能不太清楚的功能,除非您具备 Rails 背景知识。
什么是 XML 外部实体?
XML,即可扩展标记语言,是一种用于存储、传输和重建任意数据的标记语言和文件格式。这种语言在编程领域用于定义以人可读和机器可读的格式对文档进行编码的规则。这种文件结构如何容易受到攻击?为什么它会对您的系统构成威胁?默认情况下,大多数 XML 处理工具允许指定外部实体(URI),该实体在解析 XML 文件期间被检索和处理。发生这种情况时,解析器可以请求并包含 XML 文档中指定 URI 处的内容。
此漏洞使系统面临被利用的风险。例如,恶意攻击者可以利用此属性作为获取服务器上任何资源的途径。
XXE(XML 外部实体)注入是一种利用 XML 解析漏洞的攻击。它针对使用面向用户的 XML 解析功能的系统,允许攻击者访问服务器上的文件和资源。攻击可能包括泄露包含敏感数据(例如密码或私人用户数据)的本地文件,以及在系统标识符中使用文件:方案或相对路径。
显然,一个坚定的攻击者可能会接管您的服务器,特别是在对服务器结构和您正在使用的技术堆栈的一些信息有充分的了解的情况下。
XML 外部实体示例
现在我们已经解释了 XML 外部实体攻击背后的概念,让我们来看一些例子。
这是一个包含用户名 XML 元素的示例 XML 文档。
<?xml version="1.0" encoding="ISO-8859-1"?>
<username>John</username>
</xml>
相当无害且简单。现在,如何向 XML 添加外部实体?嗯,这很简单。
可以使用 DOCTYPE 标头内的系统标识符添加外部 XML 实体。此指令基本上会向 XML 文件结构添加一些属性。例如,下面的代码包含一个外部 XML 实体,它将获取 /secrets.yml 的内容并将其显示给按用户名呈现的用户。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///secrets.yml" >]>
<username>&xxe;</username>
</xml>
如您所见,这些实体可以访问服务器中的本地或远程内容。如果您保存的敏感文件可以为攻击者提供将整个平台的控制权交给攻击者的途径,那么这将是一个坏消息。其他 XML 外部实体攻击可以访问可能不会停止返回数据的本地资源,可能影响应用程序可用性并导致拒绝服务 (DoS) 攻击。
如果你留意了,这时你就应该拉响警报并致电你的安全专家。
这只是对 XML 外部实体主题的简要说明。它绝不涵盖所有复杂性和错综复杂之处。要保护您的平台免受网络上最复杂的攻击,需要对该技术有广泛的了解,并牢牢掌握平台的基础架构。
好吗?继续。
防止 XML 外部实体攻击
好吧,那么您如何才能防止您的系统受到这些恶意攻击,并在此过程中不丢掉工作呢?
别担心。缓解 XML 外部实体攻击非常简单。通常,只要您不是故意尝试打开漏洞窗口,并且考虑到您需要加载用户提供的 XML 文件的功能,Rails 就能很好地保护您。
让我们举例说明。
正如我们之前提到的,如果应用程序有一个解析 XML 文件的端点,攻击者就可以向服务器发送特制的有效负载并获取敏感文件。攻击者可以访问的文件取决于您如何设置系统以及如何实施用户权限。
因此,为了防止这种情况发生,首先,不要使用支持实体替换的库(如 LibXML)。相反,请使用 Rails REXML 中包含的内置默认库。
现在,如果您已经在使用此库并且无法更改它,或者关键库需要此库,请确保禁用实体替换。
您只需在初始化文件中添加以下代码即可完成此操作:
require 'xml'
require 'libxml'
# Change the ActiveSupport XML backend from REXML to LibXML
ActiveSupport::XmlMini.backend = 'LibXML'
# Deny entity replacement in LibXML parsing
LibXML::XML.class_eval do
def self.default_substitute_entities
XML.default_substitute_entities = false
end
end
值得庆幸的是,新版本的 LibXML 使得启用实体替换变得困难。但是,必须记住的是,如果您决定采用这种方式,您在使用 LibXML 时仍然可能容易受到 DoS 攻击。
现在,假设您的应用程序实际上利用外部实体来实现某些关键功能。在这种情况下,您可以采取的一种方法来最大限度地降低漏洞利用的可能性,就是将已知的外部实体列入安全名单。
您只需在使用库解析 XML 文件文档之前检查其中是否有包含列表中没有的“ENTITY”的字符串即可。
require 'nokogiri'
require 'active_record'
ActiveRecord::Base.establish_connection(
adapter: 'mysql2', # or 'postgresql' or 'sqlite3' or 'oracle_enhanced'
host: 'localhost',
database: 'your_database',
username: 'your_username',
password: 'your_password'
)
class Job < ActiveRecord::Base
end
class ExampleData
attr_reader :file
def initialize(file)
@file = file
end
def xml
raise StandardError.new "POTENTIAL ATTACK" if "<!ENTITY".in? file
Nokogiri::XML(open(file))
end
def create_jobs
xml.css('request').each do |node|
Job.create(
:last_name => node['name'],
:telephone => node['phone'],
:street_address => node['address'],
:city => node['city'],
:state => node['state'],
:zip => node['zip'],
:email => node['email'],
:au_chog => node['chogAu'],
:person_type => node['affil'],
:research_use => node['use'],
:subject => node['subject'],
:notes => node['note'],
:start_date => node['startDate'],
:end_date => node['addDate'],
:complete => true,
:time_spend => node['hours']
)
end
end
file = File.dirname(__FILE__) + "/data/old_data.xml"
example_data = ExampleData.new(file)
example_data.create_jobs
end
核选项
最后——我想强调的是——如果应用程序不需要解析 XML,请不要解析。我知道解析 XML 可能会很方便,并允许平台为用户提供便捷的功能。不过,有很多方法可以在不使用这些库的情况下提供类似的功能。最后,最好的缓解策略是不要以任何方式受到攻击。
如今,为用户提供强大而安全的平台和服务非常复杂。它需要大量的工作和专业知识。对于专注于高效提供快速而富有创意的解决方案的团队来说,这可能是一项艰巨的任务。
展望
目前,大多数开发工具包、软件包和库都非常强大。它们具有多层保护,可抵御 XXE 等各种漏洞。但是,总是有可能无意中引入漏洞,危及您的工作和公司。因此,保持最新状态并依靠出色的 Rails 社区来扩展您的选择至关重要。
Rails 是一个易于使用且友好的平台,可用于构建强大而灵活的应用程序。它使防范 XXE 注入漏洞的工作变得简单直接。无需摆弄复杂的配置或危险的设置。
文章来源:NodeJS XML External Entities Guide: Examples and Prevention