diff --git a/var/Typecho/Common.php b/var/Typecho/Common.php index 02f7b8e1..83d10c66 100644 --- a/var/Typecho/Common.php +++ b/var/Typecho/Common.php @@ -22,7 +22,7 @@ define('__TYPECHO_MB_SUPPORTED__', function_exists('mb_get_info') && function_ex class Typecho_Common { /** 程序版本 */ - const VERSION = '1.1/17.8.17'; + const VERSION = '1.1/17.10.13'; /** * 允许的属性 @@ -1105,6 +1105,67 @@ EOF; return array($type, $header, $body); } + /** + * 检查是否是一个安全的主机名 + * + * @param $host + * @return bool + */ + public static function checkSafeHost($host) + { + if ('localhost' == $host) { + return false; + } + + $address = gethostbyname($host); + $inet = inet_pton($address); + + if ($inet === false) { + // 有可能是ipv6的地址 + $records = dns_get_record($host, DNS_AAAA); + + if (empty($records)) { + return false; + } + + $address = $records[0]['ipv6']; + $inet = inet_pton($address); + } + + if (strpos($address, '.')) { + // ipv4 + // 非公网地址 + $privateNetworks = array( + '10.0.0.0|10.255.255.255', + '172.16.0.0|172.31.255.255', + '192.168.0.0|192.168.255.255', + '169.254.0.0|169.254.255.255', + '127.0.0.0|127.255.255.255' + ); + + $long = ip2long($address); + + foreach ($privateNetworks as $network) { + list ($from, $to) = explode('|', $network); + + if ($long >= ip2long($from) && $long <= ip2long($to)) { + return false; + } + } + } else { + // ipv6 + // https://en.wikipedia.org/wiki/Private_network + $from = inet_pton('fd00::'); + $to = inet_pton('fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'); + + if ($inet >= $from && $inet <= $to) { + return false; + } + } + + return true; + } + /** * 获取图片 * diff --git a/var/Typecho/Http/Client/Adapter.php b/var/Typecho/Http/Client/Adapter.php index 0394b8cb..c1aefb6b 100644 --- a/var/Typecho/Http/Client/Adapter.php +++ b/var/Typecho/Http/Client/Adapter.php @@ -294,8 +294,8 @@ abstract class Typecho_Http_Client_Adapter * * @access public * @param string $url 请求地址 - * @param string $rfc 请求协议 * @return string + * @throws Typecho_Http_Client_Exception */ public function send($url) { @@ -307,6 +307,10 @@ abstract class Typecho_Http_Client_Adapter throw new Typecho_Http_Client_Exception('Unknown Host', 500); } + if (!in_array($params['scheme'], array('http', 'https'))) { + throw new Typecho_Http_Client_Exception('Unknown Scheme', 500); + } + if (!empty($params['path'])) { $this->path = $params['path']; } diff --git a/var/Widget/Service.php b/var/Widget/Service.php index ff291acd..35403ddd 100644 --- a/var/Widget/Service.php +++ b/var/Widget/Service.php @@ -140,7 +140,6 @@ class Widget_Service extends Widget_Abstract_Options implements Widget_Interface ->setHeader('User-Agent', $this->options->generator) ->setTimeout(3) ->setData($input) - ->setIp('127.0.0.1') ->send(Typecho_Common::url('/action/service', $this->options->index)); } catch (Typecho_Http_Client_Exception $e) { diff --git a/var/Widget/XmlRpc.php b/var/Widget/XmlRpc.php index 0fcd4018..274b2b60 100644 --- a/var/Widget/XmlRpc.php +++ b/var/Widget/XmlRpc.php @@ -2057,6 +2057,16 @@ class Widget_XmlRpc extends Widget_Abstract_Contents implements Widget_Interface $pathInfo = Typecho_Common::url(substr($target, strlen($this->options->index)), '/'); $post = Typecho_Router::match($pathInfo); + /** 检查源地址是否合法 */ + $params = parse_url($source); + if (false === $params || !in_array($params['scheme'], array('http', 'https'))) { + return new IXR_Error(16, _t('源地址服务器错误')); + } + + if (!Typecho_Common::checkSafeHost($params['host'])) { + return new IXR_Error(16, _t('源地址服务器错误')); + } + /** 这样可以得到cid或者slug*/ if (!($post instanceof Widget_Archive) || !$post->have() || !$post->is('single')) { return new IXR_Error(33, _t('这个目标地址不存在'));