哈尔滨无障碍网站建设,外贸自建站多久能出单,wordpress 刷新缓存,荆州seo1.1 .Sql 注入攻击原理
SQL 注入漏洞可以说是在企业运营中会遇到的最具破坏性的漏洞之一#xff0c;它也是目前被利用得最多的漏洞。要学会如何防御 SQL 注入#xff0c;首先我们要学习它的原理。 针对 SQL 注入的攻击行为可描述为通过在用户可控参数中注入 SQL 语法#x…1.1 .Sql 注入攻击原理
SQL 注入漏洞可以说是在企业运营中会遇到的最具破坏性的漏洞之一它也是目前被利用得最多的漏洞。要学会如何防御 SQL 注入首先我们要学习它的原理。 针对 SQL 注入的攻击行为可描述为通过在用户可控参数中注入 SQL 语法破坏原有 SQL 结构达到编写程序时意料之外结果的攻击行为。其成因可以归结为以下两个原因叠加造成的 程序编写者在处理应用程序和数据库交互时使用字符串拼接的方式构造 SQL 语句。未对用户可控参数进行足够的过滤便将参数内容拼接进入到 SQL 语句中。注入攻击的本质是把用户输入的数据当做代码执行。这里有两个关键条件用户能够控制输入。原本程序要执行的代码拼接了用户输入的数据。 1.2 .Sql 审计方法
手动找的话可以直接找到 sqlmapper.xml 文件或者直接搜索 select、update、delete、insert “String sql”等关键词定位 SQL xml 配置文件。 如果 sql 语句中有出现 $ 进行参数拼接则存在 SQL 注入风险。 当找到某个变量关键词有 SQL 注入风险时可以再根据调用链找到该存在注入风险的业务逻辑代码查看参数来源是否安全、是否有配置 SQL 危险参数过滤的过滤器最终确认是否存在 SQL 注入。以下给出可能造成 sql 注入攻击的关键字审计时可根据实际情况进项查找 常见 SQL 语句关键词 【一一帮助安全学习,所有资源一一】①网络安全学习路线②20 份渗透测试电子书③安全攻防 357 页笔记④50 份安全攻防面试指南⑤安全红队渗透工具包⑥网络安全必备书籍⑦100 个漏洞实战案例⑧安全大厂内部教程 1.3Sql 注入漏洞危害
1 、 攻击者可以做到 业务运营的所有数据被攻击 对当前数据库用户拥有的所有表数据进行增、删、改、查等操作 若当前数据库用户拥有 file_priv 权限攻击者可通过植入木马的方式进一步控制 DB 所在服务器 若当前数据库用户为高权限用户攻击者甚至可以直接执行服务器命令从而通过该漏洞直接威胁整个内网系统 2、可能对业务造成的影响 ① 用户信息被篡改 ② 攻击者偷取代码和用户数据恶意获取 线上代码被非法篡改并造成为恶意攻击者输送流量或其他利益的影响
1.4 Sql 注入漏洞代码示例
Java 代码动态构建 SQL
Statement stmt null;
ResultSet rs null;
try{
String userName ctx.getAuthenticatedUserName(); //this is a constant
String sqlString SELECT * FROM t_item WHERE owner userName AND itemName request.getParameter(itemName) ;
stmt connection.createStatement();
rs stmt.executeQuery(sqlString);
// ... result set handling
}
catch (SQLException se){
// ... logging and error handling
}复制代码 这里将查询字符串常量与用户输入进行拼接来动态构建 SQL 查询命令。仅当 itemName 不包含单引号时这条查询语句的行为才会是正确的。如果一个攻击者以用户名 wiley 发起一个请求并使用以下条目名称参数进行查询 name OR a a复制代码 那么这个查询将变成 SELECT * FROM t_item WHERE owner wiley AND itemname name OR aa;复制代码 此处额外的 OR aa条件导致整个 WHERE 子句的值总为真。那么这个查询便等价于如下非常简单的查询 SELECT * FROM t_item复制代码 这个简化的查询使得攻击者能够绕过原有的条件限制这个查询会返回 items 表中所有储存的条目而不管它们的所有者是谁而原本应该只返回属于当前已认证用户的条目。 在存储过程中动态构建 SQL Java 代码 CallableStatement null
ResultSet results null;
try
{
String userName ctx.getAuthenticatedUserName(); //this is a constant
String itemName request.getParameter(itemName);
cs connection.prepareCall({call sp_queryItem(?,?)});
cs.setString(1, userName);
cs.setString(2, itemName);
results cs.executeQuery();
// ... result set handling
}
catch (SQLException se)
{
// ... logging and error handling
}
SQL Server存储过程
CREATE PROCEDURE sp_queryItem
userName varchar(50),
itemName varchar(50)
AS
BEGIN
DECLARE sql nvarchar(500);
SET sql SELECT * FROM t_item
WHERE owner userName
AND itemName itemName ;
EXEC(sql);
END
GO复制代码 在存储过程中通过拼接参数值来构建查询字符串和在应用程序代码中拼接参数一样同样是有 SQL 注入风险的。
Hibernate 动态构建 SQL/HQL
原生 SQL 查询 String userName ctx.getAuthenticatedUserName(); //this is a constant
String itemName request.getParameter(itemName);
Query sqlQuery session.createSQLQuery(select * from t_item where owner userName and itemName itemName );
ListItem rs (ListItem) sqlQuery.list();复制代码 HQL 查询 String userName ctx.getAuthenticatedUserName(); //this is a constant
String itemName request.getParameter(itemName);
Query hqlQuery session.createQuery(from Item as item where item.owner userName and item.itemName itemName );
ListItem hrs (ListItem) hqlQuery.list();复制代码 即使是使用 Hibernate如果在动态构建 SQL/HQL 查询时包含了不可信输入同样也会面临 SQL/HQL 注入的问题。 HQL 代码中session.createQuery 使用 HQL 语句将查询到的数据存到到 list 集合中需要时在拿出来使用。而参数中 itemName 是通过 request.getParameter 直接获取。攻击者若在此处写入恶意语句程序将恶意语句查询出来的数据存放在 list 集合中再通过某处调用成功将数据显示在前台。
Mybatis 注入分析
Mybatis 框架下易产生 SQL 注入漏洞的情况主要分为以下三种 1模糊查询 like 例如对人员姓名检索进行模糊查询如果考虑安全编码规范问题其对应的 SQL 语句如下 Select * from user where name like %#{name}%复制代码 但由于这样写程序会报错研发人员将 SQL 查询语句修改如下 Select * from user where name like %${name}%复制代码 在这种情况下我们发现程序不再报错但是此时产生了 SQL 语句拼接问题如果 java 代码层面没有对用户输入的内容做处理势必会产生 SQL 注入漏洞。 2in 之后的参数 例如对人员姓名进行同条件多值检索的时候如当用户输入 001,002,003...时如果考虑安全编码规范问题其对应的 SQL 语句如下 Select * from name where id in (#{id})复制代码 但由于这样写程序会报错研发人员将 SQL 查询语句修改如下 Select * from name where id in (${id})复制代码 修改 SQL 语句之后程序停止报错但是却引入了 SQL 语句拼接的问题如果没有对用户输入的内容做过滤势必会产生 SQL 注入漏洞。 3order by 之后(重点和区分点) 当根据姓名、id 序号等信息用户进行排序的时候如果考虑安全编码规范问题其对应的 SQL 语句如下 Select * from user where name qihoo order by #{id} desc复制代码 但由于发布时间 id 不是用户输入的参数无法使用预编译。研发人员将 SQL 查询语句修改如下 Select * from user where name qihoo order by ${id} desc复制代码 修改之后程序未通过预编译但是产生了 SQL 语句拼接问题极有可能引发 SQL 注入漏洞。
1.5 .实战案例-OFCMS SQL 注入漏洞分析
本文中使用 ofcms 进行 SQL 注入漏洞讲解此 CMS 算是对新手学习代码审计比较友好的 CMS。 上述为安装成功页面如何安装 CMS 本章不在赘述。 后台页面http://localhost:8080/ofcms-admin/admin/index.html 漏洞点 ofcms-admin/src/main/java/com/ofsoft/cms/admin/controller/system/SystemGeneratrController.java
create方法
|
/**
* 创建表
*/
public void create() {
try {
String sql getPara(sql);
Db.update(sql);
rendSuccessJson();
} catch (Exception e) {
e.printStackTrace();
rendFailedJson(ErrorCode.get(9999), e.getMessage());
}
}复制代码 上述代码中使用 getpara 获取 sql 的参数值并 update跟进一下 getpara 和 update 方法。 跳转至 jfinal-3.2.jar/com/jfinal/core/controller.class public String getPara(String name) {
return this.request.getParameter(name);
}复制代码 上述代码无特殊用意就是获取参数值继续跟进 Db.update 方法。 跳转至 jfinal-3.2.jar/com/jfinal/plugin/activerecord/Db.class public static int update(String sql) {
return MAIN.update(sql);
}复制代码 发现调用 MAIN.update , 继续跟进。 跳转至 jfinal-3.2.jar/com/jfinal/plugin/activerecord/DbPro.class public int update(String sql) {
return this.update(sql, DbKit.NULL_PARA_ARRAY);
}复制代码 继续跟进到最后发现华点。 public int update(String sql, Object... paras) {
Connection conn null;
int var4;
try {
conn this.config.getConnection();//连接
var4 this.update(this.config, conn, sql, paras);//调用update更新
} catch (Exception var8) {
throw new ActiveRecordException(var8);
} finally {
this.config.close(conn);
}
return var4;
}复制代码 重点Object... Object 是所有类的基类而 Object... 是不确定方法参数情况下的一种多态表现形式(可以传递多个参数)。 再继续跟进 update 同文件代码 int update(Config config, Connection conn, String sql, Object... paras) throws SQLException {
PreparedStatement pst conn.prepareStatement(sql);
config.dialect.fillStatement(pst, paras);
int result pst.executeUpdate();
DbKit.close(pst);
return result;
}复制代码 上述代码执行 SQL 语句并返回结果。 至此整个功能流程结束在我们跟进的过程中代码中无任何过滤语句获取参数值调用 update 方法更新更新成功后返回结果。
漏洞验证 漏洞点打上断点网页中输入 poc 进行验证 update of_cms_topic set topic_urlupdatexml(1,concat(0x7e,(user())),0) where topic_id 1复制代码 根据如上截图可看出我们传入的 SQL 语句是被完整的接收并未做任何过滤直接带入数据库执行所以此处直接写入漏洞代码爆出当前数据库账户为 root。 上述为 sqlmap 工具跑出来的注入点。
1.6 漏洞修复方法
添加全局过滤器过滤特殊字符 SQLFilter.java 中 PreparedStatement 参数化
如果使用参数化查询则在 SQL 语句中使用占位符表示需在运行时确定的参数值。参数化查询使得 SQL 查询的语义逻辑被预先定义而实际的查询参数值则等到程序运行时再确定。参数化查询使得数据库能够区分 SQL 语句中语义逻辑和数据参数以确保用户输入无法改变预期的 SQL 查询语义逻辑。 在 Java 中可以使用 java.sql.PreparedStatement 来对数据库发起参数化查询。在这个正确示例中如果一个攻击者将 itemName 输入为 name OR a a这个参数化查询将免受攻击而是会查找一个 itemName 匹配 name OR a a 这个字符串的条目。 PreparedStatement stmt null
ResultSet rs null
try
{
String userName ctx.getAuthenticatedUserName(); //this is a constant
String itemName request.getParameter(itemName);
// ...Ensure that the length of userName and itemName is legitimate
// ...
String sqlString SELECT * FROM t_item WHERE owner? AND itemName?;
stmt connection.prepareStatement(sqlString);
stmt.setString(1, userName);
stmt.setString(2, itemName);
rs stmt.executeQuery();
// ... result set handling
}
catch (SQLException se)
{
// ... logging and error handling
}复制代码
存储过程参数化
这个存储过程使用参数化查询而未包含不安全的动态 SQL 构建。数据库编译此存储过程时会生成一个 SELECT 查询的执行计划只允许原始的 SQL 语义被执行。任何参数值即使是被注入的 SQL 语句也不会被执行因为它们不是执行计划的一部分。 CallableStatement null
ResultSet results null;
try
{
String userName ctx.getAuthenticatedUserName(); //this is a constant
String itemName request.getParameter(itemName);
// ... Ensure that the length of userName and itemName is legitimate
// ...
cs connection.prepareCall({call sp_queryItem(?,?)});
cs.setString(1, userName);
cs.setString(2, itemName);
results cs.executeQuery();
// ... result set handling
}
catch (SQLException se)
{
// ... logging and error handling
}复制代码
Hibernate 参数化查询
Hibernate 支持 SQL/HQL 参数化查询。为了防止 SQL 注入以及改善性能以上这些示例使用了参数化绑定 的方式来设置查询参数。 String userName ctx.getAuthenticatedUserName(); //this is a constant
String itemName request.getParameter(itemName);
Query hqlQuery session.createQuery(from Item as item where item.owner ? and item.itemName ?);
hqlQuery.setString(1, userName);
hqlQuery.setString(2, itemName);
ListItem rs (ListItem) hqlQuery.list();复制代码 HQL 基于名称的参数化查询 String userName ctx.getAuthenticatedUserName(); //this is a constant
String itemName request.getParameter(itemName);
Query hqlQuery session.createQuery(from Item as item where item.owner :owner and item.itemName :itemName);
hqlQuery.setString(owner, userName);
hqlQuery.setString(itemName, itemName);
ListItem rs (ListItem) hqlQuery.list();复制代码 原生参数化查询 String userName ctx.getAuthenticatedUserName(); //this is a constant
String itemName request.getParameter(itemName);
Query sqlQuery session.createSQLQuery(select * from t_item where owner ? and itemName ?);
sqlQuery.setString(0, owner);
sqlQuery.setString(1, itemName);
ListItem rs (ListItem) sqlQuery.list();复制代码
MyBatis 框架的修复方案
尽量使用 #描述参数如果一定要使用 $则需要自己过滤用户输入 模糊查询 like SQL 注入修复建议 按照新闻标题对新闻进行模糊查询可将 SQL 查询语句设计如下 select * from news where name like concat(‘%’,#{name }, ‘%’)复制代码 采用预编译机制避免了 SQL 语句拼接的问题从根源上防止了 SQL 注入漏洞的产生。 in 之后的参数 SQL 注入修复建议 在对新闻进行同条件多值查询的时候可使用 Mybatis 自带循环指令解决 SQL 语句动态拼接的问题 select * from news where id inforeach collectionids itemitem open(separator, close)#{item} /foreach复制代码 order by SQL 注入修复建议 在 Java 层面做映射预编译机制只能处理查询参数其他地方还需要研发人员根据具体情况来解决。如前面提到的排序情景 Select * from news where title ‘淘宝’ order by #{time} asc复制代码 这里 time 不是查询参数无法使用预编译机制只能这样拼接 Select * from news where title ‘淘宝’ order by ${time} asc复制代码 针对这种情况研发人员可以在 java 层面做映射来进行解决。如当存在发布时间 time 和点击量 click 两种排序选择时我们可以限制用户只能输入 1 和 2。 当用户输入 1 时我们在代码层面将其映射为 time当用户输入 2 时将其映射为 click。而当用户输入 1 和 2 之外的其他内容时我们可以将其转换为默认排序选择 time(或者 click)。