常见的Java审计代码函数关键字_转载:Java代码审计汇总系列(一)——SQL注入

原文链接:https://cloud.tencent.com/developer/article/1534109

b35d23c1c06220aeb72fe4addeab5efe.png

一、代码审计

相比黑盒渗透的漏洞挖掘方式,代码审计具有更高的可靠性和针对性,更多的是依靠对代码、架构的理解;使用的审计工具一般选择Eclipse或IDEA;审计工作过程主要有三步:风险点发现——>风险定位追踪——>漏洞利用,所以审计不出漏洞无非就是find:“找不到该看哪些代码”和judge:“定位到代码但判断不出有没有问题”。而风险点发现的重点则在于三个地方:用户输入(入参)处+检测绕过处+漏洞触发处,一般审计代码都是借助代码扫描工具(Fortify/Checkmarx)或从这三点着手。

本系列选取WebGoat作为案例,讲解漏洞的特征发现、定位技巧、调试及触发利用的具体过程,尽量涵盖所有的挖掘场景,最后补充实战挖掘案例。

二、SQLi漏洞挖掘

1、介绍

SQLi是最著名也是影响最广的漏洞之一,注入漏洞都是程序把用户输入的数据当做代码执行,发现的关键有两个,第一是用户能够控制输入;第二是用户输入的数据被拼接到要执行的代码中从而被执行。

2、挖掘过程

这里以webgoat的数字型注入讲解SQLi漏洞的挖掘过程:

ee0971bf1cd40540c9674a8482396842.png

1) 定位特定功能模块的代码

了解不同框架特性,本系统的Springboot注解:

@RequestMapping(path= PATH)

@GetMapping(path= PATH)

@PostMapping(path= PATH)

通过抓取请求数据包获取path特征SqlInjection/assignment5b:

1620

使用IDEA的全局搜索功能(SHIFT+CTRL+F)定位到代码:

1620

2) 代码分析

SqlInjectionLesson5b.java类代码如下:

@PostMapping("/SqlInjection/assignment5b")

@ResponseBody

public AttackResult completed(@RequestParam String userid, @RequestParam String login_count, HttpServletRequest request) throws IOException {

return injectableQuery(login_count, userid);

}

protected AttackResult injectableQuery(String login_count, String accountName) {

String queryString = "SELECT * From user_data WHERE Login_Count = ? and userid= " + accountName;

try {

Connection connection = DatabaseUtilities.getConnection(getWebSession());

PreparedStatement query = connection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_READ_ONLY);

这是一个典型的动态拼接用户输入和防范案例,系统接收两个参数login_count和userid,其中login_count通过“+”直接拼接,而userid首先通过类型转换为Integer赋值给count,并经过了预编译(参数化请求)处理,不存在SQLi漏洞。

3)漏洞验证

最后构造路径及参数POC验证漏洞存在:

1620

3、漏洞分类挖掘技巧

根据挖掘经验,白盒挖掘层面大致可以将SQLi的类型分为六类:

1、入参直接动态拼接;

2、预编译有误;

3、框架注入(Mybatis+Hibernate);

4、order by 绕过预编译;

5、%和_绕过预编译;

6、SQLi检测绕过

1) 参数直接拼接

最明显的“+”拼接,思路一般有二:通过关键字定位到SQL语句,回溯参数是否是用户可控;或通过跟踪用户输入,是否执行SQL操作,搜索的关键词有:

Select|insert|update|delete|java.sql.Connection|Statement|.execute|.executeQuery|jdbcTemplate|queryForInt|queryForObject|queryForMap|getConnection|PreparedStatement|Statement|execute|jdbcTemplate|queryForInt|queryForObject|queryForMap|executeQuery|getConnection

2) 预编译有误

并不是使用了预编译PreparedStatement一定就可以防止SQL注入,动态拼接SQL同样存在SQLi注入,这也是实际审计中高发的问题,下面代码就是典型的预编译有误:

String query = "SELECT * FROM usersWHERE userid ='"+ userid + "'" + " AND password='" +password + "'";

PreparedStatement stmt =connection.prepareStatement(query);

ResultSet rs = stmt.executeQuery();

定位预编译可以通过搜索关键函数:

setObject()、setInt()、setString()、setSQLXML()

3) 框架注入

Hibernate典型的注入代码为:

session.createQuery("from Book wheretitle like '%" + userInput + "%' and published = true")

或形如:

{

StringBuffer queryString = newStringBuffer();

queryString.append(“from Test where id=’”);

queryString.append(id);

queryString.append(‘\’’);

}

定位此框架的SQL注入首先需要在xml配置文件或import包里确认是否使用此框架,然后使用关键字createQuery,session.save(,session.update(,session.delete进行定位。

Mybatis有两种变量方法,不安全的写法为:

select * from books where id= ${id}

安全的写法为JDBC预编译:

select * from books where id= #{id}

此外like、in和order by语句也需要使用#,挖掘技巧则是在注解中或者Mybatis相关的配置文件中搜索 $。

4) order by 绕过预编译

类似下面sql语句 order by 后面是不能用预编译处理的只能通过拼接处理,只能手动进行过滤,详见案例。

String sql = “Select * from news where title =?”+ “order by‘” + time + “’asc”

5) %和_绕过预编译

预编译是不能处理%,需要手动过滤,否则会造成慢查询和DOS。

6) SQLi检测绕过

若SQL在处理过程中经过黑/白名单(正则)或Filter检测,通常检测代码存在缺陷则可进行检测绕过。

4、漏洞防御

OWASP官方推荐的SQLi防御方案有四种:

1)预编译(参数化查询)

PreparedStatement stmt =connection.prepareStatement("SELECT * FROM users WHERE userid=? ANDpassword=?");

stmt.setString(1, userid);

stmt.setString(2, password);

ResultSet rs = stmt.executeQuery();

2)存储过程

使用CallableStatement对存储过程接口的实现来执行数据库查询,SQL代码定义并存储在数据库本身中,然后从应用程序中调用,使用存储过程和预编译在防SQLi方面的效果是相同的。

String custname =request.getParameter("customerName");

try {

CallableStatement cs = connection.prepareCall("{callsp_getAccountBalance(?)}");

cs.setString(1, custname);

ResultSet results = cs.executeQuery();

} catch (SQLException se) {

}

3)黑/白名单验证

属于输入验证的范畴,大多使用正则表达式限制,或对于诸如排序顺序之类的简单操作,最好将用户提供的输入转换为布尔值,然后将该布尔值用于选择要附加到查询的安全值。

public String someMethod(boolean sortOrder) {

String SQLquery = "someSQL ... order by Salary " + (sortOrder ? "ASC" :"DESC");`

4) 输出转义

将用户输入放入查询之前对其进行转义,OWASP企业安全性API(ESAPI)是一个免费的开源Web应用程序安全控制库。

CodecORACLE_CODEC = new OracleCodec();

Stringquery = "SELECT user_id FROM user_data WHERE user_name = '"

+ESAPI.encoder().encodeForSQL( ORACLE_CODEC,req.getParameter("userID"))

+ "'and user_password = '"

+ ESAPI.encoder().encodeForSQL( ORACLE_CODEC,req.getParameter("pwd")) +"'";

5)框架修复:

对于Mybatis框架:

select * from news where tile like concat(‘%’,#{title}, ‘%’),

select * from news where id in

#{item}

Mybatis的order by语句可以选择在java层做映射或过滤用户输入进行防御。

对于Hibernate(HQL)框架预编译:

方法一:

Query query=session.createQuery(“from Useruser where user.name=:customername and user:customerage=:age ”);

query.setString(“customername”,name);

query.setInteger(“customerage”,age);

方法二:

String hql ="FROM User user where user.name=? and user.age=?";

Query q =session.createQuery(hql);

q.setString(0, name);

q.setInteger(1,age);

5、实战案例

1) Mybatis框架

对文章删除功能进行审计,articelId参数前端可控:

@RequestMapping("/delete")

public ModelAndView delete(HttpServletRequestrequest) {

ModelAndView model = newModelAndView();

try {

model.setViewName(this.getRequestUri(request));

String[] aridArr = request.getParameterValues("articelId");

if (aridArr != null&& aridArr.length > 0) {

this.deleteArticle(aridArr);

}

} catch (Exception e) {

model.setViewName(this.setExceptionRequest(request,e));

logger.error("AdminArticleController.delete()--error",e);

}

return model;

}

顺着变量的走向进行审计,articelId赋值给aridArr,而后进行了为空的判断,不为空则执行deleteArticle操作,跟踪定位此函数:

private void deleteArticle(String[]artidArr) {

//删除数据中记录

articleService.deleteArticleByIds(artidArr);

EHCacheUtil.remove(CacheConstans.ARTICLE_GOOD_RECOMMEND);

继续跟踪操作,articleService类的deleteArticleByIds函数,继而进入DAO层,在ArticleDaoImpl.java内:

public void deleteArticleByIds(StringarticleIds) {

this.delete("ArticleMapper.deleteArticleByIds",articleIds);

}

进入ArticleMapper.xml,最终追踪到deleteArticleByIds的SQL语句,使用了$拼接,典型的Mybatis注入:

DELETEFROM EDU_ARTICLE WHERE EDU_ARTICLE.ARTICLE_ID IN (${value})

除了顺向思维,还可以通过逆向思维挖掘,pom.xml中看到系统使用的是Mybatis框架,可以直接去审查Maper.xml文件,查看是否使用$拼接:

UTF-8

3.2.12.RELEASE

3.2.7

1.7.3

1.7

2) Order by绕过预编译

Webgoat一个order by的案例:

1620

order by的参数orderExpression可以是一个selectExpression也可以是一个函数,比如使用一个case语句。

案例中可以根据IP或ID对数据进行排序:

1620

对应代码为Server.java:

@GetMapping(produces =MediaType.APPLICATION_JSON_VALUE)

@SneakyThrows

@ResponseBody

public List sort(@RequestParamString column) {

Connection connection = DatabaseUtilities.getConnection(webSession);

PreparedStatement preparedStatement =connection.prepareStatement("select id, hostname, ip, mac, status, descriptionfrom servers where status <> 'outof order' order by " + column);

ResultSet rs = preparedStatement.executeQuery();

List servers = Lists.newArrayList();

while (rs.next()) {

Server server = new Server(rs.getString(1), rs.getString(2),rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(6));

servers.add(server);

}

虽使用了预编译但仍拼接了order by参数column,使用case探测语句探测:(case when (true) then id else ip end),如果真则以id排序,结果为:

1620

3) 预编译有误

查看FAQ页面数据功能getFaqPage函数,前端获取page等参数:

publicFaqPageInfo getFaqPage(String tenantId, Map conditions,int page, int pageSize, String like) {

try {

tenantId= WebUtil.getLoginTenantId();

FaqPageInfo fpi =FAQ_IO_SERVICE.getPageInfo(tenantId, conditions, page, pageSize, like);

for (FaqModel fm : fpi.getData()) {

fm.setWhitelistIds(WHITELIST_SERVICE.getWhiteListOnFaq(tenantId,fm.getId()));

}

return fpi;

}

跟踪FAQ_IO_SERVICE.getPageInfo,调用FaqSqlAccess.queryByPage进行处理:

public FaqPageInfo getPageInfo(StringtenantId, Map conditions, int page, int pageSize, Stringlike)

throws SQLException {

FaqPageInfo pageInfo = new FaqPageInfo();

pageInfo.setData(FaqSqlAccess.queryByPage(tenantId, conditions, page,pageSize, like));

pageInfo.setTotalSize(FaqSqlAccess.queryCount(tenantId, conditions,like));

return pageInfo;

}

找到FaqSqlAccess.java里的queryByPage方法,追踪到SQL语句:

public static ListqueryByPage(String tenantId, Map conditions, int page,int pageSize, String like)

throws SQLException {

List models = new ArrayList<>();

String language = conditions.get("language");

Connection connection = null;

PreparedStatement stmt = null;

try {

connection = MysqlUtils.getConnection();

String sql = "select id, name, description, language, update_time,is_on from TOC_FAQ where tenant_id=?";

if (!CommonUtils.isEmptyStr(language))

sql += " andlanguage='" + language + "'";

if (!CommonUtils.isEmptyStr(like))

sql += " and name like'%" + like + "%'";

sql += " order by update_time desc limit ?,?";

stmt = connection.prepareStatement(sql);

stmt.setString(1, tenantId);

stmt.setInt(2, (page - 1) * pageSize);

stmt.setInt(3, pageSize);

ResultSet resultSet = stmt.executeQuery();

发现此处使用了预编译,但language和like参数实际是直接拼接,存在SQL注入,对于getFaqPage功能构造参数"language":"'-if(substring(user(),1,1)=0x01,sleep(5),0)-'"}进行验证。

简单或复杂的SQL注入漏洞原理和审计方法相同,只是对于业务繁杂的系统,数据的走向和处理过程会比较复杂,调用链跟踪难度会稍大一些,需要更多耐心。

1620

一、代码审计

相比黑盒渗透的漏洞挖掘方式,代码审计具有更高的可靠性和针对性,更多的是依靠对代码、架构的理解;使用的审计工具一般选择Eclipse或IDEA;审计工作过程主要有三步:风险点发现——>风险定位追踪——>漏洞利用,所以审计不出漏洞无非就是find:“找不到该看哪些代码”和judge:“定位到代码但判断不出有没有问题”。而风险点发现的重点则在于三个地方:用户输入(入参)处+检测绕过处+漏洞触发处,一般审计代码都是借助代码扫描工具(Fortify/Checkmarx)或从这三点着手。

本系列选取WebGoat作为案例,讲解漏洞的特征发现、定位技巧、调试及触发利用的具体过程,尽量涵盖所有的挖掘场景,最后补充实战挖掘案例。

二、SQLi漏洞挖掘

1、介绍

SQLi是最著名也是影响最广的漏洞之一,注入漏洞都是程序把用户输入的数据当做代码执行,发现的关键有两个,第一是用户能够控制输入;第二是用户输入的数据被拼接到要执行的代码中从而被执行。

2、挖掘过程

这里以webgoat的数字型注入讲解SQLi漏洞的挖掘过程:

1620

1) 定位特定功能模块的代码

了解不同框架特性,本系统的Springboot注解:

@RequestMapping(path= PATH)

@GetMapping(path= PATH)

@PostMapping(path= PATH)

通过抓取请求数据包获取path特征SqlInjection/assignment5b:

1620

使用IDEA的全局搜索功能(SHIFT+CTRL+F)定位到代码:

1620

2) 代码分析

SqlInjectionLesson5b.java类代码如下:

@PostMapping("/SqlInjection/assignment5b")

@ResponseBody

public AttackResult completed(@RequestParam String userid, @RequestParam String login_count, HttpServletRequest request) throws IOException {

return injectableQuery(login_count, userid);

}

protected AttackResult injectableQuery(String login_count, String accountName) {

String queryString = "SELECT * From user_data WHERE Login_Count = ? and userid= " + accountName;

try {

Connection connection = DatabaseUtilities.getConnection(getWebSession());

PreparedStatement query = connection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_READ_ONLY);

这是一个典型的动态拼接用户输入和防范案例,系统接收两个参数login_count和userid,其中login_count通过“+”直接拼接,而userid首先通过类型转换为Integer赋值给count,并经过了预编译(参数化请求)处理,不存在SQLi漏洞。

3)漏洞验证

最后构造路径及参数POC验证漏洞存在:

1620

3、漏洞分类挖掘技巧

根据挖掘经验,白盒挖掘层面大致可以将SQLi的类型分为六类:

1、入参直接动态拼接;

2、预编译有误;

3、框架注入(Mybatis+Hibernate);

4、order by 绕过预编译;

5、%和_绕过预编译;

6、SQLi检测绕过

1) 参数直接拼接

最明显的“+”拼接,思路一般有二:通过关键字定位到SQL语句,回溯参数是否是用户可控;或通过跟踪用户输入,是否执行SQL操作,搜索的关键词有:

Select|insert|update|delete|java.sql.Connection|Statement|.execute|.executeQuery|jdbcTemplate|queryForInt|queryForObject|queryForMap|getConnection|PreparedStatement|Statement|execute|jdbcTemplate|queryForInt|queryForObject|queryForMap|executeQuery|getConnection

2) 预编译有误

并不是使用了预编译PreparedStatement一定就可以防止SQL注入,动态拼接SQL同样存在SQLi注入,这也是实际审计中高发的问题,下面代码就是典型的预编译有误:

String query = "SELECT * FROM usersWHERE userid ='"+ userid + "'" + " AND password='" +password + "'";

PreparedStatement stmt =connection.prepareStatement(query);

ResultSet rs = stmt.executeQuery();

定位预编译可以通过搜索关键函数:

setObject()、setInt()、setString()、setSQLXML()

3) 框架注入

Hibernate典型的注入代码为:

session.createQuery("from Book wheretitle like '%" + userInput + "%' and published = true")

或形如:

{

StringBuffer queryString = newStringBuffer();

queryString.append(“from Test where id=’”);

queryString.append(id);

queryString.append(‘\’’);

}

定位此框架的SQL注入首先需要在xml配置文件或import包里确认是否使用此框架,然后使用关键字createQuery,session.save(,session.update(,session.delete进行定位。

Mybatis有两种变量方法,不安全的写法为:

select * from books where id= ${id}

安全的写法为JDBC预编译:

select * from books where id= #{id}

此外like、in和order by语句也需要使用#,挖掘技巧则是在注解中或者Mybatis相关的配置文件中搜索 $。

4) order by 绕过预编译

类似下面sql语句 order by 后面是不能用预编译处理的只能通过拼接处理,只能手动进行过滤,详见案例。

String sql = “Select * from news where title =?”+ “order by‘” + time + “’asc”

5) %和_绕过预编译

预编译是不能处理%,需要手动过滤,否则会造成慢查询和DOS。

6) SQLi检测绕过

若SQL在处理过程中经过黑/白名单(正则)或Filter检测,通常检测代码存在缺陷则可进行检测绕过。

4、漏洞防御

OWASP官方推荐的SQLi防御方案有四种:

1)预编译(参数化查询)

PreparedStatement stmt =connection.prepareStatement("SELECT * FROM users WHERE userid=? ANDpassword=?");

stmt.setString(1, userid);

stmt.setString(2, password);

ResultSet rs = stmt.executeQuery();

2)存储过程

使用CallableStatement对存储过程接口的实现来执行数据库查询,SQL代码定义并存储在数据库本身中,然后从应用程序中调用,使用存储过程和预编译在防SQLi方面的效果是相同的。

String custname =request.getParameter("customerName");

try {

CallableStatement cs = connection.prepareCall("{callsp_getAccountBalance(?)}");

cs.setString(1, custname);

ResultSet results = cs.executeQuery();

} catch (SQLException se) {

}

3)黑/白名单验证

属于输入验证的范畴,大多使用正则表达式限制,或对于诸如排序顺序之类的简单操作,最好将用户提供的输入转换为布尔值,然后将该布尔值用于选择要附加到查询的安全值。

public String someMethod(boolean sortOrder) {

String SQLquery = "someSQL ... order by Salary " + (sortOrder ? "ASC" :"DESC");`

4) 输出转义

将用户输入放入查询之前对其进行转义,OWASP企业安全性API(ESAPI)是一个免费的开源Web应用程序安全控制库。

CodecORACLE_CODEC = new OracleCodec();

Stringquery = "SELECT user_id FROM user_data WHERE user_name = '"

+ESAPI.encoder().encodeForSQL( ORACLE_CODEC,req.getParameter("userID"))

+ "'and user_password = '"

+ ESAPI.encoder().encodeForSQL( ORACLE_CODEC,req.getParameter("pwd")) +"'";

5)框架修复:

对于Mybatis框架:

select * from news where tile like concat(‘%’,#{title}, ‘%’),

select * from news where id in

#{item}

Mybatis的order by语句可以选择在java层做映射或过滤用户输入进行防御。

对于Hibernate(HQL)框架预编译:

方法一:

Query query=session.createQuery(“from Useruser where user.name=:customername and user:customerage=:age ”);

query.setString(“customername”,name);

query.setInteger(“customerage”,age);

方法二:

String hql ="FROM User user where user.name=? and user.age=?";

Query q =session.createQuery(hql);

q.setString(0, name);

q.setInteger(1,age);

5、实战案例

1) Mybatis框架

对文章删除功能进行审计,articelId参数前端可控:

@RequestMapping("/delete")

public ModelAndView delete(HttpServletRequestrequest) {

ModelAndView model = newModelAndView();

try {

model.setViewName(this.getRequestUri(request));

String[] aridArr = request.getParameterValues("articelId");

if (aridArr != null&& aridArr.length > 0) {

this.deleteArticle(aridArr);

}

} catch (Exception e) {

model.setViewName(this.setExceptionRequest(request,e));

logger.error("AdminArticleController.delete()--error",e);

}

return model;

}

顺着变量的走向进行审计,articelId赋值给aridArr,而后进行了为空的判断,不为空则执行deleteArticle操作,跟踪定位此函数:

private void deleteArticle(String[]artidArr) {

//删除数据中记录

articleService.deleteArticleByIds(artidArr);

EHCacheUtil.remove(CacheConstans.ARTICLE_GOOD_RECOMMEND);

继续跟踪操作,articleService类的deleteArticleByIds函数,继而进入DAO层,在ArticleDaoImpl.java内:

public void deleteArticleByIds(StringarticleIds) {

this.delete("ArticleMapper.deleteArticleByIds",articleIds);

}

进入ArticleMapper.xml,最终追踪到deleteArticleByIds的SQL语句,使用了$拼接,典型的Mybatis注入:

DELETEFROM EDU_ARTICLE WHERE EDU_ARTICLE.ARTICLE_ID IN (${value})

除了顺向思维,还可以通过逆向思维挖掘,pom.xml中看到系统使用的是Mybatis框架,可以直接去审查Maper.xml文件,查看是否使用$拼接:

UTF-8

3.2.12.RELEASE

3.2.7

1.7.3

1.7

2) Order by绕过预编译

Webgoat一个order by的案例:

1620

order by的参数orderExpression可以是一个selectExpression也可以是一个函数,比如使用一个case语句。

案例中可以根据IP或ID对数据进行排序:

1620

对应代码为Server.java:

@GetMapping(produces =MediaType.APPLICATION_JSON_VALUE)

@SneakyThrows

@ResponseBody

public List sort(@RequestParamString column) {

Connection connection = DatabaseUtilities.getConnection(webSession);

PreparedStatement preparedStatement =connection.prepareStatement("select id, hostname, ip, mac, status, descriptionfrom servers where status <> 'outof order' order by " + column);

ResultSet rs = preparedStatement.executeQuery();

List servers = Lists.newArrayList();

while (rs.next()) {

Server server = new Server(rs.getString(1), rs.getString(2),rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(6));

servers.add(server);

}

虽使用了预编译但仍拼接了order by参数column,使用case探测语句探测:(case when (true) then id else ip end),如果真则以id排序,结果为:

1620

3) 预编译有误

查看FAQ页面数据功能getFaqPage函数,前端获取page等参数:

publicFaqPageInfo getFaqPage(String tenantId, Map conditions,int page, int pageSize, String like) {

try {

tenantId= WebUtil.getLoginTenantId();

FaqPageInfo fpi =FAQ_IO_SERVICE.getPageInfo(tenantId, conditions, page, pageSize, like);

for (FaqModel fm : fpi.getData()) {

fm.setWhitelistIds(WHITELIST_SERVICE.getWhiteListOnFaq(tenantId,fm.getId()));

}

return fpi;

}

跟踪FAQ_IO_SERVICE.getPageInfo,调用FaqSqlAccess.queryByPage进行处理:

public FaqPageInfo getPageInfo(StringtenantId, Map conditions, int page, int pageSize, Stringlike)

throws SQLException {

FaqPageInfo pageInfo = new FaqPageInfo();

pageInfo.setData(FaqSqlAccess.queryByPage(tenantId, conditions, page,pageSize, like));

pageInfo.setTotalSize(FaqSqlAccess.queryCount(tenantId, conditions,like));

return pageInfo;

}

找到FaqSqlAccess.java里的queryByPage方法,追踪到SQL语句:

public static ListqueryByPage(String tenantId, Map conditions, int page,int pageSize, String like)

throws SQLException {

List models = new ArrayList<>();

String language = conditions.get("language");

Connection connection = null;

PreparedStatement stmt = null;

try {

connection = MysqlUtils.getConnection();

String sql = "select id, name, description, language, update_time,is_on from TOC_FAQ where tenant_id=?";

if (!CommonUtils.isEmptyStr(language))

sql += " andlanguage='" + language + "'";

if (!CommonUtils.isEmptyStr(like))

sql += " and name like'%" + like + "%'";

sql += " order by update_time desc limit ?,?";

stmt = connection.prepareStatement(sql);

stmt.setString(1, tenantId);

stmt.setInt(2, (page - 1) * pageSize);

stmt.setInt(3, pageSize);

ResultSet resultSet = stmt.executeQuery();

发现此处使用了预编译,但language和like参数实际是直接拼接,存在SQL注入,对于getFaqPage功能构造参数"language":"'-if(substring(user(),1,1)=0x01,sleep(5),0)-'"}进行验证。

简单或复杂的SQL注入漏洞原理和审计方法相同,只是对于业务繁杂的系统,数据的走向和处理过程会比较复杂,调用链跟踪难度会稍大一些,需要更多耐心。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/380750.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python中bool函数_bool()函数以及Python中的示例

python中bool函数Python bool()函数 (Python bool() function) bool() function is used to convert a given value to the Boolean value (True or False) as per the standard truth testing procedures. It accepts a value (like an integer, list, maps, etc) and convert…

php中函数参数个数问题

形参大于实参 <?phpheader(content-type:text/html;charsetutf-8);function fun($name,$sex,$age){echo 名字是.$name,<br>;echo 性别是.$sex,<br>;echo 年龄是.$age,<br>;}fun(DL_one,21); ?>可以看出&#xff0c;能执行但报错 实参个数大于形参个…

忘记交手机费,招商银行的自助缴费不错!

最近一直太忙,结果手机费忘记交了,前天一拨电话,"对不起,您的手机已欠费",不过,只是限制呼出,还能接(全球通这点还是挺人性化的,不过是否值50大洋的月租?) 今天上网用一卡通缴费,点完确定,系统提示缴费成功,手机立即就可以拨出去了.效率还是很高的,省了我不少麻烦. …

java criteria exist_Java Criteria.addExists方法代碼示例

import org.apache.ojb.broker.query.Criteria; //導入方法依賴的package包/類/*** see org.kuali.kfs.module.bc.document.dataaccess.BudgetConstructionLockDao#getOrphanedPositionLocks(java.lang.String)*/public List getOrphanedPositionLocks(String lockUnivId) {Cri…

python实例31[解析buildlog]

简单地解析VisualStudio的buildlog&#xff1a;&#xff08;有的时候log文件太长&#xff0c;但是我们只是关心warning和error&#xff0c; 通过该程序可以直接得到所有的warning和error的行&#xff09; importrewarninglist []warninglist.append("warning C\d{4}"…

php的静态变量static在函数内部

静态变量放在函数内 <?phpheader(content-type:text/html;charsetutf-8);function fun(){static $num1;$num;echo $num,<br>;}fun();fun(); ?>静态变量放在函数内&#xff0c;作用域没变&#xff0c;生命周期变了&#xff0c;页面执行完毕才销毁&#xff0c;静态…

java json帮助类_java 写一个JSON解析的工具类

上面是一个标准的json的响应内容截图&#xff0c;第一个红圈”per_page”是一个json对象&#xff0c;我们可以根据”per_page”来找到对应值是3&#xff0c;而第二个红圈“data”是一个JSON数组&#xff0c;而不是对象&#xff0c;不能直接去拿到里面值&#xff0c;需要遍历数组…

关键字驱动测试示例_带有示例的False关键字

关键字驱动测试示例Python False关键字 (Python False keyword) False is a keyword (case-sensitive) in python, it is a Boolean value (a value of class type bool). False is the result of a comparison operation. False是python中的关键字(区分大小写)&#xff0c;它是…

DC (域控制器)上 DNS 不查询非掌管 Domain(域) 的解决办法 --(转)

如何移除根 DNS 区域 运行 Windows Server 2003 的 DNS 服务器在它的名称解析过程中遵循特定的步骤。DNS 服务器首先查询它的高速缓存&#xff0c;然后检查它的区域记录&#xff0c;接下来将请求发送到转发器&#xff0c; 最后使用根服务器尝试解析。 默认情况下&#xff0c;Mi…

数据库主键的使用心得

1.数据库设置数据格式的作用其实是为了规范数据的存储 同时数值型也会便于后期统计&#xff0c; 如果每个字段都是varchar来存储就失去了他本身的意义了。 2.设置主键是为了让记录不重复&#xff0c;如监测站点&#xff0c;监测时间这样的联合主键有利于重复的记录进不去&#…

php函数的预加载

php代码的执行过程&#xff1a;词法分析-------语法分析------------编译-----------加载编译的代码--------执行 函数的预加载就是在加载编译的代码过程中&#xff0c;会把函数的代码加载到内存中去&#xff0c;搜易我们在执行代码的时候&#xff0c;函数已经在内存中了 <…

python none_None关键字,带Python示例

python nonePython None关键字 (Python None keyword) Note: None is not a keyword – we are just considering & writing it as a keyword which is a replacement of null (in C/C). 注意&#xff1a; None不是关键字–我们只是考虑并将其编写为关键字&#xff0c;以替…

永久勘误:微软等面试100题系列,答案V0.4版[第41-60题答案]

永久勘误&#xff1a;微软面试100系列答案V0.4版[第41-60题答案] 作者&#xff1a;July、何海涛等网友 ---------------------------几点声明: I、 此微软面试100题系列永久更新&#xff0c;答案永久勘误&#xff0c;永久优化。随时&#xff0c;永远&#xff0c;欢迎&#xff…

php中的__FUNCTION__

__FUNCTION__:魔术常量&#xff0c;获取函数名 <?phpheader(content-type:text/html;charsetutf-8);function fun(){echo __FUNCTION__;}fun(); ?>

退出win不保存设置

退出win不保存设置 最后我们把“组策略”请出来做一点变动。在运行框键入“gpedit.msc”&#xff0c;确定后&#xff0c;进入组策略窗口。打开“用户配置”/“管理模块”/“桌面”&#xff0c;选中“退出时不保存设置”&#xff0c;鼠标右键“属性”&#xff0c;将“策略”页“…

java调用 solr集群_Solr集群安装Version5.5.2(cloud模式)

Solr安装cloud模式,基于Solr的安装版本为5.5.2。安装规划SolrIP/机器名安装软件运行进程zdh-7solrjarzdh-9solrjarzookeeperzdh-7:2181,zdh-8:2181,zdh-9:2181安装用户solrcloud/zdh1234 hadoopuseradd -g hadoop -s /bin/bash -md /home/solrcloud solrcloud安装步骤1.使用sol…

elif python_elif关键字,带Python示例

elif pythonPython Elif关键字 (Python elif keyword) elif is a keyword (case-sensitive) in python, it is used in the conditional statement, if we have multiple conditions to be checked, we have to use elif keyword to check next condition. elif是python中的一…

今天看明白了,为什么有些属性会这样写了:public string status{get;set;}

自动实现的属性在 C# 3.0 和更高版本中&#xff0c;当属性的访问器中不需要其他逻辑时&#xff0c;自动实现的属性可使属性声明更加简洁。 客户端代码还可通过这些属性创建对象。 如下面的示例所示声明属性时&#xff0c;编译器将创建一个私有的匿名支持字段&#xff0c;该字段…

数字图像的大小、所需比特数(二维)

二维数字图像所需的比特数根据公式&#xff1a; 其中&#xff1a; b&#xff1a;数字图像所需的比特数 MN&#xff1a;数字图像的行和列 k&#xff1a;由灰度级算出&#xff0c;公式如下&#xff1a; L&#xff1a;图像的灰度级 比如&#xff1a; 存储一幅大小为 1024x1024&a…

ASP.NET中使用web.config配置web应用程序中的数据库连接

[摘要]&#xff1a;在web.config文件中保存数据库连接配置信息,可以让你无须重新编译应用程序即可更新应用程序的某些属性。当你想把数据库迁移到另一个不同的服务器&#xff0c;你只需要修改web.config文件中的数据库连接配置信息而已&#xff0c;并不需要重新编译和重新部署这…