老大反馈代码里面存在sql注入,这个漏洞会导致系统遭受攻击,定位到对应的代码,如下图所示

image

like 进行了一个字符串拼接,正常的情况下,前端传一个 cxk 过来,那么执行的sql就是

select * from test where name like '%cxk%';

好像没有什么问题,但是,如果被攻击了传了个 cxk%'; DELETE FROM test WHERE name like '%cxk

那么 这条sql 将会拼接成

select * from test where name like '%cxk%'; DELETE FROM test WHERE name like '%cxk%';

执行不会报错,结果是 name like cxk 的数据全部删除,这个还是比较温柔的sql注入,如果是 drop table ,那不是要原地爆炸?

既然Sql 注入危害这么大,那么怎么防范呢?

采用sql语句预编译和绑定变量,是最简单,也是最有效的方案.

那什么是预编译呢?

like this

select * from test where name like ? args: WrappedArray(JdbcValue(%cxk%))

先是 select * from test where name like ? 这样预编译好,然后传进来的数据以参数化的形式执行sql,就可以防止sql 注入。

为什么这样可以防止sql 注入呢?

分别给两种场景测试

1.likeString

代码如下

def likeString(name:String) ={

dataSource.rows[Test](sql" select * from test where name like "+s"'%${name}%'")

}

输入 cxk%'; DELETE FROM test WHERE name like '%cxk

打断点可以看到

image

将statement 中的值复制出来 到navicat 中,可以看到

image

那么jdbc 执行就会 直接执行,然后把cxk 删了。

2.like

代码如下

def like(name:String) ={

// cxu

// %cku%

dataSource.rows[Test](sql" select * from test where name like ${name.likeSql}")

}

implicit class StringBuildSqlLikeImplicit(s:String){

def likeSql: String ={

s"%${s}%"

}

def likeLeftSql: String = {

s"%${s}"

}

def likeRightSql: String ={

s"${s}%"

}

}

输入 cxk%'; DELETE FROM test WHERE name like '%cxk

打断点可以看到

image

image

可以看到 statement = select * from test where name like ** NOT SPECIFIED **

PreparedStatement.setString(1,'cxk%'; DELETE FROM test WHERE name like '%cxk')

之后,

statement =

select * from test where name like '%cxk\'; DELETE FROM test WHERE name like \'%cxk%'

将statement 中的值复制出来 到navicat 中,可以看到

image

string 内部的; % 被格式化, 这样执行的话,内部的sql 就以字符串的形式存在,这样避免了Sql 注入。

那 PreparedStatement 是这么做到的呢, 主要的原因是 PreparedStatement.setString(int parameterIndex, String x)

这里面会对x 进行一个格式化

判断是否需要格式化

image

贴上源码

private boolean isEscapeNeededForString(String x, int stringLength) {

boolean needsHexEscape = false;

for (int i = 0; i < stringLength; ++i) {

char c = x.charAt(i);

switch (c) {

case 0: /* Must be escaped for 'mysql' */

needsHexEscape = true;

break;

case '\n': /* Must be escaped for logs */

needsHexEscape = true;

break;

case '\r':

needsHexEscape = true;

break;

case '\\':

needsHexEscape = true;

break;

case '\'':

needsHexEscape = true;

break;

case '"': /* Better safe than sorry */

needsHexEscape = true;

break;

case '\032': /* This gives problems on Win32 */

needsHexEscape = true;

break;

}

if (needsHexEscape) {

break; // no need to scan more

}

}

return needsHexEscape;

}

可以看到 它会对传进来的参数判断,如果含有一些非法字符会判断传过来的值需要格式化, 那它是怎么格式化的呢? 我们看下源码

// setString 里的部分源码

if (this.isLoadDataQuery || isEscapeNeededForString(x, stringLength)) {

needsQuoted = false; // saves an allocation later

StringBuilder buf = new StringBuilder((int) (x.length() * 1.1));

buf.append('\'');

//

// Note: buf.append(char) is _faster_ than appending in blocks, because the block append requires a System.arraycopy().... go figure...

//

for (int i = 0; i < stringLength; ++i) {

char c = x.charAt(i);

switch (c) {

case 0: /* Must be escaped for 'mysql' */

buf.append('\\');

buf.append('0');

break;

case '\n': /* Must be escaped for logs */

buf.append('\\');

buf.append('n');

break;

case '\r':

buf.append('\\');

buf.append('r');

break;

case '\\':

buf.append('\\');

buf.append('\\');

break;

case '\'':

buf.append('\\');

buf.append('\'');

break;

case '"': /* Better safe than sorry */

if (this.usingAnsiMode) {

buf.append('\\');

}

buf.append('"');

break;

case '\032': /* This gives problems on Win32 */

buf.append('\\');

buf.append('Z');

break;

case '\u00a5':

case '\u20a9':

// escape characters interpreted as backslash by mysql

if (this.charsetEncoder != null) {

CharBuffer cbuf = CharBuffer.allocate(1);

ByteBuffer bbuf = ByteBuffer.allocate(1);

cbuf.put(c);

cbuf.position(0);

this.charsetEncoder.encode(cbuf, bbuf, true);

if (bbuf.get(0) == '\\') {

buf.append('\\');

}

}

// fall through

default:

buf.append(c);

}

}

buf.append('\'');

parameterAsString = buf.toString();

}

从这里可以看出,会讲' 加一个'' 那么原传入的Sring 就会被格式化成上文所说。

打断点我们可以看到

image

这一块是jdbc PreparedStatement 对SQL注入的防范。

从网上我还看到了一些这样的

那么,什么是所谓的“precompiled SQL statement”呢?

回答这个问题之前需要先了解下一个SQL文在DB中执行的具体步骤:

1.Convert given SQL query into DB format -- 将SQL语句转化为DB形式(语法树结构)

2.Check for syntax -- 检查语法

3.Check for semantics -- 检查语义

4.Prepare execution plan -- 准备执行计划(也是优化的过程,这个步骤比较重要,关系到你SQL文的效率,准备在后续文章介绍)

5.Set the run-time values into the query -- 设置运行时的参数

6.Run the query and fetch the output -- 执行查询并取得结果

打断点调试的时候看到,PreparedStatement 最终还是会转化成statement 然后执行,

jdbc 这么做应该是做应该是为了 mysql 的缓存机制,我们知道,mysql 进行select 查询的时候,会有一个缓存机制,如果执行语句一致的话,就会拿mysql 的缓存直接获取数据,如果以参数形式传到mysql 的话,这样就没有办法命中缓存了(个人看法,错误请佐证)。

综上所述,SQL注入,用PreparedStatement 防治是可以防治的,代码中也尽量用 PreparedStatement 这种形式。

题外话,那么这个是jdbc 的做法,那其他的框架是怎么解决SQL 注入的呢?

PHP 防治Sql注入

1.通过函数去对一些特殊字符进行处理 例如 addslashes(

str)

2.预编译的做法

Node 防治SQL 注入

1.使用escape()对传入参数进行编码,

2.使用connection.query()的查询参数占位符:(预编译)

3.使用escapeId()编码SQL查询标识符:

4.使用mysql.format()转义参数:

sql 整改措施 注入_记一次Sql注入 解决方案相关推荐

  1. 为什么preparedstatement能防止sql注入_使用Python防止SQL注入攻击的实现示例

    文章背景 每隔几年,开放式Web应用程序安全项目就会对最关键的Web应用程序安全风险进行排名.自第一次报告以来,注入风险高居其位!在所有注入类型中,SQL注入是最常见的攻击手段之一,而且是最危险的.由 ...

  2. 05_SQL注入_功能语句报错注入盲注

    05_SQL注入_功能语句&报错回显&盲注 1. SQL 语句和网站功能 1.1 Web开发中常见语句 [本章代码来源于pikachu和sqli-lab中的靶场] 开发中,根据不同的需 ...

  3. java远程线程注入_系统权限远程线程注入到Explorer.exe

    提升为系统权限,注入到explorer中 一丶简介 我们上一面说了系统服务拥有系统权限.并且拥有system权限.还尝试启动了一个进程. 那么我们是不是可以做点坏事了. 我们有一个系统权限进程.而调用 ...

  4. sql server查询历史进程_学习笔记 | SequoiaDB SQL查询语句执行过程

    本篇笔记将为大家介绍 SequoiaDB 巨杉数据库查询 SQL 语句的执行过程,以及查询语句执行过程中实例层.协调节点.编码节点.数据节点各自承担的功能. 应用程序或用户想要从数据库查询需要的数据, ...

  5. sql重命名数据库_为什么要为SQL单元测试巧妙地命名数据库对象

    sql重命名数据库 This article is focussed on clever database object naming from both development and SQL un ...

  6. sql备份恢复数据库_使用DBATools通过SQL恢复数据库操作验证备份

    sql备份恢复数据库 In this article, we will explore database backup validation by with SQL restore database ...

  7. sql 键查找 索引查找_残留谓词对SQL Server索引查找操作的影响

    sql 键查找 索引查找 抽象 (Abstract) It is common assumption that an Index Seek operation in a query plan is o ...

  8. factorybean 代理类不能按照类型注入_彻底搞懂依赖注入(一)Bean实例创建过程

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 上一章介绍了Bean的加载过程(IOC初始化过程),加载完成后,紧接着就要用到它的依赖注入 ...

  9. sql 整改措施 注入_防止SQL注入的五种方法

    一.SQL注入简介 SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编程时的疏忽,通过SQL语句,实现无帐号登录,甚至篡改数据库. 二.SQL注入攻击的总体 ...

最新文章

  1. 关于在真实物理机器上用cloudermanger或ambari搭建大数据集群注意事项总结、经验和感悟心得(图文详解)...
  2. iOS开发- 相机(摄像头)获取到的图片自动旋转90度解决办法
  3. Keras-数据准备
  4. git pull 卡在 Unpacking objects 解决方法
  5. 三、spring boot 1.5.4 web容器定制(端口号等修改)
  6. 小心 Enum Parse 中的坑
  7. VMWare 虚拟机中安装 CentOS 7
  8. 蓝桥杯 ALGO-62 算法训练 平方计算
  9. 安装QTP10.0 报需要先安装 c++组件
  10. python lambda函数详细解析(面试经常遇到)
  11. 《Java EE互联网轻量级框架整合开发》在京东预售,发个目录
  12. 孩子学Java编程_7个最适合儿童学习编程的应用程序(上)
  13. 运行kettle-8.2源码
  14. 机器学习去除马赛克案例(代码)
  15. 牛客小白月赛1 F.三视图
  16. #R语言# 生成随机数
  17. R SMOTE 报错 length of 'dimnames' [2] not equal to array extent
  18. iOS开发之沙盒机制(SandBox)
  19. JSON parse error: Invalid UTF-8 start byte 0xa0\n
  20. python统计一篇英文短文中单词出现的频率、内存使用分析

热门文章

  1. 从ARM裸机看驱动之按键中断方式控制LED(一)
  2. FFMPEG开源音视频项目学习汇总
  3. FFmpeg4.3.2之ffplay log输出级别(三十)
  4. Mac解压Linux平台tar包报错:tar: Error reading Truncated input file
  5. 高通平台手机开发之Bring-up
  6. RS(Regular Singular)隐写分析及实现
  7. iOS bugly集成报错
  8. UE4之UMG用户界面
  9. Vue之Promise
  10. 如何配置cmd操作XAMPP中的MYSQL的运行环境?