网站安全学习笔记

......

Posted by 呆贝斯 on June 7, 2022

什么是网站安全?

互联网是一个危险的地方!我们经常听到有关网站因拒绝服务攻击或在其主页上显示修改(通常是有害的)信息而变得不可用的消息。 在一些出名的案例中,上百万的密码、邮件地址和信用卡信息被泄露给了公众,导致网站用户面临个人尴尬和财务威胁。

网站安全的目的是防止这些(或者说所有)类型的攻击。更正式点说,站点安全就是为保护站点不受未授权的访问、使用、修改和破坏而采取的行为或实践。

有效的站点安全需要在对整个站点进行设计:包括 Web 应用编写、Web 服务器的配置、密码创建和更新的策略以及客户端代码编写等过程。 尽管这听起来很凶险,好消息是如果你使用的是服务器端的 Web 服务框架,那么多数情况下它默认已经启用了健壮而深思熟虑的措施来防范一些较常见的攻击。 其它的攻击手段可以通过站点的Web服务器配置来减轻威胁,例如启用HTTPS。 最后,可以用一些公开可用的漏洞扫描工具来协助发现你是否犯了一些明显的错误。

网站安全威胁

跨站脚本(XSS)

XSS 是一个术语,用来描述一类允许攻击者通过网站将客户端脚本代码注入到其他用户的浏览器中的攻击手段。 由于注入到浏览器的代码来自站点,其是可信赖的,因此可以做类似将该用户用于站点认证的 cookie 发送给攻击者的事情。 一旦攻击者拿到了这个 cookie,他们就可以登陆到站点,就好像他们就是那个用户,可以做任何那个用户能做的事情。 根据站点的不同,这些可能包括访问他们的信用卡信息、查看联系人、更改密码等。

有两种主要的方法可以让站点将注入的脚本返回到浏览器 – 通常被称做 反射型 和 持久型 XSS 攻击。

  • 反射型 XSS 攻击: 发生在当传递给服务器的用户数据被立即返回并在浏览器中原样显示的时候 – 当新页面载入的时候原始用户数据中的任何脚本都会被执行! 举个例子,假如有个站点搜索函数,搜索项被当作 URL 参数进行编码,这些搜索项将随搜索结果一同显示。 攻击者可以通过构造一个包含恶意脚本的搜索链接作为参数 (例如 http://mysite.com?q=beer<script%20src=”http://evilsite.com/tricky.js”></script>),然后把链接发送给另一个用户。 如果目标用户点击了这个链接,当显示搜索结果时这个脚本就会被执行。正如上述讨论的, 这促使攻击者获取了所有需要以目标用户进入站点的信息 – 可能会购买物品或分享联系人信息。

  • 持久型 XSS 攻击: 恶意脚本存储在站点中,然后再原样地返回给其他用户,在用户不知情的情况下执行。 举个例子,接收包含未经修改的 HTML 格式评论的论坛可能会存储来自攻击者的恶意脚本。 这个脚本会在评论显示的时候执行,然后向攻击者发送访问该用户账户所需的信息。 这种攻击类型及其常见而且有效,因为攻击者不需要与受害者有任何直接的接触。 尽管 POST 和 GET 方式获取到的数据是 XSS 攻击最常见的攻击来源, 任何来自浏览器的数据都可能包含漏洞(包括浏览器渲染过的 Cookie 数据以及用户上传和显示的文件等)。

防范 XSS 攻击的最好方式就是删除或禁用任何可能包含可运行代码指令的标记。 对 HTML 来说,这些包括类似 script、 object、 embed 和 link 的标签。

修改用户数据使其无法用于运行脚本或其它影响服务器代码执行的过程被称作输入过滤。 许多 Web 框架默认情况下都会对来自 HTML 表单的用户数据进行过滤。

SQL注入

SQL 注入漏洞使恶意用户能够在数据库上执行任意 SQL 代码,从而允许访问、修改或删除数据,而无需考虑用户的权限。 成功的注入攻击可能会欺骗身份、创建具有管理权限的新身份、访问服务器上的所有数据或破坏/修改数据以使其无法使用。

如果传递给底层 SQL 语句的用户输入可以修改该语句的语义,这种漏洞便是存在的。 例如下面一段代码,本来是用来根据 HTML 表单提供的特定名字(userName) 来列出所有的用户:

statement = "SELECT * FROM users WHERE name = '" + userName + "';"

如果用户输入了真实的名字,这段代码会如预想的运行。然而一个恶意用户可以完全将这个 SQL 语句的行为改变为下面的新语句的行为, 只要通过将 userName指定为下列“粗体”的文本。修改后的代码创建了一个合法的 SQL 语句,该语句删除了整个 users 表, 然后从 userinfo 表中获取了所有数据(所有用户的信息都被暴露了)。这是有效的, 因为注入的文本的第一部分 (a’;) 结束了原来的语句 ( ‘ 在 SQL 语句中是用来描述字符串常量的) 。

SELECT * FROM users WHERE name = 'a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't';

避免此种攻击的方法就是确保任何传递给 SQL 查询语句的用户数据都无法更改查询的本来用意。 有种方式便是将用户输入中任何在 SQL 语句中有特殊含义的字符进行转义。

SQL 语句把 ‘ 号作为一个字符串常量的开头的结尾。通过在前面放置一个斜杠,我们把单引号进行了转义 ( ' ), 然后 SQL 就会将其视为一个字符(作为字符串的一部分)。

在下面的语句中我们对 ‘ 字符进行了转义。SQL 会将粗体显示的整段字符串解释为 name(这个 name 很古怪,但至少是没有危害的!)

SELECT * FROM users WHERE name = 'a\';DROP TABLE users; SELECT * FROM userinfo WHERE \'t\' = \'t';

Web 框架通常会为你进行这种转义操作。例如 Django,可以确保任何传递给查询集合 (model 查询) 的用户数据都是已经转义过的。

跨站请求伪造(CSRF)

CSRF 攻击允许恶意用户在不知情或不同意的情况下使用其他用户的凭据执行操作。

这种类型的攻击最好通过例子来解释。John 是一个恶意用户, 他知道特定站点允许登录用户使用包含帐户名称和金额的 HTTP POST 请求向指定帐户汇款。 John 构建了一个表单,其中包含他的银行详细信息和作为​​隐藏字段的金额, 并将其通过电子邮件发送给其他站点用户(使用伪装成“快速致富”站点链接的提交按钮)。

如果用户单击提交按钮,将向服务器发送一个 HTTP POST 请求, 其中包含交易详细信息以及浏览器与站点关联的任何客户端 cookie(将关联的站点 cookie 添加到请求中是正常的浏览器行为)。 服务器将检查 cookie,并使用它们来确定用户是否已登录并有权进行交易。

最终的结果就是任何已登陆到站点的用户在点击了提交按钮后都会进行这个交易。John 发财啦!

这里的诀窍是,John 不需要访问那些用户的 cookie(或者说身份信息) – 用户的浏览器存储了这些信息, 而且会自动将其包含在发送给对应服务器的请求中。

杜绝此类攻击的一种方式是在服务器端要求每个 POST 请求都包含一个用户特定的由站点生成的密钥 ( 这个密钥值可以由服务器在发送用来传输数据的网页表单时提供)。 这种方式可以使 John 无法创建自己的表单,因为他必须知道服务器提供给那个用户的密钥值。 即使他找出了那个密钥值,并为那个用户创建了表单,他也无法用同样的表单来攻击其他的所有用户。

其他威胁

  • 点击劫持:在这种攻击中,恶意用户劫持了针对可见顶级站点的点击,并将它们路由到下方的隐藏页面。 例如,此技术可能用于显示合法的银行站点,但会将登录凭据捕获到 iframe 攻击者控制的不可见站点中。 点击劫持也可以用来让用户点击一个可见站点上的按钮,但这样做实际上是在不知不觉中点击了一个完全不同的按钮。 作为防御,您的站点可以通过设置适当的 HTTP 标头来防止自己嵌入到另一个站点的 iframe 中。

  • 拒绝服务:DoS 通常是通过向目标站点充斥虚假请求来实现的,从而中断合法用户对站点的访问。 请求可能很多,或者它们可能单独消耗大量资源(例如,缓慢读取或上传大文件)。 DoS 防御通常通过识别和阻止“不良”流量同时允许合法消息通过来发挥作用。 这些防御通常位于 Web 服务器之前或内部(它们不是 Web 应用程序本身的一部分)。

  • 目录遍历:在此攻击中,恶意用户尝试访问他们不应访问的部分 Web 服务器文件系统。 当用户能够传递包含文件系统导航字符(例如,../../)的文件名时,就会出现此漏洞。解决方案是在使用输入之前对其进行清理。

  • 文件包含:在这种攻击中,用户能够指定一个“非预期”文件以在传递给服务器的数据中显示或执行。 加载后,此文件可能会在 Web 服务器或客户端执行(导致 XSS 攻击)。解决方案是在使用输入之前对其进行清理。

  • 命令注入:命令注入攻击允许恶意用户在主机操作系统上执行任意系统命令。解决方案是在系统调用中使用用户输入之前对其进行清理。

常见提升网站安全做法

当 Web 应用信任来自浏览器的数据时,上述章节里提到的大多数攻击利用手段才能成功。无论你做什么其它的事情来提升你的网站的安全性能, 在将信息展示在浏览器之前、在使用 SQL 语句进行查询之前、在传递给一个操作系统或者文件系统之前,你应该过滤掉所有的用户源信息。

在你可以了解到的有关网站安全大多数课程之中,最重要的就是不要相信来自浏览器的数据。 包括在 URL 参数中的 GET 请求、POST 请求、HTTP 头、cookies、用户上传的文件等等。一定要每次都检查用户输入的信息。每次都预想最坏的结果。

你可以采取一些简单的步骤:

  1. 采取更加强大的密码管理措施。当密码频繁更换时鼓励更加健壮的密码。采取双因素认证,也就是说除了密码, 用户还应该输入另一种认证码(通常是只有唯一一个用户拥有的通过一些物理硬件传输的,比如发送给用户手机的验证短信)。
  2. 将你的服务器配制成 HTTPS 和 HTTP Strict Transport Security (en-US) (HSTS)。HTTPS 会加密你的用户和服务器之间传输的信息。 这使得登录认证、cookise、POST 数据及头信息不易被攻击者获得。
  3. 持续追踪那些常见的网络攻击 (the current OWASP list is here),先解决最脆弱的部分。
  4. 使用 vulnerability scanning tools 来对你的网站进行一些安全测试 (然后,你的非常受欢迎的网站还可以靠提供赏金来寻找 bug,就像 Mozilla 这样(like Mozilla does here)。
  5. 只存储和展示你不得不需要的东西。比如,如果你的用户不得不存储一些敏感信息(如信用卡详明),只展示足以让用户识别卡号的几位数字即可, 却不足以让黑客复制之后在另一个站点使用。现今最常见的是只展示信用卡卡号后 4 位数字。

总结

这篇文章介绍了有关网络安全的概念,你应该避免一些常见的攻击。最重要的是,你应该理解一个网络应用程序, 不能相信任何来自网络服务器的数据!所有的用户数据在展示、使用 SQL或者回应系统之前应该被过滤查询。