云画册系统 php,企业级源代码安全和质量缺陷扫描分析服务平台-DMSCA体验邀请20200628...

企业级源代码安全和质量缺陷扫描分析服务平台-DMSCA 体验邀请

近几年来,源代码安全和质量分析工具和方案如雨后春笋般冒出,万花齐放,百鸟争鸣。

到底好不好,只有亲身体验,适合自己的才为最好。

端玛企业级源代码安全和质量方案-DMSCA 历经淬炼,为众多知音所喜爱,在此感谢大家

一致关爱,新的 DMSCA 及配套产品将为新老用户再次带来惊奇。

在此防疫不停产,确保信息系统源代码安全,端玛科技自 2020-07-01~2020-08-30 这段期限

内,在线为新老用户提供至少三次免费扫描,有需求者联系我们,竭诚为您们服务,助力您

们开发安全可靠的软件。

欢迎拨打电话:4006091636,客服手机:18500260583

1.系统架构

2.系统组件

1 / 14

3. 规则和描述

4.扫描记录

2 / 14

5. 结果汇总

6. SQL 注入安全漏洞介绍和修复建议

CWE ID: 89

3 / 14

摘要

以用户或者外部不可信来源的输入动态构造 SQL 查询的命令,将可能改变 SQL 查

询语句本来的语义,从而导致执行任意的 SQL 命令。

缺陷描述

SQL injection 错误在以下情况下发生:

1. 数据从一个不可信赖的数据源进入程序。

- 在这种情况下, 静态扫描工具无法确定数据源是否可信赖。

2. 数据用于动态地构造一个 SQL 查询。

示例 1 以下代码动态地构造并执行了一个 SQL 查询,该查询可以搜索与指定名

称相匹配的项。该查询仅会显示条目所有者与被授予权限的当前用户一致的条目。

...

String userName = ctx.getAuthenticatedUserName();

String itemName = request.getParameter("itemName");

String query = "SELECT * FROM items WHERE owner = '"

+ userName + "' AND itemname = '"

+ itemName + "'";

ResultSet rs = stmt.execute(query);

...

这一代码所执行的查询遵循如下方式:

SELECT * FROM items

WHERE owner =

AND itemname = ;

但是,由于这个查询是动态构造的,由一个不变的基查询字符串和一个用户输入

字符串连接而成,因此只有在 itemName 不包含单引号字符时,才会正确执行这一查

询。如果一个用户名为 wiley 的攻击者为 itemName 输入字符串“name' OR

'a'='a”,那么查询就会变成:

SELECT * FROM items

WHERE owner = 'wiley'

AND itemname = 'name' OR 'a'='a';

4 / 14

附加条件 OR 'a'='a' 会使 where 从句永远评估为 true,因此该查询在逻辑上

将等同于一个更为简化的查询:

SELECT * FROM items;

这种查询的简化会使攻击者绕过查询只返回经过验证的用户所拥有的条目的要

求;而现在的查询则会直接返回所有储存在 items 表中的条目,不论它们的所有者

是谁。

示例 2 这个例子指出了将不同的恶意数值传递给在“示例 1”中构造和执行的查

询时所带来的各种影响。如果一个用户名为 wiley 在 itemName 中输入字符串

“name'; DELETE FROM items; --”,则该查询将会变为以下两个:

SELECT * FROM items

WHERE owner = 'wiley'

AND itemname = 'name';

DELETE FROM items;

--'

众多数据库服务器,其中包括 Microsoft(R) SQL Server 2000,都可以一次

性执行多条用分号分隔的 SQL 指令。对于那些不允许运行用分号分隔的批量指令的

数据库服务器,比如 Oracle 和其他数据库服务器,攻击者输入的这个字符串只会

导致错误;但是在那些支持这种操作的数据库服务器上,攻击者可能会通过执行多条

指令而在数据库上执行任意命令。

注意成对的连字符 (--);这在大多数数据库服务器上都表示下面的语句将作为

注释使用,而不能加以执行 [4]。在这种情况下,注释字符的作用就是删除修改的

查询指令中遗留的最后一个单引号。对于那些不允许按照这种方式使用注释的数据

库,通常攻击者会按“示例 1” 的方式进行攻击。如果攻击者输入字符串“name');

DELETE FROM items; SELECT * FROM items WHERE 'a'='a”,则会创建以下三个有

效指令:

SELECT * FROM items

WHERE owner = 'wiley'

AND itemname = 'name'

DELETE FROM items;

5 / 14

SELECT * FROM items WHERE 'a'='a';

有些人认为在移动世界中,典型的 Web 应用程序漏洞(如 SQL injection)

是无意义的 -- 为什么用户要攻击自己?但是,谨记移动平台的本质是从各种来源

下载并在相同设备上运行的应用程序。恶意软件在银行应用程序附近运行的可能性很

高,它们会强制扩展移动应用程序的攻击面(包括跨进程通信)。

示例 3 以下代码对示“示例 1” 进行调整,使其适用于 Android 平台。

...

PasswordAuthentication pa = authenticator.getPasswordAuthentication();

String userName = pa.getUserName();

String itemName = this.getIntent().getExtras().getString("itemName");

String query = "SELECT * FROM items WHERE owner = '"

+ userName + "' AND itemname = '"

+ itemName + "'";

SQLiteDatabase db = this.openOrCreateDatabase("DB", MODE_PRIVATE, null);

Cursor c = db.rawQuery(query, null);

...

修复建议:

造成 SQL injection 攻击的根本原因在于攻击者可以改变 SQL 查询的上下

文,使程序员原本要作为数据解析的数值,被篡改为命令了。当构造一个 SQL 查询

时,程序员应当清楚,哪些输入的数据将会成为命令的一部分,而哪些仅仅是作为数

据。参数化 SQL 指令可以防止直接窜改上下文,避免几乎所有的 SQL injection

攻击。参数化 SQL 指令是用常规的 SQL 字符串构造的,但是当需要加入用户输入

的数据时,它们就需要使用捆绑参数,这些捆绑参数是一些占位符,用来存放随后插

入的数据。换言之,捆绑参数可以使程序员清楚地分辨数据库中的数据,即其中有哪

些输入可以看作命令的一部分,哪些输入可以看作数据。这样,当程序准备执行某个

指令时,它可以详细地告知数据库,每一个捆绑参数所使用的运行时的值,而不会被

解析成对该命令的修改。

可以将“示例 1” 改写成使用参数化 SQL 指令(替代用户输入连续的字符

串),如下所示:

String userName = ctx.getAuthenticatedUserName();

String itemName = request.getParameter("itemName");

String query = "SELECT * FROM items WHERE itemname=? AND owner=?";

PreparedStatement stmt = conn.prepareStatement(query);

stmt.setString(1, itemName);

6 / 14

stmt.setString(2, userName);

ResultSet results = stmt.execute();

...

下面是 Android 的等同内容:

...

PasswordAuthentication pa = authenticator.getPasswordAuthentication();

String userName = pa.getUserName();

String itemName = this.getIntent().getExtras().getString("itemName");

String query = "SELECT * FROM items WHERE itemname=? AND owner=?";

SQLiteDatabase db = this.openOrCreateDatabase("DB", MODE_PRIVATE, null);

Cursor c = db.rawQuery(query, new Object[]{itemName, userName});

...

更加复杂的情况常常出现在报表生成代码中,因为这时需要通过用户输入来改变

SQL 指令的命令结构,比如在 WHERE 条件子句中加入动态的约束条件。不要因为这

一需求,就无条件地接受连续的用户输入,从而创建查询语句字符串。当必须要根据

用户输入来改变命令结构时,可以使用间接的方法来防止 SQL injection 攻击:

创建一个合法的字符串集合,使其对应于可能要加入到 SQL 指令中的不同元素。在

构造一个指令时,可使用来自用户的输入,以便从应用程序控制的值集合中进行选

择。

注意事项:

1. 使用参数化 SQL 指令的一个常见错误是使用由用户控制的字符串来构造 SQL 指

令。这显然背离了使用参数化 SQL 指令的初衷。如果不能确定用来构造参数化指令

的字符串是否由应用程序控制,请不要因为它们不会直接作为 SQL 指令执行,就假

定它们是安全的。务必彻底地检查 SQL 指令中使用的所有由用户控制的字符串,确

保它们不会修改查询的含意。

2. 防范 SQL injection 攻击的另外一种常用方式是使用存储过程。虽然存储过程

可以阻止某些类型的 SQL injection 攻击,但是对于绝大多数攻击仍无能为力。

存储过程有助于避免 SQL injection 的常用方式是限制可作为参数传入的指令类

型。但是,有许多方法都可以绕过这一限制,许多危险的表达式仍可以传入存储过

程。所以再次强调,存储过程在某些情况下可以避免这种攻击,但是并不能完全保护

您的应用系统抵御 SQL injection 的攻击。

框架及场景参考

(一)SQL Injection: Hibernate

7 / 14

Hibernate 是一种 ORMapping 框架,内部可以使用原生 SQL 还有 HQL 语言进行

SQL 操作。

所谓的 HQL 注入,就是指在 Hibernate 中没有对数据进行有效的验证导致恶意数据

进入应用程序中造成的。

请看这段代码:

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException{

response.setContentType(“text/html”);

Configuration configuration = new Configuration();

configuration.configure();

SessionFactory sessionFactory = configuration.buildSessionFactory();

String input = request.getParameter(“sqlin”);

String hqlString = “from classes where name = ‘” + input + “’”;

System.out.println(hqlString);

Session session = sessionFactory.openSession();

List classesLise = session.createQuery(hqlString).list();

for(Classes classes : classesList){

response.getWriter().write(classes.getName());

response.getWriter().print(“
”);

}

session.close();

}

Input 参数即可造成注入。

不过在 Hibernate 中,一般都是在 createQuery 中使用 PDO,使用

setString 填充占位符进行 sql 语句的拼接,如果是这样的话,自然就不存在 SQL

注入,但是不排除有人像上面的图片中的写法。

此外,还需注意 HQL 注入对万能密码、知道表名列名的情况下进行盲注等情况

的发生。

(二)SQL Injection: iBatis Data Map

使用 iBatis Data Map 可以指定 SQL 指令中的动态参数,通常使用 # 字符

来定义它们,如:

SELECT * FROM items WHERE owner = #userName#

8 / 14

变量名称周围的 # 字符表示 iBatis 将使用 userName 变量创建参数化查询。

但是,iBatis 还允许使用 $ 字符将变量直接连接到 SQL 指令,使其易受 SQL

injection 攻击。

示例 4 以下代码动态地构造并执行了一个 SQL 查询,该查询可以搜索与指定名

称相匹配的项。该查询仅会显示条目所有者与被授予权限的当前用户一致的条目。

SELECT * FROM items WHERE owner = #userName# AND itemname = '$itemName$'

但是,由于这个查询是动态构造的,由一个不变的基查询字符串和一个用户输入

字符串连接而成,因此只有在 itemName 不包含单引号字符时,才会正确执行这一查

询。如果一个用户名为 wiley 的攻击者为 itemName 输入字符串“name' OR

'a'='a”,那么查询就会变成:

SELECT * FROM items

WHERE owner = 'wiley'

AND itemname = 'name' OR 'a'='a';

附加条件 OR 'a'='a' 会使 where 从句永远评估为 true,因此该查询在逻辑

上将等同于一个更为简化的查询:

SELECT * FROM items;

这种查询的简化会使攻击者绕过查询只返回经过验证的用户所拥有的条目的要

求;而现在的查询则会直接返回所有储存在 items 表中的条目,不论它们的所有者

是谁。

(三)SQL Injection: JDO

使用 Java 数据对象 (JDO) 执行通过不可信来源的输入构建的动态 SQL 或

JDOQL 指令,会让攻击者有机会篡改指令的含义或者执行任意 SQL 命令。

示例 5 以下代码动态地构造并执行了一个 SQL 查询,该查询可以搜索与指定名

称相匹配的项。该查询仅会显示条目所有者与被授予权限的当前用户一致的条目。

...

String userName = ctx.getAuthenticatedUserName();

String itemName = request.getParameter("itemName");

9 / 14

String sql = "SELECT * FROM items WHERE owner = '"

+ userName + "' AND itemname = '"

+ itemName + "'";

Query query = pm.newQuery(Query.SQL, sql);

query.setClass(Person.class);

List people = (List)query.execute();

...

这一代码所执行的查询遵循如下方式:

SELECT * FROM items

WHERE owner =

AND itemname = ;

但是,由于这个查询是动态构造的,由一个不变的基查询字符串和一个用户输入

字符串连接而成,因此只有在 itemName 不包含单引号字符时,才会正确执行这一查

询。如果一个用户名为 wiley 的攻击者为 itemName 输入字符串“name' OR

'a'='a”,那么查询就会变成:

SELECT * FROM items

WHERE owner = 'wiley'

AND itemname = 'name' OR 'a'='a';

附加条件 OR 'a'='a' 会使 where 从句永远评估为 true,因此该查询在逻辑

上将等同于一个更为简化的查询:

SELECT * FROM items;

这种查询的简化会使攻击者绕过查询只返回经过验证的用户所拥有的条目的要

求;而现在的查询则会直接返回所有储存在 items 表中的条目,不论它们的所有者

是谁。

(四)SQL Injection: MyBatis Mapper

使用 MyBatis Mapper XML 文件可以指定 SQL 指令中的动态参数,通常使用

# 字符来定义它们,如:

resultType="MyResultMap">

SELECT *

10 / 14

FROM items

WHERE owner = #{userName}

变量名称周围带有括号的 # 字符表示 MyBatis 将使用 userName 变量创建参

数化查询。但是,MyBatis 还允许使用 $ 字符将变量直接连接到 SQL 指令,使其

易受 SQL injection 攻击。

示例 6 以下代码动态地构造并执行了一个 SQL 查询,该查询可以搜索与指定名

称相匹配的项。该查询仅会显示条目所有者与被授予权限的当前用户一致的条目。

resultType="MyResultMap">

SELECT *

FROM items

WHERE owner = #{userName}

AND itemname = ${itemName}

但是,由于这个查询是动态构造的,由一个不变的基查询字符串和一个用户输入

字符串连接而成,因此只有在 itemName 不包含单引号字符时,才会正确执行这一查

询。如果一个用户名为 wiley 的攻击者为 itemName 输入字符串“name' OR

'a'='a”,那么查询就会变成:

SELECT * FROM items

WHERE owner = 'wiley'

AND itemname = 'name' OR 'a'='a';

附加条件 OR 'a'='a' 会使 where 从句永远评估为 true,因此该查询在逻辑

上将等同于一个更为简化的查询:

SELECT * FROM items;

这种查询的简化会使攻击者绕过查询只返回经过验证的用户所拥有的条目的要

求;而现在的查询则会直接返回所有储存在 items 表中的条目,不论它们的所有者

是谁。

(五)SQL Injection: Persistence

使用 Java J2EE Persistence API 来执行通过不可信来源的输入构建的动态

11 / 14

SQL 语句会使得攻击者能够篡改语句的含义或者执行任意 SQL 命令。

示例 7 以下代码动态地构造并执行了一个 SQL 查询,该查询可以搜索与指定名

称相匹配的项。该查询仅会显示条目所有者与被授予权限的当前用户一致的条目。

...

String userName = ctx.getAuthenticatedUserName();

String itemName = request.getParameter("itemName");

String query = "SELECT * FROM items WHERE owner = '"

+ userName + "' AND itemname = '"

+ itemName + "'";

List items = entManager.createQuery(query).getResultList();

...

这一代码所执行的查询遵循如下方式:

SELECT * FROM items

WHERE owner =

AND itemname = ;

但是,由于这个查询是动态构造的,由一个不变的基查询字符串和一个用户输入

字符串连接而成,因此只有在 itemName 不包含单引号字符时,才会正确执行这一查

询。如果一个用户名为 wiley 的攻击者为 itemName 输入字符串“name' OR

'a'='a”,那么查询就会变成:

SELECT * FROM items

WHERE owner = 'wiley'

AND itemname = 'name' OR 'a'='a';

附加条件 OR 'a'='a' 会使 where 从句永远评估为 true,因此该查询在逻辑

上将等同于一个更为简化的查询:

SELECT * FROM items;

这种查询的简化会使攻击者绕过查询只返回经过验证的用户所拥有的条目的要

求;而现在的查询则会直接返回所有储存在 items 表中的条目,不论它们的所有者

是谁。

7. 应用安全策略框架

12 / 14

8. Java 安全策略范围举例

13 / 14

9. 企业安全开发技术标准实现

14 / 14

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值