大约一周前,Luke Plant 和 Simon Willison 写了他们的 YAGNI 原则例外清单。正如 Simon 所写:YAGNI——你不需要它——是一条规则,你不应该仅仅因为它可能在未来有用而添加功能——只有在解决直接问题时才编写代码。你什么时候应该超越 YAGNI?当后期添加东西的成本与早期添加的成本相比非常昂贵时,值得冒险。当您从经验中知道初始投资将获得多次回报时。因为我喜欢尝试创造词组,所以我建议我们称这些为 PAGNI——可能是可能需要它的缩写。我喜欢这个概念!它非常适用于安全工程:许多风险缓解措施难以实施和解决不太可能的威胁。您不想在早期对安全工程与功能工作进行过度投资:如果您未能获得任何客户,那么您的应用程序的安全性并不重要。然而,也有一些安全工程值得预先做:一开始很容易做的基本安全缓解措施,但随着时间的推移,它们会变得越来越难。这是我的一些安全 PAGNI,包括我的 Twitter 追随者的一些建议。为了防止本文失控,我仅将其范围限定为应用程序安全性。如果您对未来有关信息安全其他领域的文章感兴趣,请告诉我!现实世界中的许多攻击本质上都是机会犯罪:攻击者进行广泛扫描以寻找容易出现的漏洞,然后利用他们发现的漏洞。如果你不解决这些基本缺陷,你就会不知不觉地受到损害。
幸运的是,我们有可以提供帮助的工具。现代 Web 开发库/框架可以缓解许多内置的常见缺陷。例如,Django 具有针对 XSS、CSRF、SQL 注入和许多其他常见缺陷的内置缓解措施。使用 Django 可以保护您(至少部分地)免受前 10 个最常见 Web 漏洞中的六个。这不是您应该使用 Django 的论据——还有其他很棒的工具。但它是一个很好的基准:据我估计,Django 在“默认安全”部门中略高于平均水平。你应该选择至少和 Django 一样好的东西。如果您选择的库/框架不如 Django 好(或更好),请选择其他东西。沿着类似的路线:使用好的工具来帮助您进行加密。众所周知,正确编写加密代码非常困难。最近的一个例子:卡巴斯基密码管理器中的缺陷。如果您需要加密或签名,编写自定义代码应该是最后的手段。相反,使用 libsodium,或者更好的是,使用您的云平台的机密管理功能(例如 AWS Secrets Manager、GCP Secret Manager 等)。更多赌注:让人们可以轻松且合法地告诉您有关安全问题的信息。许多(大多数?)安全漏洞不会被攻击者发现:它们是由您网站的普通用户偶然发现的。所以,发布一个漏洞披露政策——这是一个很好的模板——在你网站的某个地方(我建议'/security/'),并设置一个 security@ 电子邮件地址。某种阻止来自其他用户的不需要的通信的方法,在基本层面内置于平台。 (因为如果你不 PAGNI,以后再添加就太难了,所以你永远不会这样做,并且必须应用不能阻止骚扰的无效解决方法。)- Stuart Langridge (@sil) 七月2021 年 5 月 5 日如果您正在构建任何类型的社交功能,您必须从一开始就考虑滥用行为。几乎不可能针对垃圾邮件、骚扰或滥用改进缓解措施,而且等到攻击发生时才对其采取措施是非常不道德的。
我建议您考虑一下我听说的“滥用前”角色以及所有其他用户原型。想想这类人可以用你的平台做什么,并从一开始就构建缓解措施(例如阻止、静音和报告的工具)。事后不可能添加审计日志:谁在什么时候做了什么? “我再也看不到 X 但我昨天能看到!” “谁编辑了Z?” “可疑/受损用户 Y 采取了哪些行动?”可以让他们稍后对客户可见,但对于内部/支持访问,它们很有价值。 — Robert Coup (@amatix) 2021 年 7 月 5 日设置适当的日志记录可能有点烦人。每次设置时,我都必须重新阅读 Django 的日志记录文档;我似乎无法记住这一切是如何运作的。我经常想跳过它。然而,正如罗伯特指出的那样,这是一个坏主意:如果出现问题,如果没有良好的审计跟踪,就不可能弄清楚事后会发生什么。因此,花点时间设置日志记录,并确保您的应用程序在任何有趣的事情发生时都发出消息。理想情况下,这些日志消息应该流式传输到某种外部日志服务,这样的攻击者即使破坏了您的应用程序服务器也无法删除日志。许多应用程序都有某种管理/员工界面。您可以使用作者/编辑的管理界面来更新内容;为帮助客户提供支持;用于后台工作流程;供开发人员调整设置或功能标志;或者更多。 Django 的内置管理界面是它的一大特色,所以我工作的大多数应用程序一开始都有其中之一。但是,稍后,这些管理界面可能会变得非常可怕。随着公司的发展和不同部门需要更多的东西,它们往往会随着时间的推移而增加功能。如果不加以检查,您最终可能会遇到成百上千的“管理员”可以访问各种可怕功能的情况。一个安全漏洞,或一个被盗的凭证,都可能使攻击者能够跟踪用户、下载敏感数据、转移资金等。
不要让这种情况发生。在您的应用程序生命周期的早期,采取一些措施来限制管理功能的“爆炸半径”: 将您的管理员与您的生产应用程序分开。在 /admin/ 托管管理面板的 Django 默认设置不是一个好方法,安全方面。至少,管理应用程序应该是不同的顶级域(以防止 cookie/会话攻击)。理想情况下,您应该为员工和最终用户使用不同的身份验证,并将管理面板置于另一层安全之后,例如应用感知代理或 VPN。而且您绝对应该要求对您的管理应用程序进行多重身份验证。拥有多个管理应用程序:一个用于支持团队,另一个用于您的计费部门,第三个用于开发人员调整功能标志等。这有助于将不相关的功能置于不需要它的用户手中,并且可以防止管理功能蠕变。避免使用单一的“is-admin”标志;请改用基于角色的访问控制 (RBAC)。也就是说,您的管理应用程序不应该仅仅因为有人登录就假设他们可以访问所有内容。每个功能都应该在权限检查之后进行门控,并且您应该使用角色/组将正确的功能分配给正确的用户。如果您有任何类型的假设用户功能(即某人假设另一个用户的身份并以他们的身份登录;这通常是支持团队要求的功能),请特别小心。通常,这是通过创建与真实用户无法区分的登录令牌或会话 cookie 来实现的。这是审计跟踪的一个问题:无法判断用户是否采取了操作,或者管理员是否使用了他们的帐户并执行了操作。确保任何假定的角色操作都正确地归因于实际的底层员工帐户!是的,这是一项相当大的工作,但它是 PAGNI 的缩影。如果您不事先这样做,那么以后进行改造将非常困难,并且在您这样做之前您将面临一些相当大的风险。如果这一切看起来太多了&mldr 可能只是没有管理面板!?具有将生产数据库的编辑版本恢复到暂存的机制,这样如果暂存中存在错误,则开发更安全,而不会泄露敏感内容(如 PII)
— Simon Willison (@simonw) 2021 年 7 月 5 日,我们希望尽可能将生产数据保留在生产中。但这几乎不可能以任何绝对的方式实现。我们希望拥有能够尽可能接近地反映生产数据的临时站点。我们希望能够将部分生产数据加载到开发中,以诊断与数据相关的错误。业务分析师和数据科学团队需要访问帐户数据来构建模型。等等。通常,这是通过不加选择地复制生产数据并将其加载到其他地方来完成的。因此,我们最终会将敏感数据(PII、账单信息、健康数据等)转移出生产环境。这总是很危险的——开发和临时服务器很少像生产一样受到很好的保护——有时是非法的。因此,在早期——一旦你开始存储敏感数据——你就会想要构建一些工具来执行生产之外的数据传输。确保删除任何敏感数据或用虚拟数据替换。最安全的方法是使用允许列表(而不是阻止列表)。这样做,以便您必须明确列出可以安全传输的表和列,并假设所有其他表和列都是不安全的。这样,您就不会在添加新敏感列时意外忘记阻止它们。最终,每个应用程序都需要一种方法来使用户的会话或密码无效。通常这是为了响应某种支持问题。有时这是为了响应帐户接管(您的一个用户的帐户被盗,可能是通过先前违规的共享凭证)。有时这是一个罕见的会话错误,需要您使现有会话无效。无论哪种方式,有一些功能相当容易实现,但将来会节省您的培根:一种为用户,某些用户组或所有用户触发密码重置的方法
一种要求用户(或某个组等)在下次登录后更改密码的方法 一种使会话令牌(对于用户、某些用户等)无效的方法,从而在该人下次来时强制重新进行身份验证如果您允许通过外部身份提供商(Twitter、Github、SAML 等)登录到该站点,这是一种在用户下次点击您的应用程序时强制对该外部提供者重新进行身份验证的方法 在您需要它们之前构建这些,您就赢了不要急于弄清楚何时需要它们。我确定还有其他人!让我知道你的建议。随着时间的推移,我可能会在收到建议或想到新建议时更新此列表。