HTML dezenfektanı kullanarak regex &

0 Cevap php

I know that parsing HTML with regexp is bad, and it can not work for all cases (there are plenty topics about that on Stack Overflow). But I still wanted to try to sanitize HTML with regex based on a whitelist method.

I would like to show you my code bellow (written in PHP 5.2). It seems to work fine, but I'm still wondering if there are security issues.

Yani, yanlış bir şey var mı?

Temel ilke Html_Sanitizer kullanmaktır :: sterilize ()

  1. Işlev ilk belirteçleri ile hiçbir nitelikleri ile birlikte izin etiketleri değiştirir. Sonra özelliklere sahip etiketleri ayrıştırmak ve çok belirteci ile değiştirin.
  2. HTML etiketleri daha sonra (cleanTag işlevini kullanarak) izin özelliklerini algılamak için ayrıştırılır. HTML etiketi nedenle (lets-umut) güvenli şekilde yeniden yaptırılmıştır.
  3. htmlspecialchars'ın kalan kodu temiz olduğundan emin olmak için kullanılır
  4. belirteçleri güvenli etiketleri ile değiştirilir.

Kod:

class Html_Sanitizer
{
    const VALIDATOR_CSS_UNIT = '(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0';
    const VALIDATOR_URL = 'http://\\S+';
    const VALIDATOR_CSS_PROPERTY = '[a-z\-]+';
    const VALIDATOR_STYLE = '[^"]*';

    protected static $_tags = 'a|b|blockquote|br|cite|d[ldt]|h[1-6]|i|img|li|ol|p|span|strong|u|ul';

    protected static $_attributes = array(
        'img' => array(
            'width' => '[0-9]+',
            'height' => '[0-9]+',
            'src' => self::VALIDATOR_URL,
            'style' => self::VALIDATOR_STYLE
            ),
        'span' => array(
            'style' => self::VALIDATOR_STYLE
            ),
        'p' => array(
            'style' => self::VALIDATOR_STYLE
            ),
        'a' =>  array(
            'href' => self::VALIDATOR_URL
            )
    );

    protected static $_styleValidators = array(
        'color' => '(\#[a-fA-F0-9]+)|([a-z ]+)',
        'background-color' => '\#[a-zA-Z0-9]+',
        'font-style' => '(normal|italic|oblique)',
        'font-size' => '[\-a-z]+',
        'margin-left' => self::VALIDATOR_CSS_UNIT,
        'margin-right' => self::VALIDATOR_CSS_UNIT,
        'text-align' => '(left|right|center|justify)',
        'text-indent' => self::VALIDATOR_CSS_UNIT,
        'text-decoration' => '(none|overline|underline|blink|line-through)',
        'width' => self::VALIDATOR_CSS_UNIT,
        'height' => self::VALIDATOR_CSS_UNIT
    );

    public static function sanitize($str)
    {
        $tokens = array();

        //tokenize opening tags with no attributes
        $pattern = '#<(/)?('. self::$_tags .')>#';
        $replace = '__SAFE_TAG_$1$2__';
        $str = preg_replace($pattern, $replace, $str);

        // tokenize tags with attributes
        $pattern = '#<('. self::$_tags .')(?:\s+(?:[a-z]+)="(?:[^"\\\]*(?:\\\"[^"\\\]*)*)")*\s*(/)?>#';
        preg_match_all($pattern, $str, $matches, PREG_SET_ORDER);
        foreach($matches as $i => $match) {
            $tokens[$i] = self::cleanTag($match[1], $match[0]);
            $str = str_replace($match[0], '__SAFE_TOKEN_'.$i.'__', $str);
        }

        $str = htmlspecialchars($str);

        foreach ($tokens as $i => $cleanTag) {
            $str = str_replace('__SAFE_TOKEN_'.$i.'__', $cleanTag, $str);
        }

        $pattern = '#__SAFE_TAG_(/?(?:'. self::$_tags .'))__#';
        $replace = '<$1>';
        $str = preg_replace($pattern, $replace, $str);

        return $str;
    }

    public static function cleanTag($tag, $str)
    {
        $cleanTag = '<' . $tag;

        if ($tag === 'a') {
            $cleanTag .= ' rel="nofolow" target="_blank"';
        }

        if (isset(self::$_attributes[$tag])) {
            foreach(self::$_attributes[$tag] as $attr => $attrPattern) {
                $pattern = '#'.$attr.'="('. $attrPattern .')"#';
                preg_match($pattern, $str, $match);
                if (isset($match[1])) {
                    if ($attr == 'style') {
                        $cleanTag .= ' style="' . self::cleanStyle($match[1]) . '"';
                    } else {
                        $cleanTag .= ' ' . $attr . '="' . $match[1] . '"';
                    }
                }
            }
        }

        if ($tag === 'img') {
            $cleanTag .= ' /';
        }

        $cleanTag .= '>';
        return $cleanTag;
    }

    public static function cleanStyle($style)
    {
        $cleanStyle = '';

        foreach(self::$_styleValidators as $stl => $stlPattern) {
            $pattern = '#[; ]?' . $stl . '\s*:\s*(' . $stlPattern . ')\s*;#i';
            preg_match($pattern, $style, $match);
            if (isset($match[1])) {
                $cleanStyle .= ($cleanStyle ? ' ' : '') . $stl . ':' . $match[1] . ';';
            }
        }

        return $cleanStyle;
    }
}

0 Cevap