• ${}和#{}


    #{}匹配的是一个占位符,相当于JDBC中的一个?,会对一些敏感的字符进行过滤,编译过后会对传递的值加上双引号,因此可以防止SQL注入问题。

    ${}匹配的是真实传递的值,传递过后,会与sql语句进行字符串拼接。${}会与其他sql进行字符串拼接,不能预防sql注入问题。

    为什么能防止SQL注入:

    PreparedStatement类的setString()方法(MyBatis在#{}传递参数时,是借助setString()方法来完成,${}则不是):

    setString()方法全部源码:

    public void setString(int parameterIndex, String x) throws SQLException {
            synchronized(this.checkClosed().getConnectionMutex()) {
                if (x == null) {
                    this.setNull(parameterIndex, 1);
                } else {
                    this.checkClosed();
                    int stringLength = x.length();
                    StringBuilder buf;
                    if (this.connection.isNoBackslashEscapesSet()) {
                        boolean needsHexEscape = this.isEscapeNeededForString(x, stringLength);
                        Object parameterAsBytes;
                        byte[] parameterAsBytes;
                        if (!needsHexEscape) {
                            parameterAsBytes = null;
                            buf = new StringBuilder(x.length() + 2);
                            buf.append('\'');
                            buf.append(x);
                            buf.append('\'');
                            if (!this.isLoadDataQuery) {
                                parameterAsBytes = StringUtils.getBytes(buf.toString(), this.charConverter, this.charEncoding, this.connection.getServerCharset(), this.connection.parserKnowsUnicode(), this.getExceptionInterceptor());
                            } else {
                                parameterAsBytes = StringUtils.getBytes(buf.toString());
                            }

                            this.setInternal(parameterIndex, parameterAsBytes);
                        } else {
                            parameterAsBytes = null;
                            if (!this.isLoadDataQuery) {
                                parameterAsBytes = StringUtils.getBytes(x, this.charConverter, this.charEncoding, this.connection.getServerCharset(), this.connection.parserKnowsUnicode(), this.getExceptionInterceptor());
                            } else {
                                parameterAsBytes = StringUtils.getBytes(x);
                            }

                            this.setBytes(parameterIndex, parameterAsBytes);
                        }

                        return;
                    }

                    String parameterAsString = x;
                    boolean needsQuoted = true;
                    if (this.isLoadDataQuery || this.isEscapeNeededForString(x, stringLength)) {
                        needsQuoted = false;
                        buf = new StringBuilder((int)((double)x.length() * 1.1D));
                        buf.append('\'');

                        for(int i = 0; i < stringLength; ++i) {  //遍历字符串,获取到每个字符
                            char c = x.charAt(i);
                            switch(c) {
                            case '\u0000':
                                buf.append('\\');
                                buf.append('0');
                                break;
                            case '\n':
                                buf.append('\\');
                                buf.append('n');
                                break;
                            case '\r':
                                buf.append('\\');
                                buf.append('r');
                                break;
                            case '\u001a':
                                buf.append('\\');
                                buf.append('Z');
                                break;
                            case '"':
                                if (this.usingAnsiMode) {
                                    buf.append('\\');
                                }

                                buf.append('"');
                                break;
                            case '\'':
                                buf.append('\\');
                                buf.append('\'');
                                break;
                            case '\\':
                                buf.append('\\');
                                buf.append('\\');
                                break;
                            case '¥':
                            case '₩':
                                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) == 92) {
                                        buf.append('\\');
                                    }
                                }

                                buf.append(c);
                                break;
                            default:
                                buf.append(c);
                            }
                        }

                        buf.append('\'');
                        parameterAsString = buf.toString();
                    }

                    buf = null;
                    byte[] parameterAsBytes;
                    if (!this.isLoadDataQuery) {
                        if (needsQuoted) {
                            parameterAsBytes = StringUtils.getBytesWrapped(parameterAsString, '\'', '\'', this.charConverter, this.charEncoding, this.connection.getServerCharset(), this.connection.parserKnowsUnicode(), this.getExceptionInterceptor());
                        } else {
                            parameterAsBytes = StringUtils.getBytes(parameterAsString, this.charConverter, this.charEncoding, this.connection.getServerCharset(), this.connection.parserKnowsUnicode(), this.getExceptionInterceptor());
                        }
                    } else {
                        parameterAsBytes = StringUtils.getBytes(parameterAsString);
                    }

                    this.setInternal(parameterIndex, parameterAsBytes);
                    this.parameterTypes[parameterIndex - 1 + this.getParameterIndexOffset()] = 12;
                }

            }
        }


    1)开启MySQL日志:

    在MySQL配置文件中的[mysqld]下增加如下配置:

    # 是否开启mysql日志  0:关闭(默认值) 1:开启
    general-log=1

    # mysql 日志的存放位置
    general_log_file="D:/query.log"


    2)重启MySQL服务(要以管理员身份运行):

    net stop mysql

    net start mysql
     
    SQL注入问题

    MyBatis的#{}之所以能够预防SQL注入是因为底层使用了PreparedStatement类的setString()方法来设置参数,此方法会获取传递进来的参数的每个字符,然后进行循环对比,如果发现有敏感字符(如:单引号、双引号等),则会在前面加上一个'/'代表转义此符号,让其变为一个普通的字符串,不参与SQL语句的生成,达到防止SQL注入的效果。

    #{}${}用法总结 1)#{}在使用时,会根据传递进来的值来选择是否加上双引号,因此我们传递参数的时候一般都是直接传递,不用加双引号,${}则不会,我们需要手动加

    2)在传递一个参数时,我们说了#{}中可以写任意的值,${}则必须使用value;即:${value}

    3)#{}针对SQL注入进行了字符过滤,${}则只是作为普通传值,并没有考虑到这些问题

    4)#{}的应用场景是为给SQL语句的where字句传递条件值,${}的应用场景是为了传递一些需要参与SQL语句语法生成的值。

     
  • 相关阅读:
    抓取国家地区基础数据
    h264
    h.264
    vlc 推送rtsp视频流不能播放
    花生壳tcp内网端口映射
    make 安装时指定目录
    ubuntu安装vsftpd
    vsftpd命令
    vim删除某一列
    linux打开防火墙
  • 原文地址:https://www.cnblogs.com/KL2016/p/15773936.html
Copyright © 2020-2023  润新知