Web 应用安全指南/检查清单
外观
杂项要点
- 不要依赖 Web 应用防火墙来保证安全(但是,可以考虑使用它们来提高安全级别)
- 如果使用了外部库(例如,用于数据库访问、XML 解析),请始终使用最新版本
- 如果需要随机数,请从安全/加密随机数生成器中获取
- 对于每个数据操作或检索,请始终检查访问权限
- 在任何情况下都不要尝试自己实现加密算法。请使用高级库进行加密。
- 确保调试输出和错误消息不会泄露敏感信息
- 在代码中标记有问题的调试输出(例如
//TODO DEBUG REMOVE
),即使您打算在测试后立即将其删除 - 不要使用“
eval()
”和类似函数- 如果可能,请避免使用“
system()
”和类似函数
- 如果可能,请避免使用“
- 确保数据库服务器无法从外部直接访问
- 考虑阻止旧版浏览器使用您的应用程序
文件包含与泄露
- 不要从用户输入中获取包含文件的名称,只能从受信任的列表或常量中获取。
- 如果要使用用户输入,请根据白名单进行验证。检查文件是否存在或输入是否匹配特定格式是不够的。
- 如果可能,请避免让脚本读取和传递文件。
- 如果您使用用户提供的文件名读取和传递文件,请彻底验证文件名以避免目录遍历和类似攻击,并确保用户有权读取该文件。
- 确保应用程序运行时没有超过所需的权限。
文件上传漏洞
- 避免不必要的文件上传
- 确保用户上传的文件不会被 Web 服务器解释为脚本文件,例如,通过检查文件扩展名(或 Web 服务器用于识别脚本文件的任何方法)
- 确保文件无法上传到意外的目录(目录遍历)
- 尝试禁用上传目录中的脚本执行
- 确保文件扩展名与文件内容的实际类型匹配
- 如果只需要上传图像,请考虑使用安全库重新压缩它们以确保它们有效
- 确保上传的文件在传递给用户时使用正确的 Content-type 指定
- 使用允许的文件类型白名单,防止用户上传有问题的文件类型,例如 HTML、CSS、JavaScript、XML、SVG 和可执行文件
- 防止用户上传特殊文件(例如 .htaccess、web.config、robots.txt、crossdomain.xml、clientaccesspolicy.xml)
- 防止用户覆盖应用程序文件
- 考虑使用“Content-disposition: attachment”标头传递上传的文件
SQL 注入
- 使用预处理语句访问数据库 – 或 –
- 使用存储过程,并使用适当的语言/库方法或预处理语句进行访问
- 始终确保应用程序使用的数据库登录名仅具有所需的权限
跨站脚本 (XSS)
- 在将任何非常量内容包含在响应中之前,尽可能靠近输出位置进行转义(即,在包含“echo”或“print”调用的行中)
- 如果不可能(例如,在构建较大的 HTML 块时),请在构建时进行转义,并指示变量内容已预先转义以及名称中的预期上下文。
- 在转义时考虑上下文:转义 HTML 内部的文本与转义 HTML 属性值不同,并且与转义 CSS 或 JavaScript 内部的值或 HTTP 标头内的值非常不同。
- 这可能意味着您需要针对多个上下文和/或多次进行转义。例如,当将 HTML 片段作为 JS 常量传递以供稍后包含在文档中时,在将常量写入 JavaScript 源代码时,需要针对 HTML 中的 JS 字符串进行转义,然后在脚本将片段写入文档时,再次针对 HTML 进行转义。(请参阅基本原理以获取示例)
- 攻击者绝不能将任何内容放在不应放置的位置,即使您认为它不可利用(例如,因为尝试利用它会导致 JavaScript 损坏)。
- 在文档开头(即,尽早)和/或标头中显式设置正确的字符集。
- 确保用户提供的 URL 以允许的方案开头(白名单),以避免危险的方案(例如 javascript:-URL)
- 不要忘记重定向脚本中的 URL
- 可以将内容安全策略用作额外的安全措施,但它本身不足以防止攻击。
XML 和内部数据转义
- 如果可能,请避免使用 XML。
- 对于 XML,请使用经过良好测试的高质量库,并密切关注文档。了解您的库 - 一些库具有允许您在不知情的情况下绕过转义的函数。
- 如果您解析(读取)XML,请确保您的解析器不尝试加载外部引用(例如实体和 DTD)。
- 对于数据的其他内部表示形式,请确保应用了正确的转义或过滤。即使看起来更困难,也尝试使用经过良好测试的高质量库(如果可用)。
- 如果手动进行转义,请确保它能够以安全的方式处理空字节、意外字符集、无效的 UTF-8 字符等。
XML、JSON 和通用 API 安全
- 确保对 API 进行适当的访问控制
- 不要忘记您需要正确转义所有输出以防止 XSS 攻击,数据格式(如 XML)需要特别考虑,并且在许多情况下都需要防止跨站请求伪造 (CSRF)。
- 使用具有成熟库的标准数据格式(如 JSON),并正确使用它们。这可能会处理您所有的转义需求。
- 确保浏览器不会误解您的文档或允许跨站点加载
- 确保您的文档格式正确
- 发送正确的 content type
- 使用
X-Content-Type-Options: nosniff
标头 - 对于 XML,请提供字符集并确保攻击者无法插入任意标签
- 对于 JSON,请确保顶级数据结构是对象,并且 HTML 中所有具有特殊含义的字符都已转义
(不)受信任的输入
- 彻底过滤/转义任何不受信任的内容
- 如果某些输入字段的允许字符集受到限制,请在使用它之前检查输入是否有效
- 如果您对某种数据(例如服务器变量)有疑问,请将其视为不受信任的
- 如果您确定,但没有真正需要将其视为受信任的,请将其视为不受信任的
- 请求 URL(例如,在环境变量中)不受信任
- 来自 HTTP 标头的数据不受信任
- Referer
- X-Forwarded-For
- Cookie
- 服务器名称(!)
- 所有 POST 和 GET 数据都不受信任
- 包括不可修改的用户输入字段,例如 select
- 所有内容验证都必须在服务器端完成
跨站请求伪造 (CSRF)
- 包含一个隐藏的表单字段,其中包含与用户会话(最好是执行的操作)绑定的随机令牌,并在响应中检查此令牌
- 确保令牌不可预测,攻击者无法获取
- 不要将其包含在攻击者可以使用
<script>
标签加载到其站点中的文件中
- 不要将其包含在攻击者可以使用
- Referer 检查不安全,但可以用作附加措施
点击劫持
- 通过包含 HTTP 响应标头“来防止在当前浏览器中对您的应用程序进行 (i)framingX-Frame-Options: deny”
- 通过包含一个 JavaScript 框架破坏程序来防止在过时的浏览器中进行 (i)framing,该程序检查 (i)framing,如果检测到则拒绝显示页面
- 对于安全要求高的应用程序,您希望用户使用 JavaScript 禁用的过时浏览器,请考虑要求使用旧版浏览器的用户启用 JavaScript
不安全的数据传输
- 对任何和所有数据传输使用 SSL/TLS (https)
- 不要以 http 方式开始通信,只有在“需要”时才重定向到 https
- 使用“secure”属性标记 Cookie
- 在可能的情况下使用 Strict-Transport-Security 标头
- 教育用户直接访问https://URL
- 如果您的 Web 应用程序执行 HTTPS 请求,请确保它验证证书和主机名
- 如果连接到内部服务器,请考虑限制受信任的 CA
会话固定
- 在用户登录后立即重新生成(更改)会话 ID(销毁旧会话)
- 防止攻击者通过用户会话来利用用户,仅从cookie中获取会话ID,而不是从GET或POST参数中获取(PHP:php.ini设置“session.use_only_cookies”)
会话劫持
- 为会话cookie设置“HttpOnly”属性
- 使用安全的随机性和足够的长度生成随机会话ID
- 不要泄露会话ID
截断攻击,修剪攻击
- 避免截断输入。将过长的输入视为错误。
- 如果需要截断,请确保在截断后检查值,并且仅使用截断后的值
- 确保不会发生修剪或一致地进行检查
- 引入长度检查
- 注意由于编码导致的不同长度
- 通过设置适当的SQL模式,确保SQL将截断的查询视为错误SQL模式
密码安全
- 不要存储明文密码,只存储哈希值
- 使用Argon2、scrypt、bcrypt或其他专为安全密码存储而设计的安全哈希算法。[1][2]
- 使用每个用户的盐值
- 使用增强(例如多迭代哈希来减缓暴力破解尝试)
- 限制每个IP的登录尝试次数(而不是每个用户帐户)
- 实施合理但不要过于严格的密码策略
- 如果实施了密码重置流程,请确保其具有足够的安全性。“母亲的娘家姓”之类的问题通常可以被攻击者猜测,并且不够安全。
比较问题
- 了解编程语言中的比较类型并使用正确的类型
- 如有疑问(尤其是使用PHP时),请使用严格比较(PHP:“
===
”) - 当比较字符串是否相等时,请确保您实际上是在检查字符串是否相等,而不是一个字符串是否包含另一个字符串
PHP特定问题
- 不要使用简写形式“
<?
”,始终使用完整形式“<?php
” - 当使用nginx web服务器时,请确保正确遵循**官方**安装说明并注意“陷阱”页面。注意一些教程中经常包含有效的但不安全的配置示例。
- 在某些情况下,
preg_replace
可以充当eval()
。避免将用户输入传递给它。如果必须这样做,请正确过滤和转义它。 - 使用Suhosin(如果可能,包括补丁)并使用严格规则进行配置
- 启用
suhosin.executor.disable_emodifier
- 如果可能,启用
suhosin.executor.disable_eval
- 如果可能,将
suhosin.mail.protect
设置为2
- 启用
- 从旧版本更新PHP到PHP 5.4时,请确保旧版应用程序不依赖于magic quotes来保证安全。
预取和蜘蛛
- 对于触发任何操作的任何内容,请使用POST请求而不是GET请求
特殊文件
- 了解这些文件的含义
- 确保robots.txt不泄露“秘密”路径
- 除非需要,否则确保crossdomain.xml和clientaccesspolicy.xml不存在
- 如果使用,请确保crossdomain.xml和clientaccesspolicy.xml仅允许来自受信任域的访问
- 防止用户上传/更改特殊文件(请参阅文件上传漏洞部分)
SSL、TLS和HTTPS基础
- 遵循SSLLabs最佳实践,包括
- 确保禁用SSLv2
- 自己生成证书的私钥,不要让您的CA来做
- 使用合适的密钥长度(通常在2013年为2048位)
- 如果可能,禁用客户端发起的重新协商
- 考虑手动限制/设置密码套件