SQL
强烈建议保护我们的网站免受注入攻击的重要性,以确保我们的数据安全。良好做法建议使用准备好的查询来避免这些攻击。但这就是我要去的地方,它是否存在或者你知道任何例子,即使使用准备好的查询,也可以执行这种类型的攻击?
我以这段代码为例:
$server = "localhost";
$user = "usuario";
$password = "password";
$dbname = "ejemplo";
// Conectar
$db = new mysqli($server, $user, $password, $dbname);
// Comprobar conexión
if($db->connect_error){
die("La conexión ha fallado, error número " . $db->connect_errno . ": " . $db->connect_error);
}
// Preparar
$stmt = $db->prepare("INSERT INTO Clientes (nombre, ciudad, contacto) VALUES (?, ?, ?)");
$stmt->bind_param('ssi', $nombre, $ciudad, $contacto);
// Establecer parámetros y ejecutar
$nombre = "Donald Trump";
$ciudad = "Madrid";
$contacto = 4124124;
$stmt->execute();
$nombre = "Hillary Clinton";
$ciudad = "Barcelona";
$contacto = 4665767;
$stmt->execute();
// Mensaje de éxito en la inserción
echo "Se han creado las entradas exitosamente";
// Cerrar conexiones
$stmt->close();
$db->close();
对于未来的网络安全项目,我有一个疑问,其中将应用多种攻击来测试站点的漏洞。
问候。
正如我在评论中已经说过的那样,可以就该主题编写一个库,并且鉴于可能的场景、可用于连接的 API、数据库管理器、可能的环境的多样性,它永远不会被 100% 阐明...... .
但是,我知道该问题旨在阐明除了使用准备好的查询之外,可以观察到的其他防止SQL Injection的措施。
作为贡献,我将放一些关于 OWASP 的指标,OWASP 是关于一般安全性的权威。
在SQL 注入预防备忘单中,他们考虑了主要防御级别和附加防御级别(在链接中有根据语言/处理程序的安全代码示例),如果您想更深入,最后还有一系列链接进入主题):
主要防御:
附加防御:
主要防御
防御选项 1:Prepared Statements(带有参数化查询)
使用带有变量绑定的准备好的语句(也称为参数化查询)是所有开发人员首先应该学会如何编写数据库查询的方式。它们比动态查询更容易编写和理解。参数化查询迫使开发人员首先定义所有 SQL 代码,然后将每个参数传递给查询。这种编码风格允许数据库区分代码和数据,而不管提供什么用户输入。
准备好的语句确保攻击者无法更改查询的意图,即使 SQL 命令是由攻击者插入的。在下面的安全示例中,如果攻击者输入 的用户名
tom 'o' 1 '=' 1
,则参数化查询不会受到攻击,而是会寻找与字符串字面匹配的用户名tom 'o' 1 '=' 1
。具体语言建议:
在极少数情况下,准备好的语句会损害性能。遇到这种情况时,最好 a) 强制验证所有数据或 b) 使用特定于数据库供应商的转义例程删除所有用户提供的输入,如下所述,而不是使用准备好的语句。
防御选项 2:存储过程
存储过程对 SQL 注入并不总是安全的。但是,某些标准存储过程编程结构在安全实施时与使用参数化查询具有相同的效果,这是大多数存储过程语言的规范。
它们要求开发人员简单地创建带有自动参数化参数的 SQL 语句,除非开发人员做了一些不寻常的事情。准备好的语句和存储过程之间的区别在于,存储过程的 SQL 代码是定义并存储在数据库本身中,然后从应用程序中调用的。这两种技术在防止 SQL 注入方面同样有效,因此您的组织必须选择最适合您的方法。
注意:“安全实现”意味着存储过程不包括任何不安全的动态 SQL 生成。开发人员通常不会在存储过程中生成动态 SQL。但是,这是可以做到的,但应该避免。如果无法避免,则存储过程必须使用本文所述的输入验证或适当的转义,以确保用户提供的存储过程的所有输入都不能用于向存储过程注入 SQL 动态生成的查询。审核员应始终在 SQL Server 存储过程中寻找 sp_execute、execute 或 exec 的使用。其他供应商的类似功能也需要类似的审计跟踪。
在某些情况下,存储过程会增加风险。例如,在 MS SQL 服务器中,您有 3 个主要的默认角色:db_datareader、db_datawriter 和 db_owner。在使用存储过程之前,DBA 将根据要求授予 db_datareader 或 db_datawriter Web 服务用户权限。但是,存储过程需要执行权限,这是默认情况下不可用的功能。一些集中用户管理但仅限于这 3 个角色的配置使所有 Web 应用程序在 db 所有者权限下运行,因此存储过程可以工作。自然,
防御选项 3:白名单输入验证
SQL 查询的某些部分不是使用绑定变量的合法位置,例如表名或列名,以及排序指示符(ASC 或 DESC)。在这种情况下,输入验证或查询重新设计是最合适的防御措施。对于表名或列名,理想情况下这些值来自代码,而不是来自用户参数。
但是如果用户参数值用于区别于表名和列名,那么参数值应该映射到合法/预期的列或列名,以保证未验证的用户输入不会在查询中结束。请注意,这是设计不佳的症状,如果时间允许,应考虑重写。
防御选项 4:转义所有用户提供的输入
当上述方法都不可行时,这种技术只能作为最后的手段使用。输入验证可能是一个更好的选择,因为与其他防御相比,这种方法很脆弱,我们不能保证它会在所有情况下阻止所有 SQL 注入。
此技术用于在将用户输入放入查询之前对其进行转义。它是一个非常具体的数据库在它的实现。通常仅在实施输入验证不具有成本效益时才建议更新遗留代码。从头开始构建的应用程序或需要低风险容忍度的应用程序必须使用参数化查询、存储过程或为您构建查询的某种对象关系映射器 (ORM) 来构建或重写。
这种技术是这样工作的。对于某些类型的查询,每个 DBMS 都支持一种或多种特定的字符转义方案。如果您随后使用您正在使用的数据库的适当转义方案转义所有用户提供的输入,DBMS 将不会将该输入与开发人员编写的 SQL 代码混淆,从而避免潜在的 SQL 注入漏洞。
额外的防御
除了采用四种主要防御之一,我们还建议您采用所有这些附加防御来提供纵深防御。这些额外的防御是:
最低权限
为了最大限度地减少成功的 SQL 注入攻击造成的潜在损害,您应该最大限度地减少分配给环境中每个数据库帐户的权限。不要将 DBA 或管理员类型的访问权限分配给您的应用程序帐户。我们知道这很容易,当您这样做时,一切都会“正常工作”,但这是非常危险的。
从头开始确定您的应用程序帐户需要哪些访问权限,而不是试图弄清楚您需要删除哪些访问权限。确保只需要读取权限的帐户仅对他们需要访问的表具有读取权限。
如果帐户只需要访问表的一部分,请考虑创建一个视图来限制对这部分数据的访问,并将帐户的访问权限分配给视图而不是基础表。很少,如果有的话,它会授予对数据库帐户的创建或删除访问权限。
如果您采用在任何地方都使用存储过程并且不允许应用程序帐户直接运行它们自己的查询的策略,那么将这些帐户限制为仅运行它们需要的存储过程。不要直接向数据库中的表授予任何权限。
SQL 注入并不是对数据库数据的唯一威胁。攻击者可以简单地将参数值从他们提供的合法值之一更改为未经授权的值,但应用程序本身可能被授权访问。因此,最小化授予您的应用程序的权限将减少此类未经授权的访问尝试的可能性,即使攻击者没有尝试将 SQL 注入作为其漏洞的一部分。
当您使用它时,您应该最小化运行 DBMS 的操作系统帐户的权限。不要以 root 或系统身份运行 DBMS!大多数 DBMS 都被一个非常强大的系统帐户所累。例如,MySQL 默认在 Windows 上作为系统运行!将 DBMS 操作系统帐户更改为更合适的帐户,并具有受限的权限。
多个数据库用户
Web 应用程序设计者不仅应该避免在 Web 应用程序中使用相同的所有者/管理员帐户来连接数据库。不同的数据库用户可用于不同的 Web 应用程序。
通常,每个需要访问数据库的单独 Web 应用程序都可以有一个指定的数据库用户帐户,Web 应用程序将使用该帐户连接到数据库。这样,应用程序设计人员可以在访问控制方面拥有良好的粒度,尽可能减少权限。每个数据库用户都可以选择访问他们只需要的内容,并根据需要进行写入访问。
例如,登录页面需要对表的用户名和密码字段具有读取权限,但不具有任何写入权限(没有插入、更新或删除)。但是,记录页肯定需要对该表的插入权限;只有当这些 Web 应用程序使用不同的数据库用户连接到数据库时,才能应用此限制。
意见
您可以使用 SQL 视图通过限制对表中特定字段或表连接的读取访问来进一步增加访问粒度。它可能具有额外的好处:例如,假设系统需要(可能由于某些特定的法律要求)来存储用户密码,而不是加盐密码。
设计者可以使用视图来弥补这个限制;撤销对表的所有访问权限(除所有者/管理员之外的所有数据库用户)并创建一个哈希密码字段而不是字段本身的视图。任何设法从数据库中窃取信息的 SQL 注入攻击都将仅限于窃取密码的哈希值(它甚至可能是哈希键),因为任何 Web 应用程序的数据库用户都无法访问它。表本身.
白名单输入验证
除了在没有其他可能的情况下(例如,当绑定变量不合法时)作为主要防御之外,输入验证还可以作为辅助防御,用于在继续 SQL 查询之前检测未经授权的输入。有关详细信息,请参阅输入验证备忘单。在这里谨慎行事。通过字符串构造将经过验证的数据插入到 SQL 查询中不一定是安全的。
简短的回答?不,它不存在。长答案?没有什么是 100% 安全的;使用准备好的语句几乎可以保证避免 sql 注入,但是像CheatSheetSeries 这样的手册列出了更多的“主要”防御措施和一些额外的防御措施,表明准备好的语句并不总是足够的。
在https://security.stackexchange.com/questions/15214/are-prepared-statements-100-safe-against-sql-injection对此主题进行了讨论,其中给出了一些允许此类攻击的特定情况的示例.