浅析Statement和PreparedStatement,SQL注入

一、SQL注入

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

上述语句摘自百度百科,可能对于有些人来说晦涩难懂,那么我举个最简单的例子,来体验这一过程;

假设有一个登录表单,后台数据校验sql为select * from user where username = 'XXX' and password = 'XXX',XXX为传入的用户名和密码,根据sql返回的结果判断登录是否成功;(方便解释,简单处理)

这条sql是预先拼接好然后提交给数据库执行的,假设我们把password的内容改为1' or '1' = '1注意里面的单引号!如果登录名为caojiantao,那么最终生成的sql便是:

select * from user where username = 'caojiantao' and password = '1' or '1' = '1'

!!这样一来不用知道用户caojiantao的密码也能够登录成功了,更有甚者,在密码处输入"1';drop table user;",直接删除了数据表,十分的危险。

这就是一个最简单sql注入的例子,输入包含sql命令的内容,欺骗服务器执行破坏数据。

二、Statement

JDBC核心接口,对象用于将SQL语句发送到数据库中。一个简单的demo演示Statement的使用;

    public static void main(String[] args) {
        // 数据库配置
        String url = "jdbc:mysql://127.0.0.1/ssm";
        String name = "com.mysql.jdbc.Driver";
        String user = "root";
        String password = "Cjt00382114.";
        // 登录账号密码
        String username = "caojiantao";
        String pwd = "123";
        // 拼接sql
        String sql = "select * from user where username = '" + username + "' and password = '" + pwd + "'";
        try {
            // jdbc操作
            Class.forName(name);
            Connection connection = DriverManager.getConnection(url, user, password);
            // Statement
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            while (resultSet.next()){
                System.out.println(resultSet.getString("nickname"));
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }

代码很简单,判断用户名和密码是否匹配,匹配则输出用户的nickname昵称;

根据上面sql注入的问题,我们试着把pwd传入1' or '1' = '1,前面的1可以随便填,运行程序可以发现输出了用户昵称曹建涛,说明sql注入成功,那么,我们该怎么避免呢?

三、PreparedStatement

采用字符串匹配?筛选sql命令字符串?没那么麻烦,JDBC已经有现成的处理方案了,那就是PreparedStatement

PreparedStatement继承自Statement,字面可译为声明,强调一个预,内部包含一个预编译的sql语句,参数采用占位符?进行填充,还是看一段代码体会下;

    public static void main(String[] args) {
        // 数据库配置
        String url = "jdbc:mysql://127.0.0.1/ssm";
        String name = "com.mysql.jdbc.Driver";
        String user = "root";
        String password = "Cjt00382114.";
        // 登录账号密码
        String username = "caojiantao";
        String pwd = "123";
        String preSql = "select * from user where username = ? and password = ?";
        try {
            // jdbc操作
            Class.forName(name);
            Connection connection = DriverManager.getConnection(url, user, password);
            // PreparedStatement
            PreparedStatement preparedStatement = connection.prepareStatement(preSql);
            preparedStatement.setString(1, username);
            preparedStatement.setString(2, pwd);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()){
                System.out.println(resultSet.getString("nickname"));
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }

我们可以修改pwd内容为1' or '1' = '1,运行程序没有任何输出,说明PreparedStatement有效地避免了sql注入问题;

因为SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令,如此,就起到了SQL注入的作用了!

上述摘自java中预处理PrepareStatement为什么能起到防止SQL注入的作用??!!

因为是继承关系,因而Statement具备的PreparedStatement全都有,而且PreparedStatement还具备独有的预处理功能,相比StatementPreparedStatement好处有三:

  1. 提高代码的可读性,便于维护;
  2. 提高了sql执行效率;
  3. 增强了安全性,避免sql注入;

四、花絮——myBatis的 # 和 $

# 相当于对数据 加上 双引号,$ 相当于直接显示数据。

一句话言简意赅。分条陈述:

  1. # 能够sql注入问题,$ 不行;
  2. $ 用于传入数据库对象,例如表名;
  3. 能用 # 就不要使用 $;

参考文章:mybatis中的#和$的区别

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,288评论 0 4
  • JDBC简介 SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。JDBC...
    奋斗的老王阅读 1,432评论 0 51
  • 概念Java提供了 Statement、PreparedStatement 和 CallableStatement...
    Gothrow阅读 1,748评论 0 1
  • 前奏:“有空的时候用元认知梳理自己建立信心的过程,这是有‘套路’的,也就是说有思维模型和相应的行动套路在里面。”这...
    谢宇雨阅读 181评论 2 0
  • 白牛镇高年级数学教研会发言1刘教授:解决老大难的问题,来和乡小的学生来共同探讨探讨这个老大难的问题。以四则运算为总...
    c刘春雨阅读 393评论 0 0