利用存储过程增强web服务的安全
1 简介
使用存储过程防范针对web服务的注入攻击
如果应用程序具有使用字符串串联和用户提供的输入的动态数据库查询,则攻击者可以在应用程序上使用 SQL 注入。
为避免 SQL 注入缺陷,开发人员需要:
停止编写带有字符串串联的动态查询,或者防止恶意 SQL 输入包含在已执行的查询中。
有一些简单的技术可以防止 SQL 注入漏洞,它们几乎可以与任何类型的编程语言和任何类型的数据库一起使用。
虽然 XML 数据库可能存在类似的问题(例如,XPath 和 XQuery 注入),但也可以使用这些技术来保护它们。
除了前面一节所讲的参数化查询方法,我们还可以利用数据库的存储过程进行校验。
尽管存储过程并不总是不受 SQL 注入的影响,但开发人员可以使用某些标准的存储过程编程结构。
只要安全地实现存储过程,此方法与使用参数化查询具有相同的效果(这是大多数存储过程语言的标准)。
如果需要存储过程,使用它们的最安全方法是开发人员使用自动参数化的参数构建 SQL 语句,除非开发人员做了一些非常不正常的事情。
参数化查询和存储过程之间的区别在于,存储过程的 SQL 代码是定义并存储在数据库本身中,然后从应用程序中调用的。
由于参数化查询语句和安全的存储过程在防止 SQL 注入方面同样有效,因此应该选择最适合实际场景的方法。
2 一个存储过程使用示例
- 原理
存储过程是预定义在数据库中的SQL语句,通过调用存储过程的名称传递参数,不直接嵌入用户输入,减少SQL注入风险。
- 实现方式
通过数据库创建存储过程,并在Go代码中调用。
示例:创建存储过程
DELIMITER //
CREATE PROCEDURE GetUser(IN userId INT)
BEGIN
SELECT username FROM users WHERE id = userId;
END //
DELIMITER ;
调用存储过程
r.GET("/user", func(c *gin.Context) {
id := c.Query("id")
var username string
// 调用存储过程
err := db.QueryRow("CALL GetUser(?)", id).Scan(&username)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "User not found"})
return
}
c.JSON(http.StatusOK, gin.H{"username": username})
})
3 小结
存储过程在多数时候是安全的,因为远离了用户操作接口。
有时,某些场景下当系统受到攻击时,存储过程可能会增加风险。
例如,在 MS SQL Server 上,如果系统有三个主要的默认角色:db_datareader.db_datawriter和db_owner.
在存储过程开始使用之前,DBA 将根据需求向 Web 服务的用户授予 db_datareader OR db_datawriter权限。
默认情况下,该web用户的角色不可执行,但是,存储过程需要执行权限。
在某些用户管理已集中但仅限于这 3 个角色的设置中,Web 应用程序必须按权限级别运行,以便存储过程可以工作。
自然,这意味着如果服务器遭到破坏,攻击者拥有db_owner对数据库的完全权限,而以前他们可能只有读取访问权限。
- 点赞
- 收藏
- 关注作者
评论(0)