SSRF请求伪造攻击以及PHP中如何避免

概念

攻击者利用某服务器请求来获取内网或外网系统权限,暴力请求获取服务器端口开发情况等。

攻击流程

  1. 攻击者构造请求
  2. 服务器根据攻击者构造的请求对内网服务器进行请求
  3. 内网服务将请求反馈给服务器
  4. 服务器将获取到的内网资源返回给攻击者

危害

使服务器资源泄漏,内网服务任意扫描泄漏内网信息。

容易引起SSRF的函数

file_get_contents从用户指定的URL获取文件,如果用户传的URL为/etc/password,则可轻易获得服务器的用户列表。

fsocketopen暴力请求内网端口,通过返回值,判断获得服务器端口的开放情况。

容易造成SSRF的功能

原理其实都是使得网站可以请求攻击者输入的URL

  • 页面分享,用户输入希望分享的URL,网站服务端会请求用户输入的URL,解析内容呈现给用户
  • 页面转码
  • 翻译服务
  • 加载服务器上的图片展示给用户

SSRF漏洞防御

核心思想:合理控制访问权限

  • 无特殊情况不要接收用户要访问的URL
  • 限制PHP随意访问服务器的任意路径。PHP配置中设置开启open_basedir,限定脚本的访问目录
  • 如必须接收用户的URL,可使用白名单机制,包括端口白名单、协议白名单、文件类型白名单、甚至是URL白名单;并且要统一处理服务端的返回输出,避免请求的错误信息直接暴露给用户。
  • 如果项目中需要获取外网资源,使用黑名单屏蔽内网

代码库封装

<?php
class Filter
{
    private $schemeWhiteList = [
        'http',
        'https',
    ];
    private $hostWhiteList = [
        'www.why.com'
    ];
    private $portWhiteList = [
        80, 443
    ];
    private $fileTypeWhiteList = [
        'html', 'gif', 'png', 'jpeg',
    ];
    private $blackHostList = [
        '172.', '10.', 'localhost', '127.', '192.',
    ];
    private $blackIpList = [
        '127.', '10.', '127.', '192.',
    ];

    private $info;

    public function filterBlackIp($url)
    {
        $host = $this->getHost($url);
        $ip = gethostbyname($host);
        if ($ip == $host){
            return false;
        }

        if (empty($this->blackIpList)){
            return true;
        }

        foreach ($this->blackIpList as $blackIp){
            if (strpos($ip, $blackIp) === 0){
                return false;
            }
        }
        return true;
    }

    public function filterBlackHost($url)
    {
        $host = $this->getHost($url);

        if (empty($this->blackHostList)){
            return true;
        }

        foreach ($this->blackHostList as $BlackHost){
            if (strpos($host, $BlackHost) === 0){
                return false;
            }
        }
        return true;
    }

    public function filterScheme($url)
    {
        $scheme = $this->getScheme($url);
        return in_array($scheme, $this->schemeWhiteList);
    }

    public function filterPort($url)
    {
        $port = $this->getPort($url);
        return in_array($port, $this->portWhiteList);
    }

    public function filterHost($url)
    {
        $host = $this->getHost($url);
        return in_array($host, $this->hostWhiteList);
    }

    public function getPort($url)
    {
        $info = $this->getInfo($url);
        return $info['port'];
    }


    public function getScheme($url)
    {
        $info = $this->getInfo($url);
        return $info['scheme'];
    }

    public function getHost($url)
    {
        $info = $this->getInfo($url);
        return $info['host'];
    }

    public function parseInfo($url)
    {
        return parse_url($url);
    }

    public function getInfo($url)
    {
        if (empty($this->info[md5($url)])){
            $this->info[md5($url)] = $this->parseInfo($url);
        }
        return $this->info[md5($url)];
    }

    public function getPathExt($url)
    {
        return pathinfo($url, PATHINFO_EXTENSION);
    }

    public function filterPathExt($url)
    {
        $ext = $this->getPathExt($url);
        return in_array($ext, $this->fileTypeWhiteList);
    }

}

发布了253 篇原创文章 · 获赞 47 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/why444216978/article/details/104600051