zoukankan      html  css  js  c++  java
  • 数据库中的不可见字符

    场景:产品经理通过后台系统插入一个字母组成的优惠码(例如:coupon)之后,再从后台通过关键字coupon去查找这个优惠码,查不到,同时影响线上使用。

    假设表名:exchange_code.

    假设列名:code , varchar类型

    症状1:通过Sequel Pro按字段名等等条件搜索coupon,搜索不出来这条记录。

    等价于SQL: SELECT  * from exchange_cdoe where code = 'coupon';

     

     

    症状2:通过contains条件搜索,能找到这条记录。

    等价于SQL: SELECT  * from exchange_cdoe where code contains 'coupon';

     

     

    症状3:通过 length 函数,计算一下code 长度, 发现长度并不等于coupon的长度6.

     

     

    看上去是6个字母,却表现出上面的情况。

    后面团队想到办法,把里面的内容复制出来,转化为 unicode。

    发现了里面包含 unicode 200b 这个不可见字符。



     

    coupon​

    http://tool.chinaz.com/tools/unicode.aspx  (从左至右复制上面这一行字符,去这个网址转换unicode试试)

    问题复现

    利用java 复现问题

        @Test
        public void testBlog(){
            // 字母m  对应unicode u6d
            String unicode = "\u6d\u200b\u6d";
            System.out.println("unicode:"+unicode);
            String string = unicode2String(unicode) ;
            System.out.println("string:"+string);
        }
    
        /**
         * unicode 转字符串
         */
        public static String unicode2String(String unicode) {
    
            StringBuffer string = new StringBuffer();
    
            String[] hex = unicode.split("\\u");
    
            for (int i = 1; i < hex.length; i++) {
    
                // 转换出每一个代码点
                int data = Integer.parseInt(hex[i], 16);
    
                // 追加成string
                string.append((char) data);
            }
    
            return string.toString();
        }

    输出结果

    unicode:u6du200bu6d

    string:m​m

    输出结果中mm之间有一个不可见不占位的 u200b 特殊字符,类似的 u200c 也是一样的效果。

    这些字符的产生 也许是因为”实际上当前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。” — https://zh.wikipedia.org/wiki/Unicode 。

     

    问题预防

    通过正则表达式校验数据合法性(例如,只允许数字和大小写字母)。

        @Test
        public void testBlog(){
            // 字母m  对应unicode \u6d
            String unicode = "\u6d\u200b\u6d";
            System.out.println("unicode:"+unicode);
            String string = unicode2String(unicode) ;
            System.out.println("string:"+string);
            Pattern pattern = Pattern.compile("[a-zA-Z0-9.]+");
            System.out.println("pass? "+pattern.matcher(string).matches());
        }

     输出结果

    unicode:u6du200bu6d

    string:m​m

    pass? false

     

     

    === 程序员日常小故事 之 隐形的字符===

    产品W:“怎么回事啊,这条记录我刚插入的,后台怎么查不出来啊”

    程序员T:“我看看怎么回事,之前都是好的啊”

    产品H:“这个功能模块怎么又出问题了?”

    程序员Z:“我看看啊,数据库里去查一下,怎么数据库里按字段查,也查不出来啊。 ”

    某某程序员:“按ID查。”

    某某程序员:“查一下这个字段的长度”

    某某程序员:“奶奶的,怎么和看上去的长度不一样”

    某某程序员:“看看字符串的unicode编码”

    某某程序员:“复制到Java里面转成unicode看看”

    某某程序员:“奶奶的怎么有不可见字符”

    程序员T:“产品W,你是怎么输入不可见字符的…”

    产品W:“我是正常操作的呀”

  • 相关阅读:
    解决urbuntu桌面本客户端输入ll command not found
    小白学习安全测试(二)——httrack的安装和使用
    Selenium + java不借助autolt实现下载文件到指定目录
    用例设计工具PICT — 输入组合覆盖
    解决创建maven项目Could not resolve archetype org.apache.maven.archetypes:maven-archetype-quickstart问题
    作死的自动化测试【转】
    测试开发是什么?为什么现在那么多公司都要招聘测试开发?【转】
    MySql的触发器
    MySql的存储过程
    MySql的索引操作
  • 原文地址:https://www.cnblogs.com/tanliwei/p/9102657.html
Copyright © 2011-2022 走看看