网站安全
网站安全需要在网站设计和使用的各个方面保持警惕。本文不会让你成为网站安全专家,但它将帮助你了解威胁来自哪里,以及你可以采取哪些措施来加强你的 Web 应用程序以抵御最常见的攻击。
先决条件 | 基本的计算机知识。 |
---|---|
目标 | 了解 Web 应用程序安全中最常见的威胁,以及你可以采取哪些措施来降低网站被黑客入侵的风险。 |
什么是网站安全?
互联网是一个危险的地方!我们经常听到网站由于拒绝服务攻击而无法访问,或者在其主页上显示修改后的(通常是有害的)信息。在其他备受瞩目的案例中,数百万个密码、电子邮件地址和信用卡详细信息泄露到公共领域,使网站用户面临个人尴尬和财务风险。
网站安全的目的是防止这些(或任何)类型的攻击。网站安全的更正式定义是保护网站免受未经授权的访问、使用、修改、破坏或干扰的行为/实践。
有效的网站安全需要在整个网站的设计中进行努力:在你的 Web 应用程序中,Web 服务器的配置,创建和更新密码的策略以及客户端代码。虽然所有这些听起来都非常令人担忧,但好消息是,如果你正在使用服务器端 Web 框架,它几乎肯定会“默认”启用针对许多常见攻击的强大且经过深思熟虑的防御机制。其他攻击可以通过你的 Web 服务器配置来缓解,例如通过启用 HTTPS。最后,有一些公开可用的漏洞扫描工具可以帮助你找出是否犯了任何明显的错误。
本文的其余部分将详细介绍一些常见的威胁以及你可以采取的一些简单步骤来保护你的网站。
注意:这是一个入门主题,旨在帮助你开始思考网站安全问题,但它并不详尽。
网站安全威胁
本节仅列出了几个最常见的网站威胁及其缓解方法。在阅读时,请注意威胁在 Web 应用程序信任或对来自浏览器的数据不够谨慎时最容易成功。
跨站脚本 (XSS)
XSS 是一个术语,用于描述一类攻击,这些攻击允许攻击者通过网站将客户端脚本注入到其他用户的浏览器中。由于注入的代码来自该站点,因此该代码是可信的,并且可以执行诸如将用户的站点授权 Cookie 发送给攻击者之类的操作。当攻击者拥有 Cookie 时,他们可以像用户一样登录到站点,并执行用户可以执行的任何操作,例如访问他们的信用卡详细信息、查看联系信息或更改密码。
注意:从历史上看,XSS 漏洞比任何其他类型的安全威胁都更为常见。
XSS 漏洞根据站点如何将注入的脚本返回到浏览器分为反射型和持久型。
- 反射型XSS 漏洞发生在传递到服务器的用户内容立即且未经修改地返回以在浏览器中显示时。原始用户内容中的任何脚本都将在新页面加载时运行。例如,考虑一个站点搜索功能,其中搜索词被编码为 URL 参数,并且这些词与结果一起显示。攻击者可以构建一个包含恶意脚本作为参数的搜索链接(例如,
https://mdn.org.cn?q=beer<script%20src="http://example.com/tricky.js"></script>
)并将其发送给其他用户。如果目标用户点击此“有趣的链接”,则在显示搜索结果时将执行该脚本。如前所述,这使攻击者能够获取进入该站点所需的所有信息,以作为目标用户,可能以用户身份进行购买或共享其联系信息。 - 持久型XSS 漏洞发生在恶意脚本存储在网站上,然后稍后未经修改地重新显示以供其他用户无意中执行时。例如,一个接受包含未修改 HTML 的评论的讨论板可能会存储来自攻击者的恶意脚本。当显示评论时,脚本将被执行,并可以将访问用户帐户所需的信息发送给攻击者。这种类型的攻击非常流行且功能强大,因为攻击者甚至可能与受害者没有任何直接互动。
虽然来自POST
或GET
请求的数据是 XSS 漏洞最常见的来源,但来自浏览器的任何数据都可能存在漏洞,例如浏览器呈现的 Cookie 数据或上传和显示的用户文件。
防御 XSS 漏洞的最佳方法是删除或禁用任何可能包含运行代码指令的标记。对于 HTML,这包括元素,例如<script>
、<object>
、<embed>
和<link>
。
修改用户数据以使其无法用于运行脚本或以其他方式影响服务器代码执行的过程称为输入清理。许多 Web 框架默认情况下会自动清理来自 HTML 表单的用户输入。
SQL 注入
SQL 注入漏洞使恶意用户能够在数据库上执行任意 SQL 代码,从而允许访问、修改或删除数据,而不管用户的权限如何。成功的注入攻击可能会欺骗身份、创建具有管理权限的新身份、访问服务器上的所有数据或销毁/修改数据以使其无法使用。
SQL 注入类型包括基于错误的 SQL 注入、基于布尔错误的 SQL 注入和基于时间的 SQL 注入。
如果传递给底层 SQL 语句的用户输入可以更改语句的含义,则存在此漏洞。例如,以下代码旨在列出具有特定名称(userName
)的所有用户,该名称是从 HTML 表单中提供的
statement = "SELECT * FROM users WHERE name = '" + userName + "';"
如果用户指定真实姓名,则该语句将按预期工作。但是,恶意用户可以通过为userName
指定a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't
来完全更改此 SQL 语句的行为,从而更改为以下示例中的新语句。
SELECT * FROM users WHERE name = 'a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't';
修改后的语句创建了一个有效的 SQL 语句,该语句删除users
表并从userinfo
表中选择所有数据(这会泄露每个用户的信息)。这是因为注入文本的第一部分(a';
)完成了原始语句。
为了避免这种类型的攻击,你必须确保传递给 SQL 查询的任何用户数据都不能更改查询的性质。一种方法是转义用户输入中在 SQL 中具有特殊含义的所有字符。
注意:SQL 语句将'字符视为字符串文字的开头和结尾。通过在该字符前面放置反斜杠(\'),我们转义了该符号,并告诉 SQL 将其视为字符(只是字符串的一部分)。
在以下语句中,我们转义了'字符。SQL 现在将名称解释为粗体中的整个字符串(这确实是一个非常奇怪的名称,但没有害处)。
SELECT * FROM users WHERE name = 'a\';DROP TABLE users; SELECT * FROM userinfo WHERE \'t\' = \'t';
Web 框架通常会为你处理字符转义。例如,Django 确保传递给查询集(模型查询)的任何用户数据都已转义。
注意:本节大量借鉴了此处维基百科中的信息。
跨站请求伪造 (CSRF)
CSRF 攻击允许恶意用户在未经用户知情或同意的情况下,使用其他用户的凭据执行操作。
这种类型的攻击最好通过示例来解释。Josh 是一位恶意用户,他知道某个特定站点允许已登录的用户使用包含帐户名称和金额的 HTTPPOST
请求向指定帐户发送资金。Josh 创建了一个表单,其中包含他的银行详细信息和金额作为隐藏字段,并将其通过电子邮件发送给其他站点用户(提交按钮伪装成指向“快速致富”站点的链接)。
如果用户点击提交按钮,则会向服务器发送一个包含交易详细信息以及浏览器与站点关联的任何客户端 Cookie 的 HTTPPOST
请求(将关联的站点 Cookie 添加到请求是正常的浏览器行为)。服务器将检查 Cookie,并使用它们来确定用户是否已登录并是否有权进行交易。
结果是,任何在登录到交易站点时点击提交按钮的用户都将进行交易。Josh 发财了。
注意:这里的技巧是 Josh 不需要访问用户的 Cookie(或访问凭据)。用户的浏览器存储此信息,并自动将其包含在发送到关联服务器的所有请求中。
防止此类攻击的一种方法是服务器要求POST
请求包含用户特定的站点生成的密钥。密钥将在发送用于进行转账的 Web 表单时由服务器提供。此方法阻止 Josh 创建自己的表单,因为他必须知道服务器为用户提供的密钥。即使他发现了密钥并为特定用户创建了一个表单,他也将无法再使用相同的表单来攻击每个用户。
Web 框架通常包含此类 CSRF 防护机制。
其他威胁
其他常见的攻击/漏洞包括
- 点击劫持。在此攻击中,恶意用户劫持了原本打算用于可见顶级站点的点击,并将它们路由到隐藏在下方的一个页面。例如,此技术可能用于显示合法的银行站点,但将登录凭据捕获到攻击者控制的不可见的
<iframe>
中。点击劫持还可用于让用户点击可见站点上的按钮,但在这样做时实际上无意中点击了完全不同的按钮。作为防御措施,你的站点可以通过设置适当的 HTTP 标头来防止自己被嵌入到另一个站点的 iframe 中。 - 拒绝服务 (DoS)。DoS 通常通过向目标站点发送大量虚假请求来实现,从而使合法用户无法访问该站点。这些请求可能数量众多,或者每个请求都可能消耗大量资源(例如,缓慢读取或上传大型文件)。DoS 防御通常通过识别和阻止“不良”流量,同时允许合法消息通过来工作。这些防御措施通常位于 Web 服务器之前或内部(它们不是 Web 应用程序本身的一部分)。
- 目录遍历 (文件和信息泄露)。在这种攻击中,恶意用户试图访问他们不应该能够访问的 Web 服务器文件系统的一部分。当用户能够传递包含文件系统导航字符(例如,
../../
)的文件名时,就会发生此漏洞。解决方法是在使用输入之前对其进行清理。 - 文件包含。在这种攻击中,用户能够指定一个“意外”文件,以便在传递给服务器的数据中显示或执行。加载后,此文件可能会在 Web 服务器或客户端上执行(导致 XSS 攻击)。解决方法是在使用输入之前对其进行清理。
- 命令注入。命令注入攻击允许恶意用户在主机操作系统上执行任意系统命令。解决方法是在系统调用中使用用户输入之前对其进行清理。
有关网站安全威胁的全面列表,请参阅 分类:Web 安全漏洞利用(维基百科)和 分类:攻击(开放 Web 应用程序安全项目)。
一些关键信息
前面各节中几乎所有安全漏洞利用都可以在 Web 应用程序信任来自浏览器的數據时成功。无论您采取其他什么措施来提高网站的安全性,您都应在将用户源数据显示在浏览器中、用于 SQL 查询或传递给操作系统或文件系统调用之前对其进行清理。
警告:关于网站安全,您可以学到的最重要的课程是**永远不要信任来自浏览器的數據**。这包括但不限于GET
请求的 URL 参数、POST
请求、HTTP 标头和 Cookie 以及用户上传的文件中的数据。始终检查和清理所有传入数据。始终假设最坏的情况。
您可以采取的其他一些具体措施是
- 使用更有效的密码管理。鼓励使用强密码。考虑为您的网站启用双因素身份验证,以便除了密码之外,用户还必须输入另一个身份验证代码(通常是通过某些仅用户拥有的物理硬件传递的代码,例如发送到其手机的短信中的代码)。
- 配置您的 Web 服务器以使用 HTTPS 和 HTTP 严格传输安全 (HSTS)。HTTPS 对客户端和服务器之间发送的数据进行加密。这确保登录凭据、Cookie、
POST
请求数据和标头信息不容易被攻击者获取。 - 跟踪最流行的威胁(当前 OWASP 列表在此处)并首先解决最常见的漏洞。
- 使用 漏洞扫描工具 对您的网站执行自动化安全测试。稍后,您非常成功的网站还可以通过提供错误赏金来查找错误 Mozilla 在此处提供错误赏金。
- 仅存储和显示您需要的数据。例如,如果您的用户必须存储诸如信用卡详细信息之类的敏感信息,则仅显示用户可以识别信用卡号的足够部分,而不是可以被攻击者复制并在另一个站点上使用的足够部分。目前最常见的模式是仅显示信用卡号的后 4 位数字。
Web 框架可以帮助缓解许多更常见的漏洞。
总结
本文解释了 Web 安全的概念以及您的网站应尝试防御的一些更常见的威胁。最重要的是,您应该了解 Web 应用程序不能信任来自 Web 浏览器的任何数据。所有用户数据都应在显示或用于 SQL 查询和文件系统调用之前进行清理。
通过本文,您已经完成了 本模块,涵盖了您在服务器端网站编程中的第一步。我们希望您喜欢学习这些基本概念,并且您现在已准备好选择一个 Web 框架并开始编程。