其它>> 对 NULL 使用 (++) 生成 1. 对 NULL 用 (--) 生成 NULL. >> 没有生成器. Web 框架执行环境>> 一个单一共享文件 php.ini, 控制了 PHP 的大部分功能并织入了复杂的针对覆盖什么与何时覆盖的规则. PHP软件能部署在任意的机器上, 因此必须覆盖一些设置使环境正常, 这在很大程序上会违背像 php.ini 这样的机制的使用. >> PHP基本上以CGI运行. 每次页面被点击, PHP 在执行前, 重编译整个环境. 就连 Python 的玩具框架的开发环境都不会这样. >> 这就导致了整个 "PHP 加速器" 市场的形成, 仅仅编译一次, 就能加速PHP, 就像其它的语言一样. Zend, PHP的幕后公司, 將这个做为它们的商业模式. >> 很长时间以来, PHP的错误默认输出给客户端 -- 我猜是为开发环境提供帮助. 我不认为这是真相, 但我仍然看到偶尔会有mysql 错误出现在页面的顶部. >> 在 <?php ... ?>标签外的空白, 甚至在库中, PHP以文本对待并解析给响应 (或者导致 "headers already sent" 错误). 一个流行的做法是忽略 ?>关闭标签. 部署部署方式常常被引述为PHP的最高级部分: 直接部署文件就可以了. 是的, 这比需要启动整个进程的 Python 或 Rury 或 Perl 要容易. 但 PHP 留下了许多待改进的地方. 我很乐意以应用服务器的方式运行Web应用程序并反向代理它们. 这样的代价最小, 而好处多多: 你可以单独管理服务器和应用程序, 你可以按机器的多或少运行运行多个或少量应用进程, 而不需要多个web服务器,你可以用不同的用户运行应用, 你可以选择web服务器, 你可以拆下应用而无需惊动web服务器, 你可以无缝部署应用等等. 將应用与web服务器直接焊接是荒谬的, 没有什么好的理由支持你这么做. >> 每个 PHP 应用程序都使用 php.ini . 但只有一个 php.ini 文件, 它是全局的; 如果你在一个共享的服务器上, 需要修改它, 或者如果你运行两个应用需要不同的设置, 你就不走运了; 你不得不向组织申请所有必须的设置并放在应用程序, 如使用 ini_set 或在 Apache 的配置文件或在 .htaccess设置. 如果你能做的话. 可能 wow , 你有大量的地方需要检查以找出怎样获取已设置的值. >> 类似的, "隔离"PHP应用的方法也不容易, 它依赖于系统的其它部分. 想运行两个应用程序,想要不同的库版本, 或不同的PHP版本本身? 开始构建另一人Apache的拷贝吧. >> "一堆文件"方案, 除了使路由像只病重的笨驴外, 还意味着你不得不小心处理白名单或黑名单, 以控制什么东西可访问, 这是因为你的 URL 层次也就是你的代码树的层次. 配置文件和其它的"局部模块"需要C之类的东西守护以避免直接加载. 版本控制系统的文件(如 .svn) 需要保护. 使用 mod_php , 使得文件系统的所有东西都是潜在的入口; 使用应用服务器, 仅有一个入口, 并且仅通过 URL 控制调用与否. >> 你不能无缝的升级那堆以 CGI-style 运行的文件, 除非你想要应用崩溃和出现未定义行为, 当用户在升级的间歇期点击你的站点时. >> 尽管配置 Apache 运行 PHP 很"简单", 仍然会有一些陷阱. 而 PHP 文档建议使用 SetHandler 使得 .php 文件以 PHP方式运行, AddHandler 看起来运行良好, 然而事实上会有问题. 当你使用 AddHandler, 你在告知 Apache "以 php 执行它" , 这是一个可能的处理 .php 文件的方式. 但! Apache 对文件的扩展名不这样认为. 它被设计为能支持如, index.html.en 这样的文件. 对于 Apache , 文件可以同时具有任意数量的扩展名. 猜想, 你有个文件上传的表单, 存储一些文件到公共目录中. 确保没人能上传 PHP 文件, 你仅仅检查文件不能有.php 扩展名. 所有的攻击需要做的只是上传以 foo.php.txt 命名的文件; 你的上传工具不会看出问题, Apache 会认为它是个 PHP, 它会很高兴的执行. 这里不是 "使用原始文件名" 或 "没有更好的验证"导致的问题; 问题是你的web服务器要被配置用来运行任何旧代码, 使得PHP "容易部署". 这不是理论上的问题; 我已发现很多实际的站点有类似的问题了. 缺失的特性我认为所有这些都是以构建一个Web应用为中心的. 对PHP看起来很合理, 是它的销售卖点之一, 它是 "Web语言", 理应有它们. >> 无模块系统. PHP就是模版. >> 无 XSS 过滤器. htmlspecialchars 不是 XSS 过滤器. >> 无 CSRF 保护. 你必须自己做. >> 无通用标准的数据库API. 像PDO这类东西不得不包装每个特定数据库的API, 分别抽象不同部分. >> 无路由系统. 你的站点结构就是你的文件系统结构. >> 无认证或授权. >> 无开发服务器. >> 无交互调试模式. >> 无一致的部署机制; 仅仅"拷贝所有文件到服务器中". 安全语言边界PHP的蹩脚安全机制可能会放大, 因为它利用某语言拿出数据, 又把它转存到另一个中. 这是个坏注意. "<script>" 可能在SQL中意味着什么都不是, 但在HTML中就很是了. 让情况更糟糕的是通常有人哇哇喊到 "你的输入要消毒". 那完全错误; 你不可能有什么魔法使块数据完全"干静". 你需要做的就是对语言说: SQL使用占位符, 进程孵化使用参数列表, 等等. >> PHP公然鼓励 "消毒": 有个数据过滤扩展可以做到. >> 所有的 addslashes, scripslashes, 和其它的 slashes相关的东西都是废物, 毫无用处. >> 我只能告诉你这么多, 无法安全的孵化进程. 你仅能通过shell执行字符串. 你的选择是疯狂的转义, 并希望默认的shell使用正确的转义, 或手动的 pcntl_fork_exec 和 pcntl_exec. >> 所有的转义命令和转义参数存在大致相同的描述. 注意在Windows中, 转义参数不工作 (因为它假设成 Bourne shell 语议), 转义命令仅仅用空格替换一堆标点符号, 因为没人能搞清楚 Windows 命令转义行为 (它可能默默的破坏你试图做的任何事情). >> 原始的内建 MySQL 绑定, 仍然广泛使用, 它无法创建 prepared statements. 直到今天, PHP 文档关于SQL注入的建议还是让人抓狂的做如类型检查, 使用sprintf 和 is_numeric, 在每个地方手动的使用mysql_real_escape_string , 或在每处手动使用 addslashes (这个"可能更有用"!) 这样的实践. 并没有提到 PDO 或 参数化, 除了在用户评论中有点线索. 至少在两年以前, 我就有具体的向 PHP dev 抱怨过了 , 他被惊动了, 而页面却从未变过. Insecure-by-default>> register_globals. 它被默认关闭的,而在5.4中去除了. 我不在乎. >> include 接受 HTTL URLS. 和上面一样. >> Magic quotes. So close to secure-by-default, and yet so far from understanding the concept at all. 核心PHP解释器本身就有一些恼人的安全问题. >> 2007年的时候, 解析器有个整数溢出漏洞. 修复始于 if(size > INT_MAX) return NULL; 从那以后就走下坡路了. (对于那些不需要使用C的人: 曾经, INT_MAX 是适合变量最大整数. 我希望你能从这里搞清楚其余的东西.) >> 最近, PHP 5.3.7 包括了个 crypt() 函数, 有个漏洞让任何人可以用任何密码登录. >> PHP5.4是容易遭受拒绝服务攻击,因为它需要Content-Length头(任何人都可以设置),并试图分配更多内存。这是一个坏主意。 我可以挖掘更多, 但重点不是这有很多X漏洞 -- 是软件就有bugs, 无论如何都有. 这些自然是令人咋舌. 我并没有特意寻找这些; 但在过去的几个月里, 它们自己送上门来了. 总结一些评论会理所当然的指出我没得出任何结论. 好吧, 我是没有结论. 如果你一路看到了这里, 我假设一开始你就同意我了 :) 如果你仅了解PHP而对学习其它东西感兴趣, 可以看看 Python 教程, 尝试 Flask 这个为web准备的家伙. (我不是它的模版语言的铁杆粉丝, 但它确实很好的完成了这些工作.) 它將你的应用分成多个部分, 但它们看起来仍然是一致的. 我可能稍后会写个关于这个的贴子; 旋风般的介绍整个语言和不同于这里所说的web堆栈. 之后或对于更大的项目, 你可能需要 Pyramid, 一个中等规模的框架, 或者是 Django, 一个构建站点的复杂的框架, 如 Django站点. |