麻省理工学院的课程“计算机系统安全”。 第11课:Ur / Web编程语言,第2部分

麻省理工学院。 讲座课程#6.858。 “计算机系统的安全性。” Nikolai Zeldovich,James Mickens。 2014年


计算机系统安全是一门有关开发和实施安全计算机系统的课程。 讲座涵盖了威胁模型,危害安全性的攻击以及基于最新科学研究的安全技术。 主题包括操作系统(OS)安全性,功能,信息流管理,语言安全性,网络协议,硬件安全性和Web应用程序安全性。

第1课:“简介:威胁模型” 第1 部分 / 第2 部分 / 第3部分
第2课:“控制黑客攻击”, 第1 部分 / 第2 部分 / 第3部分
第3讲:“缓冲区溢出:漏洞利用和保护” 第1 部分 / 第2 部分 / 第3部分
讲座4:“共享特权” 第1 部分 / 第2 部分 / 第3部分
讲座5:“安全系统从何而来?” 第1 部分 / 第2部分
讲座6:“机会” 第1 部分 / 第2 部分 / 第3部分
讲座7:“本地客户端沙箱” 第1 部分 / 第2 部分 / 第3部分
讲座8:“网络安全模型” 第1 部分 / 第2 部分 / 第3部分
讲座9:“ Web应用程序安全性” 第1 部分 / 第2 部分 / 第3部分
讲座10:“符号执行” 第1 部分 / 第2 部分 / 第3部分
第11课:“ Ur / Web编程语言” 第1 部分 / 第2 部分 / 第3部分

稍后,我将告诉您有关虚假跨站点请求的信息。 我认为讲义解释了为什么在我们的案例中,crossite脚本不起作用。 原因是,每当您创建语法的“片段”时,该对象,树以及该树的不同部分都不只是字符串。



您不能无意间将用户字符串转换为结构树,这不会自动发生,因为很难编写这样的转换器。 但是您可以尝试为Ur / Web写一个翻译器。 很快我将举一个例子,这将有助于减少您对此的担忧。 我想向您展示该语法实际上在编译器中变成了什么。

似乎我们可以在HTML周围加上双引号,这样我们才可以返回正常世界。 有人可能想知道为什么跳过双引号而不是放置XML如此重要吗?

您可以相信我,这是等效的代码。 这是一个内联函数标签,用于创建HTML文档的树节点。 接下来,我将表示CSS样式的参数放在此节点中。 实际上,这里什么都没有发生,因此有许多种不同的方式说“无”,它不需要任何属性。

接下来,我放置body标签,这是标准库中的另一件事。 所有标准标签都是库中的一流函数。



接下来,我们需要将文本“ Hello World”放在正文中,因此我们调用cdata函数,其中cdata是字符数据的XML单词或只是字符串常量,我们可以将文本放在此处。 这应该给我们与以前相同的结果。 让我们看看这是否有效。

现在,我将返回页面。 我们看到的和以前一样,因此与函数在开始时一样。



这不仅是生产线。 这会导致设计一系列操作,因此只有它们允许您创建有效的HTML,并且它们永远无法将行隐式解释为代码,而不仅仅是将内容放置在应有的页面上。



现在,我将尝试做一些不太复杂的事情,这可能是一个问题。 让我们决定我们真的很高兴看到这个世界,因此我们以粗体突出显示“ hello”一词并再次进行编译。



您会看到页面上发生了什么-这个单词没有变粗体,因为编译器显示了如何解释文本而不是标记。 这是HTML语法的一种表示形式,该函数构建语法时无需内置常规的编码约定。 该功能以您想要的方式解释所有内容,而无需考虑您自己的任何事情。

因此,cdata实现执行通常称为转义或“转义”的操作。 但是程序员不必知道有逃避之类的事情。 您可以将其视为一组方便的函数,用于创建描述页面的对象树。

我听说您想查看此处生成的HTML。 好的,那将不是最令人兴奋的事情。 我将尝试在屏幕上放大它,但是它不适合一行。



学生:考虑到您正在使用XHTML,是否可以仅使用cdata字符数据的路径而不是手动进行处理?

教授:我想,但是我需要的XML比我需要的更多。 关于JavaScript URL,还有一个很好的问题。 如果我们允许JavaScript URL,则创建后门以在运行时将字符串自动解释为程序。 这会导致各种问题。

让我们尝试避免它。 首先,我将切换回简化版本,然后在体内添加几行。 让我们放入一个链接,尝试执行适当的操作。 在这里,我们为错误消息留出了空间。



接下来,运行编译器并查看其工作方式。



无效的网址,然后是JavaScript条目和短语“通过祝福”或“通过祝福”。 函数中内置了Bless,它是解析URL的网守。 默认情况下,不允许使用URL,因此当然不允许使用此选项。 通常,编写自己的URL策略以创建代表JavaScript URL的值是一个坏主意。 因为那样的话,由于这些地址可能无效,因此将需要各种保证。

为了使它更清楚一点,让我将这段代码分解成一个单独的函数,该函数调用接受URL的链接器。 因此,URL是一种类型,而不是字符串。 这是表示URL的类型,该URL被您的应用程序的策略明确允许。

像在某些流行的HTML模板框架中一样,我使用花括号来指示在我们创建的HTML内从宿主语言中插入了一些代码。 所有这些都是通过静态检查类型的方式完成的。 因此系统将检查:“是的,这是URL所属的地方,它说它确实是URL,所以一切都很好。”



然后,我可以这样说来明确安排bless调用:“让我们根据URL的“ blessing”结果在此处调用链接器函数。” 在那之后,我们应该得到和以前一样的错误信息。



不幸的是,我无法为您运行此程序,等到失败为止,但是我可以说它肯定会失败,因为我故意犯了一个编译器错误。 该URL策略不会接受该URL。

如果我错过了这个祝福的呼叫,那么在编译时这将是一个更严重的错误,因为您拥有字符串和正确的URL,并且它们的类型不同。



让我们变得更有趣。 我将为此演示打开一个配置文件。 这很短,至少如果您查看任何Java Web应用程序框架。 他们拥有这些巨大的XML文件用于配置,因此我们的一切都变得更好。



我们可以添加一条规则,指出允许Wikipedia上的所有内容,然后将Wikipedia URL放在正文中。



现在转到页面,然后单击“请单击”。



我们得到的是:找不到维基百科的地址。



因此,主要思想是拥有一个抽象类型的URL,就像您可以拥有一个哈希表的抽象类型一样,该哈希表对哈希表的外观进行编码,并防止代码进入哈希表数组。 我们可以对URL执行相同的操作。 使用此祝福功能,系统可确保此类型的每个值都在某个时候通过适当的检查。

例如,使用此策略,我们知道我们永远不会有JavaScript URL,因此您可以安全地获取URL的值并将其用作链接。 这不会破坏语言的基本抽象。

学生:是否可以通过将“纯” JavaScript插入正文字符串来使用它?

教授:是的,不是。 代替JavaScript,您可以嵌入执行某些任务的Ur / Web代码。 现在,我将键入命令:

return <xml><body onload = {alertLOADED”}> 

您将看到发生了什么-口译员在屏幕上放置了一个窗口,上面写着“已加载”-“已加载”字样。



尝试将字符串形式的JavaScript代码解释为程序会是一场灾难。 您会看到,我们可以将代码放入您正在使用的相同编程语言中,但已经受这些花括号的限制了。 然后,它会自动以JavaScript编译以在客户端运行。

我注意到,较新版本的浏览器能够避免字符解释错误,但某些较旧的浏览器却能够使某些内容混淆。 无论如何,如果所有字符元素都进入文档,它们将被解释为UTF-8。 如果使用其他编码有任何问题,则此编码不应在此处应用。

学生:编译器检查字符串是否包含有效的URL。 但是,如果您在运行时计算字符串,那么bless是否会在运行时检查给定的字符串是否有效?

教授:让我们创建一个表格来测试此语句,并将其放在此处。 我们在URL文本框中输入URL,然后插入Submit Submit按钮。



当您单击它时,将通过为表单中的每个字段写入一个值来调用链接器函数。 在这种情况下,只有一个称为“ URL”的字段,因此链接器将处理包含URL作为字符串类型的条目。 然后,我们尝试对其应用祝福功能,看看它是否有效。



在键入错误的URL类型时,您会看到一个错误消息示例,如果您不熟悉Haskell,这些事情将毫无意义。 我忘了在这里插入return函数。 至少现在它更像Java程序。 而且我也忘记了说现在是整页了。 因此,只有在body标签内部之前,我们才能使用a标签。



现在运行编译器,转到我们的页面,单击“请单击”按钮,输入一些不完整的地址。



然后,我们单击Submit Query(发送查询)-“ Send a request”(发送请求),并收到一条错误消息-该类型的地址未解析。



如果我们输入下一个屏幕所示的正确URL,然后单击Submit Query,则不会出现错误消息。



我认为您的问题的答案很长,而且不太令人兴奋。

学生:除了禁止使用JavaScript外,URL还有其他更严格的条件吗?
教授:目前,更严格的限制只是常量和前缀。 但是您也可以创建自己的禁止规则,它们将按照您编写禁止规则的顺序工作。

学生:事实证明,如果您坚持禁止JavaScript,但在“ JavaScript”一词的中间插入换行符,则编译器可以对此进行解释...

教授:是的,那太糟糕了。 这就是为什么坚持使用白名单方法而不是使用黑名单方法的原因。 您可能希望所有规则都以特定协议(例如HTTP)开头,并且只允许适合您批准的协议套件。 我建议这样做。

学生:对于许多站点,您可以允许用户交换链接,在这种情况下,您需要在所有地方允许链接。

教授:如果您希望用户共享JavaScript链接,或者我不知道Flash链接或此处允许的任何内容,则可以允许链接。 您会看到,您可以创建所有HTTP,HTTPS,URL的“白名单”,从而确保大多数站点的安全运行。 这种方法仅比仅允许特定URL弱一点。 但是至少您可以完全消除将字符串作为程序自动执行的可能性。

让我给您一个摘要示例,它是数据库中提供的一个简单聊天室系统的示例。 用户可以单击链接转到会议室,然后发送消息。 这是该方案的几个选项中的第一个。



首先,我会注意到我将重新编译它。 然后神奇地将所有已声明的数据库表添加到数据库中,我们可以开始使用该应用程序。 但是首先我们需要添加一些聊天室。 因此,让我们打开演示数据库的界面,然后在表室中插入值“ one”和“ two”。



现在它们已经出现在这里了。



现在,我们进入第一个聊天室,可以整天通过发送文本行(例如,第一行)来娱乐自己。 尝试发送HTML会更加有趣,并且会立即对其进行处理。 这是程序主要功能的一个示例。



再次,我们将快速研究它的工作原理,因此我们拥有这两个SQL表-表室和表消息,它们在编程语言的第一类中简单声明了。 我们给出每个表的图表。 然后,当我们尝试访问这些表时,编译器确保根据有希望的键入方案对它们进行访问。



因此,我们有一个房间表,其中每个房间都是一个记录,该记录由一个标识符ID(一个整数)和一个Title(一个字符串)组成。 这是我们仅创建记录的视图类型。 我刚刚在SQL控制台中创建了一些房间。 我们还会收到一条通知,通知每条消息都属于一个特定的房间,创建时间以及作为消息内容的文本。
现在让我快速跳转到主要功能。



我们运行一个SQL查询-您会看到Ur / Web中内置的SQL语法示例。 我不想通过标准库中的此扩展来进行函数调用。 这很冗长,足以让我想起以下事实:标准库具有调用函数的方法,这些方法是构建SQL查询的有效方法。

这些函数的类型使它们可以为您打印请求,而不仅仅是保证语法有效。 这段代码只是简单地遍历此查询的所有行,并为每行生成部分HTML代码。

特别是,我们将把查询结果放在“标题”字段上,并将其转换为带有大括号的表示法的HTML。 方括号还表示这不是真正的HTML,但请以标准方式为我进行转换。 因此,我们可以处理字符串和整数以及其他类型的所有数据。

学生:如果其中包含恶意HTML或其他内容,会被过滤掉吗?

教授:是的,会的。 在Ur / Web中,您可以将其视为构建一棵树。 这是代表某些文本的节点。 显然,文本无法执行任何操作。

学生:因此,如果此标头在用户的控制之下,并且有人与标题Alert进行了聊天,那不是JavaScript吗?

教授:不会自动将其解释为JavaScript,HTML或其他任何形式。 该程序将其视为纯文本。

因此,回到我们的屏幕图像。 我们有这个标题Title,让我们用标签框起来。 而且,我们使用link属性代替了href(通常的HTML链接方式),该属性是一种伪属性Ur / Web,它不是URL而是大多数Ur / Web表达式作为参数。 关键是,当您单击此链接时,将启动此表达式以创建应显示的新页面。
在这种情况下,我们将调用聊天功能,此功能在下一个屏幕上定义。



我不会详细介绍。 但是,我们还有其他一些使用各种标准库函数的SQL查询,它们以各种方式使用请求的结果。

我们生成此HTML页面,并说您正在使用这样的标题进行聊天,我们有一个表单,用户可以在其中输入文本。 这是我几分钟前用来演示程序工作方式的表格。 提交表单按钮具有此Add属性,其中包含say,这是Ur / Web函数的名称。 因此,当我们提交表单时,我们将调用此函数。

运行更多的SQL将新行插入到表中。 我们自动从聊天室ID跳到表单中的此处的文本字段,并且根据需要将其自动隐藏。 但是再说一次,在Ur / Web中,您无需考虑以这种方式“转义”该功能。 因为这只是构建树的语法,而不是字符串的语法。 因此,绝不会发生您无法从选择的语法解释方式中想到的奇怪事情。

因此,事实上,我们以图形GUI的形式拥有这种形式的小部件,并且这是一个文本字段,编译器得出结论,填写文本框形式产生的记录必须具有一个称为字符串类型的“文本”元素。 这种形式的编码和键入规则不是语言内置的内容,而是从Ur Express库中获取的,该库实际上控制着这些形式,确定了有效函数的类型。
如果您对该程序的这一部分没有更多的疑问,我将继续下一步。 我将使用一种方法来强制封装支持Ur / Web且很少支持其他语言的应用程序各个部分。 我要去这个房间。 我将采用一些定义,并将它们放入一个模块中,这些模块将其中一些封装为私有。 特别是,数据库表将是私有的,因此没有人能够直接访问它们。

您只能使用我们提供的一组方法来访问它们。 一种方法在事务内部运行,并创建具有可用聊天室的ID和标题字段的记录列表。

接下来,我们只是扩展此聊天操作。 我在这里所做的唯一一件事就是输入概念ID的名称-类型ID。 因此,我不仅仅是说ID是整数,而是说这是一种新类型。



外界可以联系聊天的唯一方法是获取所有房间的列表,而外界可以使用的唯一方法是调用其中的聊天功能。 假设这是哈希表类中的某种抽象类型的哈希表,其中存储了详细信息,这些信息解释什么是ID以及如何在内部生成ID,这些ID对该模块是私有的,并且调用此模块的客户端代码不应使用它们。

现在,我将所有这些语法向下传递并将其放置在模块中,因此默认情况下,它不会暴露给其余代码。 接下来,我实现这种房间方法。 我们已经有机会组织聊天。 但是我们可以使用另一个标准库函数以更简单的方式实现房间,以当前形式解释请求。
让我们从房间列表中按名称排序选择所有内容。 像往常一样,此查询对我们来说是一种经过验证的数据类型。 然后系统确定:“好的,此表达式将生成与该模块的签名中声明的类型匹配的记录列表。” 因此,现在,在此模块之外,没有其他代码可以提及会议室表或消息表。



因此,至少从本申请的观点来看,我们可以从中申请所需的不变性。 我们甚至可以将秘密隐藏在模块内部,这样,如果代码的任何其他部分可以获取秘密,就不会出现安全问题。

学生:其他一些代码也可以实现这种房间方法吗?

教授:那将是一个完全不同的表。 实际上,我们可以通过将这样的4行代码片段插入另一个模块来实现。



然后,我们可以使用此表执行任何操作。 我将在30秒内编译它,然后我们会看到发生了什么。 但是实际上这是一个不同的表,就好像您具有相同的私有名称一样,但是用于两个不同的Java类。

因此,您假设在此模块内有一个称为room的抽象类型,其中包含ID标识符和Title标题。 这是不正确的。 聊天接受房间参数作为输入。 当我们调用聊天功能时,将通过URL进行调用。 ID和标题传递到调用该函数的URL表示之外。 我们只需要ID即可实现此功能。 因此,当我们调用函数时,实际上是在调用URL。
如果在通过URL调用聊天时将标头作为附加参数传递给用户,则在空间使用方面会很浪费,并且对用户而言是不礼貌的。 这有意义吗? 让我们看一下这张幻灯片上的URL栏。



我们关注的频道的标识符会自动序列化到该行末的URL。 如果我们传输了包含ID和标题Title的记录,那么该标题也将被序列化,这至少有点不合逻辑。

54:10

麻省理工学院的课程“计算机系统安全”。 第11课:Ur / Web编程语言,第3部分


该课程的完整版本可在此处获得

感谢您与我们在一起。 你喜欢我们的文章吗? 想看更多有趣的资料吗? 通过下订单或将其推荐给您的朋友来支持我们, 为我们为您发明的入门级服务器的独特模拟,为Habr用户提供30%的折扣: 关于VPS(KVM)E5-2650 v4(6核)的全部真相10GB DDR4 240GB SSD 1Gbps从$ 20还是如何划分服务器? (RAID1和RAID10提供选件,最多24个内核和最大40GB DDR4)。

VPS(KVM)E5-2650 v4(6核)10GB DDR4 240GB SSD 1Gbps至12月免费,在六个月内付款,您可以在此处订购。

戴尔R730xd便宜2倍?在荷兰和美国,我们有2台Intel Dodeca-Core Xeon E5-2650v4 128GB DDR4 6x480GB SSD 1Gbps 100电视(249美元起) 阅读有关如何构建基础架构大厦的信息。 使用价格为9000欧元的Dell R730xd E5-2650 v4服务器的上等课程?

Source: https://habr.com/ru/post/zh-CN425999/


All Articles