其他人的数据,你的安全性: 面向企业的Mashup应用程序,第 2部分

分享于 

24分钟阅读

Web开发

  繁體

在10天内开发 Windows 8应用程序。

在本系列的第一篇文章中,我介绍了交叉源资源共享( CORS ) 和构建iframe沙箱,并描述了如何使用这些技术在mashup应用程序中使用数据,并为defense-in-depth策略提供一个。 通过定义信任级别,我将开始探索如何使用来自CORS连接的数据,然后进行相应的消毒。 为此,我将建立在项目Silk提供的指导之上。 首先,让我们讨论信任以及企业中的mashup应用程序如何为现有范例提供独特的挑战。

信任或者缺少它

编写安全代码,作者提出了一个极好的口号: ,所有输入都是恶意的,在企业mashup应用程序中,这是 true,但有些输入比它的他的更恶恶。 例如来自公司资源系统的数据源是否与来自 Twitter的数据源构成相同的威胁? 另一个关于软件安全性的常见表达式是"所有外部系统都有威胁。",这是 true,但是安全性是关于风险管理的,这需要在mashup开发过程中保持。 风险是威胁( 威胁是利用系统中的漏洞)的影响和它的执行概率的组合。 HR数据提要的威胁类型可能会比消耗 Twitter 提要所能实现的威胁更低。 Twitter 提要可以是任何用户提供的文本内容,而HR提要则是由部门的成员提供和验证的一组结构化数据点。 这给了HR系统一个较低的风险( 假设执行的概率低于或者等于 Twitter )。 考虑到系统的信任,扩展你对输入的愿景,包括来自你的mashup提供者的内容,并权衡内部 vs 外部提供者的信任。

以下是为mashup提供程序构建你的输入验证时需要考虑的一些问题:

  • 你的组织文化对风险有什么影响? 当功能处于危险状态时,你是否对风险不利或者更不关注风险?
  • 提供程序的历史记录是什么? 例如,如果你知道内部提供程序已经通过不满意的员工发送到它的站点,那么你很明显要注意。
  • 提供程序从提供程序接收的数据类型? 以 Twitter vs 映射为例,例如。 来自Bing地图的内容类型与 Twitter ( 取决于 API ) 中的内容不同。 这对你对提供者的信任有什么影响?
  • 数据是否在你的威胁模型中跨越信任边界?

Mashup数据= 输入

总体来说,你的目标是安全地从不同来源使用数据,一些信任和其他不信任的数据。 来自各种源"是很长的一段时间"输入的数据,这意味着你需要考虑输入验证的三个元素: 约束。拒绝和消毒。约束输入不仅限制了允许的内容。 它还意味着将可能的入口点减少到系统中。 ( 在信息安全性中,我们调用这个"。减少攻击面。") 你需要一个输入 chokepoint,所有消耗的数据。 幸运的是,in模式&实践的优秀人员为项目丝丝中的数据管理器提供了很好的设计。

为数据管理器提供的样例代码是处理Ajax请求的优秀单点,我们将在示例应用程序中使用。 作为处理请求的组件,数据管理器对我们输入验证过程的组件非常理想。 图 1 显示了使用增强的数据管理器在我们的应用程序中请求的Ajax请求。

图 1: 最初来自Project的工作流,更新为显示我们的新子流程

我们有两个验证活动:

  • 验证响应:这个过程对来自Ajax请求的内容执行输入确认活动。 此时,我们已经从提供者那里收到数据,并需要确保它遵循为我们的应用程序配置的安全标准。
  • 验证缓存:这个进程对来自缓存的内容执行输入确认活动。 永远不要假定缓存中的数据是干净的。 尽管我们的应用程序将在存储缓存之前清理数据,但是我们需要确保数据是清洁的。 操作开发人员假设的缓存是干净的,有时称为缓存中毒。 这种攻击通过将恶意内容注入缓存中,使缓存中开发者信任错误,从而为来自缓存的数据注入任何输入验证活动。

我们将使用单个小部件来管理验证活动。 我们将使用Project设计来构建一个执行验证验证三个过程的验证小部件: 约束,拒绝和消毒在 中可以找到一个优秀的,简明的输入验证技术,可以提高Web应用程序安全性: 威胁和对策。 尽管微软已经退休了这个内容,但是本书对于web应用程序安全性来说是一个优秀的资源,即使你不是 ASP.NET 开发者,我也。

过程的第一步是将数据约束为已知的良好数据。 当你看到"已知的好数据"立即想到白色 List。 对于输入验证的白名单方法,你可以确定哪些是允许的,哪些是拒绝的。 下面是一些可以用于执行这里操作的示例技术:

  • 类型检查: 从请求 MATCH 返回的数据返回信任代理所返回的数据? 实现这样的检查可以能是JavaScript中的一个挑战,因为"类型"的想法并不总是清晰的剪切。 幸运的是,你可以限制应用程序接受的数据类型,只接受通过数据类型检查的内容。
  • 按以下方式检查:使用 正规表达式 检查返回的长度是否符合你预期的长度。 例如 Twitter 提要的长度是 140个字符,或者它是? 请注意假设,Twitter 提要是 140个字符,但可以支持你需要考虑的HTML ( 例如缩小的URL )。
  • 格式检查: 搜索返回的数据以查找你期望的模式。 例如如果希望返回3 个逗号分隔项的List,请使用 正规表达式 检查数据是否符合这里格式。 不符合项意味着无效数据。
  • 你期望一个介于 1到 10之间的数字? 范围检查可以将数据限制为适当的特定范围。 例如在人力资源系统中,个人年龄的259值可能无效。

对于我们的小部件,我们将重点放在类型检查上。 其他元素是对小部件的出色扩展,可以在特定情况下使用。 例如,可以在用户界面小部件向页面呈现数据时添加长度验证程序。 我将描述的是一个输入验证小部件的框架和基本框架,我鼓励你使用本文讨论的主题。

限制输入

验证部件使用与项目丝绸中的数据管理器相同的设置。 这与标准UI小部件稍微不同,但这个控件并不创建接口,只是清理数据。 许多小部件一样,我们首先为控件设置可能的选项。 这些是在控件实例化时将被替换的默认设置:

(function (hybrid, $) {
 hybrid.sanitizer = {
 //default options options: {
 data: null, //data to be validated dataType: null//[OPTIONAL] expected data type of the data },

这里有很多默认小部件方法,比如 Destroy_create_init,但是我们不会在这里实现这些方法。 作为我们的主力的方法是 sanitize 方法。 这个方法从任何地方接受输入,约束它到我们接受的类型,并将数据编码为更安全的输出。

//validate data provided  sanitize: function (inputOptions) { 
 var that = this; 
 that.options = $.extend({}, this.options, inputOptions); 
 var suppliedDataType = null; 
 var output = null;

首先,在项目丝代码中,我们将 this 转换为 that,以避免 this 变成它的他的嵌套函数。 接下来,我们使用 jQuery extend 方法创建新的options 对象,将默认值与在调用 sanitize 方法时提供的inputOptions 值相结合。 这里步骤确保在 options 对象中提供了所有值。 两个将保存重要信息的变量是 suppliedDataType,它通过识别所提供的数据类型和 output

尽管我们在 options 对象中有一个 dataType 设置,但是我们希望依赖于数据的确定。 这是约束数据的一个方面。 我们只接受特定种类的数据。 你接受的数据取决于你,但是为了本项目,我们需要JSON和 XML。 我们来看看关于这两种数据类型的具体关注点。

JSON

JavaScript对象表示法( JSON ) 是一种非常常见的mashup数据格式。 如果你使用jQuery作为你的Ajax调用,并指定JSON作为数据类型,jQuery将为你实现一个有效的JSON对象( 如果结果无效,则抛出异常)。 如果不使用 jQuery,那么根据如何将文本转换为JSON对象,可能会有问题。 多次JavaScript开发人员需要将文本转换为对象,他们认为使用 eval() 是一种更好的方法。 下面是一些使用jQuery将文本转换为JSON的示例代码。 可以使用内置于 IE 和大多数其他浏览器的JSON.parse, 来遵循相同的流程。 对于缺少这个功能的老浏览器,你需要将 crockford的 JSON2.js 包含到polyfill中。

try { 
 output = $.parseJSON(that.options.data); 
 if (null!== output) 
 suppliedDataType = "json"; 
 } 
 catch (ex) { 
 }

在这里 block 中,jQuery parseJSON 方法检查传入 data 对象的数据是否是有效的JSON对象。 如果使用 dataType :"json" 进行Ajax调用,那么肯定会有JSON对象。 当数据类型为文本或者使用多个数据类型且仅返回文本的某些原因时,这里检查为。 如果 output 有一个值( 如果数据被解析为 JSON,它应该是),则将 suppliedDataType 变量设置为 json。 如果数据不是有效的JSON,代码将封装 try/catch 中的部分,因为在不能将数据转换为 JSON ( 和 parseXML 不同的是,我们会马上看)的情况下,parseJSON 方法的会引发异常。

eval() 或者不对它的求值( )

在安全领域,eval()的使用是一个棘手的问题。 当你向安全专业人员描述它的功能时,你通常会得到一个由运行和。 基本上,eval 采取数据并将它的转换为命令,这意味着数据和命令通道的攻击。 然而,对于开发人员来说,eval 是代码问题的答案。 作为开发人员( 或者开发团队),你需要平衡功能和安全性。 安全的最佳实践说从不 eval 不可信数据( 它返回到早期检查受信任的内容)。 不幸的是,代码问题并不总是符合最佳实践。 当你需要使用 eval 时,请注意使用它将注入到你的应用程序中的风险。 确保你在威胁模型中注意到 eval的使用,因为安全部门希望知道这一点。

JSONP

如果你想从( 还记得第一篇文章中的应用程序同源策略) 以外的源检索JSON对象,那么JSONP可能是你的答案。 JSONP通过在页面上插入脚本标记来调用调用站点对象的远程JSON的Ajax请求。 远程站点接收请求并将JSON对象包装在"回拨"QueryString 参数定义的方法中。 然后在应用程序页面上执行脚本引用,JSON对象作为方法的值返回。 完成之后,脚本标记将从页面中移除,本地变量保存回调方法的值。 例如假设我执行了以下JSONP请求:

http://travel.contoso.com/alerts/medical-alerts.ashx?callback=viewAlerts

这将导致浏览器解释以下输出:

viewAlerts([{ "ID": 1, "Title": "Flu strikes Kenya" }]);

ChiliBook.lineNumbers = true; ChiliBook.automatic = true ;

如果这听起来像脚本注入,那么你是正确的。 为了使单源策略的限制,tmodel允许你创建一个脚本引用,然后在应用程序的原点执行该脚本。 可以想象,这将为你的应用程序带来巨大的安全风险。 作为最佳实践,限制对可信提供者使用 JSONP,并通过你的杀毒流程运行JSON输出。 然而,有些提供者只提供JSONP数据,如果你想访问来自提供者的数据,你必须接受风险。 咨询你的信息安全团队关于 JSONP ( 或者使用外部脚本资源)的策略和过程。 在威胁模型中记录JSONP实现,并说明为什么需要这样做。

大多数人都在激发一些令人安全的( 在一个iframe沙箱中执行它,并且标准化了如何将json称为 are ) 更安全的方法,但是到了更多的时候,它是安全风险。

XML

接收的另一种常见数据格式是 XML。 如同JSON一样,如果你使用jQuery作为Ajax请求并指定数据类型,那么将根据你的浏览器设置XML文档。 为检查XML数据并将它的解析为有效的XML文档,jQuery提供了几个很好的帮助器:

if (null === suppliedDataType) { 
 if (jQuery.isXMLDoc(that.options.data)) { 
 suppliedDataType = "xml"; 
 output = that.options.data; 
 } 
 else { 
 output = $.parseXML(that.options.data); 
 if (null!== output) 
 suppliedDataType = "xml"; 
 } 
 }

我们可能要求 dataType :"xml", 并且从Ajax请求返回一个XML文档。 测试这个条件是第一步。 通过使用 jQuery.isXMLDoc 方法,可以避免浏览器( 因为不同的浏览器做不同的事情) 中的XML混乱。 如果数据已经是格式良好的XML文档,这里方法返回 true。 如果不是XML文档,代码将尝试使用 $.parseXML 方法将响应转换为 XML。 使用 parseXML 方法,jQuery检查 that.options.data 并确定它是否可以转换为XML文档。 在数据不是XML的情况下,parseXML 方法将返回空值。 成功地将 Casting that.options.data 用作XML之后,我们将 suppliedDataType 设置为 XML。

其他数据类型?

在我们的应用程序中,我们只接受JSON和 XML。 将拒绝任何其他类型的数据。 要使用输入验证项,请执行以下操作: 我们将输入输入JSON和 XML,并输入所有其他的。 如果我们收到文本,它需要被转换为JSON或者 XML,或者将被忽略。 这个限制让我们减少了通过我们系统的可能数据。 当我们采用更多的数据类型时,我们可以扩展解决方案,但是现在我们只需要关注"已知的好数据。"图 2 显示我们的拒绝过程。

switch (suppliedDataType) { 
 case"json": 
 this._recursiveJSONSanitizer(output, this._sanitizeJSON); 
 break; 
 case"xml": 
 this._recursiveXMLNodeSanitizer(output.firstChild, this._sanitizeXML); 
 break; 
 default: 
 throw"The supplied data type is either not supported or not recognized."; 
 break; 
 } 
 return output; 
 },
图 2: 除非数据是JSON或者 XML,否则应用程序会拒绝它。

Sanitization: 使数据安全和不可执行

现在我们已经为有效数据类型设置了约束,并拒绝了所有它的他的,我们需要清理。 这里清理需要几个子流程:

  • 规范我们的数据
  • 确保注入的代码是惰性
  • 确保只有允许的HTML可用

这里我们将检查 sanitizeJSON 方法及其执行这些步骤的方式。 sanitizeXMLsanitizeJSON 方法的工作方式相同。 它们从一个递归方法调用,这些方法通过每个节点来处理对象的文本:

_sanitizeJSON: function (data) { 
 var tainted_data = data; 
 var canon_data = $.encoder.canonicalize(tainted_data); 
 if (null!= window.toStaticHTML) 
 data = window.toStaticHTML(canon_data); 
 else 
 data = $.encoder.encodeForHTML(canon_data); 
 },

首先,我们在"被污染"变量中捕获数据。 这只是向开发人员表明数据还没有经过消毒过程。 接下来,我们使用来自 Chris Schmidt的 $.encoder 插件来检查多个编码的数据。 如果 canonicalize 命令检测到多个编码,它会引发异常,因为多个编码的存在是安全威胁的标志。 从那里我们使用 window.toStaticHTML 命令来渲染 tainted_data 中的任何脚本。 toStaticHTML 函数是内置到 IE的JavaScript函数,它防止恶意脚本在数据通道中执行。 如果你是针对其他浏览器的,则可以使用 $.encoder.encodeForHTML(canon_data) 实现类似效果的方法。 finally,如果有允许的HTML标记的List,可以使用简单替换调用将编码的HTML标记替换为已经解码的HTML标记:

data = window.toStaticHTML(canon_data).replace('&lt;p&gt;', "<p>").replace("&lt;/p&gt;", "</p>");

如果允许呈现标记,请在你的威胁模型中维护可以接受标记的List。 安全团队需要注意这个信息。 某些HTML标记比其他标记更安全,比如格式化标记,例如 <strong>。<em>和 <blockquote>。 请注意以下标签( 该 List 来自 http://msdn.microsoft.com/en-us/library/ff649310.aspx。),因为它们被用于将脚本或者它的他恶意代码注入到你的应用程序中:

  • <小程序>
  • <正文>
  • <嵌入>
  • <帧>
  • <脚本>
  • <框架集>
  • <html>
  • <iframe>
  • <>
  • <样式>
  • <层>
  • <链接>
  • <ilayer>
  • <元>
  • <对象>

我还没有涵盖消毒部件的所有方面。 可以在代码库找到 sanitization widget的完整代码。 我建议你建立一个 shell,然后提交你的改进。

现在,我们将关闭小部件:

} 
} (this.hybrid = this.hybrid || {}, jQuery));

然后将它的作为 sendRequest 管理器项目数据的方法的一部分,如图 3所示。

sendRequest: function (options) { 
 var that = hybrid.dataManager; 
 var cachedData = hybrid.dataStore.get(options.url); 
 var callerOptions = 
 $.extend({ cache: options.cache }, 
 that.dataDefaults, options); 
 if (callerOptions.cache && cachedData) { 
 var sanitized_cacheData = 
 hybrid.sanitizer.sanitize({ 
 data: cachedData, 
 dataType: callerOptions.dataType }); 
 options.success(sanitized_cacheData); 
 return; 
 } 
 callerOptions.success = function (data) { 
 var tainted_data = data; //setup the data as a tainted component that needs //sanitization var sanitized_data = 
 hybrid.sanitizer.sanitize({ 
 data: tainted_data, 
 dataType: callerOptions.dataType }); 
 if (callerOptions.cache) { 
 hybrid.dataStore.set(callerOptions.url, 
 sanitized_data); 
 } 
 options.success(sanitized_data); 
 }; 
 $.ajax(callerOptions); 
 },
图 3将我们的小部件与项目丝数据管理器集成

评论主题

在mashup的世界中,mantra"所有的输入都是邪恶的"仍然适用? 如果你不信任构成应用程序的所有数据和功能,你能构建一个伟大的应用程序?

约束,拒绝和消毒

本文重点讨论输入验证的活动。 我首先讨论了信任及其在mashup应用程序领域中的作用。 在on中使用数据管理器,我们将看到一个小部件,用于执行从Ajax请求返回的数据的三个元素。 这是defense-in-depth策略中保护mashup应用程序用户的另一个层。 我的next是modern的安全特性,现代浏览器的安全特性,比如XSS过滤,安全防御,防御超过 OWASP前十年的安全。

关于作者

过去十年Tim一直在使用 JavaScript。ASP.NET 和 C# 构建web应用程序。 现在Tim带领FrontierMEDEX开发在线医疗和安全智能工具开发团队。 Tim是一个CISSP和 CEH,专门用于安全软件开发。

这篇文章是 Tim Kulp写的。 过去十年Tim一直在使用 JavaScript。ASP.NET 和 C# 构建web应用程序。 现在Tim带领FrontierMEDEX开发在线医疗和安全智能工具开发团队。 Tim是一个CISSP和 CEH,专门用于安全软件开发。

查找 Tim:


相关文章