php的Warning: preg_match(): Null byte in regex问题的分析

昨天我们的xhgui出现报错Warning: preg_match(): Null byte in regex,于是,检查原因:是有pattern里面的null(0×0)字符引起的。
先看一个demo:

preg_match("/abcd".chr(0)."efg/", 'abc');

分析源码(源码位置:php/ext/pcre/php_pcre.c:325)

PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
{
    ......
    p = ZSTR_VAL(regex);// p = '/abcd',c语言字符串以\0结尾,这个赋值就把\0后面的字符丢了
    ......
    delimiter = *p++; // delimiter = "/"
    ......
    start_delimiter = delimiter; // start_delimiter = "/"
    if ((pp = strchr("([{< )]}> )]}>", delimiter)))
        delimiter = pp[5];
    end_delimiter = delimiter; // end_delimiter = "/"

    pp = p; // pp = 'abcd'

    if (start_delimiter == end_delimiter) {
        /* We need to iterate through the pattern, searching for the ending delimiter,
           but skipping the backslashed delimiters.  If the ending delimiter is not
           found, display a warning. */

        while (*pp != 0) { // 这个while没找到结束标记,所以循环结束后pp指针移动到字符串末尾
            if (*pp == '\' && pp[1] != 0) pp++;
            else if (*pp == delimiter)
                break;
            pp++;
        }
    }
    ......
    if (*pp == 0) {
        if (pp < ZSTR_VAL(regex) + ZSTR_LEN(regex)) { // 判断末尾位置是不是原字符串的末尾位置,不是则报E_WARNING
            php_error_docref(NULL,E_WARNING, "Null byte in regex");
        }
        ......
    }

从这段源码可以看出我们demo中输入的”/abcd”.chr(0).”efg/”字符串由于赋值操作,变成了”/abcd”,后面的chr(0).”efg/”在赋值操作中丢失。看起来是c语言本身的问题(c语言的字符串以\0结尾),而php没有处理这个问题。

延伸阅读,php的bug list中有一篇报告:点击查看
pattern中的\0(null)会导致安全问题,因为c语言的\0是字符串的结束符,在检测用户输入的字符串是遇到\0会认为用户输入结束,所以后面的字符就不会再检测,导致用户输入的字符串绕过匹配检测,产生这个安全问题。

转载请注明:小Y » php的Warning: preg_match(): Null byte in regex问题的分析

赞 (5) 评论 (0) 分享 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址