生产环境 vendor 目录必须设为只读,因php运行时仅需读取代码,写权限会引发webshell注入和部署不一致风险;正确做法是chown归部署用户、chmod 755目录、find -type f设644文件权限、单独chmod +x vendor/bin/*,并确保www-data属deploy组且有组读执行权。

生产环境 vendor 目录必须设为只读,但不能简单 chmod -R 555 —— 否则 autoload 会失败,PHP 进程连 opendir() 都被拒。
为什么 vendor/ 设为只读是硬性要求
PHP 运行时(如 Nginx + PHP-FPM)只需读取 vendor 中的代码,写权限既无必要,又引入两类确定性风险:
- 攻击者利用未过滤的缓存路径、日志注入或反序列化漏洞,向
vendor/composer/或vendor/{pkg}/src/写入 Webshell - 误执行
composer dump-autoload或composer install(比如通过部署脚本漏删 dev 命令),破坏已验证的部署一致性
Laravel、Symfony 等框架明确将 vendor/ 视为不可变资产,storage/ 和 bootstrap/cache/ 才是运行时可写目录。
chmod -R 555 vendor/ 是典型错误操作
它会让 PHP 进程无法进入子目录(缺执行位),报错如:Warning: require(/var/www/app/vendor/autoload.php): failed to open stream;更糟的是,某些框架会在 vendor/composer/ 下尝试写 autoload_static.php 或 installed.json 快照,直接触发 Permission denied。
正确做法是分层控制:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
-
chown -R deploy:deploy vendor/→ 归属部署用户,避免 root 残留 -
chmod 755 vendor/→ 目录需执行位(x),否则无法遍历 -
find vendor/ -type f -exec chmod 644 {} \;→ 所有文件去写权限,保留读+执行组权限 -
chmod +x vendor/bin/* 2>/dev/null || true→ 仅放行明确需要执行的二进制(如phinx),其余删掉 - 若应用依赖动态类映射(如某些插件机制),需单独保留
vendor/composer/autoload_classmap.php可写,否则应预生成并设为 644
CI/CD 构建后同步到生产环境的权限陷阱
rsync 或 cp -r 会继承源端 umask 或挂载点权限,常见现象:
-
file_put_contents(/var/www/app/vendor/composer/autoload_static.php): Failed to open stream: Permission denied→ 实际是vendor/composer/目录属主为 root,而 PHP 进程以 www-data 运行,且未加入 deploy 组 -
Could not scan for classes inside "app/Console"→composer dump-autoload在 CI 中执行成功,但生成的autoload_*.php文件权限为 600,部署后 www-data 无读权
修复关键点:
- 确保 www-data 属于 deploy 组:
usermod -aG deploy www-data - CI 构建阶段就用
find vendor -type f -perm /u+w -exec chmod 644 {} \;清洗所有可写文件 - 避免在构建机用 root 执行
composer install,改用部署用户或指定--no-interaction --no-dev并验证归属
vendor/ 下哪些文件必须清理,否则等于开放攻击面
composer install --no-dev --optimize-autoloader --classmap-authoritative --no-interaction 只控制“装什么”,不清理“留什么”。以下内容必须在构建后删除:
-
vendor/bin/:全删,除非你明确需要phinx或doctrineCLI 在线上运行 -
vendor/**/tests/、vendor/**/Tests/、vendor/**/test/、vendor/**/Test/ vendor/**/{.git,.gitignore,.travis.yml,phpunit.xml,phpstan.neon,psalm.xml}-
vendor/**/docs/、vendor/**/examples/、vendor/**/demo/ -
vendor/composer/installed.json:含全部包哈希与版本,泄露后可精准匹配 CVE
Linux/macOS 推荐命令:find vendor -path '*/tests' -o -path '*/.git' -o -name 'phpunit.xml' -delete;CI 中建议显式 rm -rf,不依赖 glob 匹配。
真正难的不是 chmod 数字怎么填,而是让 chown、find -exec chmod、rm -rf 这三步在 CI 流水线里稳定执行,并确保部署用户、Web 用户、组权限三者对齐 —— 少一步,权限就断在 runtime。










