
在将php zend应用迁移至aws ec2后,用户常遇到“the form submitted did not originate from the expected site”错误,尤其在登录时。此问题通常与跨站请求伪造(csrf)保护机制对请求来源的验证失败有关。本文将深入分析其原因,并提供通过强制使用https协议来有效解决此问题的专业指南。
深入理解“非预期来源”错误及其根源
当PHP应用程序在AWS EC2环境中出现“The form submitted did not originate from the expected site”错误时,这通常是应用程序内置的跨站请求伪造(CSRF)保护机制被触发的结果。CSRF保护旨在确保表单提交请求确实来源于用户当前正在访问的网站,而非恶意第三方站点。它通常通过验证请求的Origin或Referer头部信息,或通过比对会话中存储的CSRF令牌来实现。
在迁移Web应用到云环境(如AWS EC2)时,特别是当涉及到协议变更(从HTTP到HTTPS)或引入负载均衡器/反向代理时,这个错误尤为常见。其核心原因在于,应用程序对请求协议或来源的判断与实际情况不符,导致CSRF验证失败:
- 协议不一致性: 最常见的情况是,应用程序在内部生成链接或验证请求时,期望使用HTTPS协议,但由于某种原因(例如,通过HTTP访问负载均衡器,再由负载均衡器转发到后端EC2实例的HTTP端口),应用程序接收到的请求被认为是HTTP协议。这种协议上的不匹配会使得Origin或Referer头部在应用程序看来是“不信任”的,或者与预期不符。
- 负载均衡器/反向代理的影响: 在AWS EC2架构中,通常会在前端部署Application Load Balancer (ALB) 或 Network Load Balancer (NLB)。用户通过HTTPS访问ALB,ALB再通过HTTP(或HTTPS)将请求转发到后端的EC2实例。如果应用程序没有正确配置来识别ALB转发的原始协议(通常通过X-Forwarded-Proto等头部),它可能会误认为请求是通过HTTP接收的。
- 会话Cookie安全标志: 如果应用程序在HTTPS环境下设置了带有Secure标志的会话Cookie,但后续请求尝试通过HTTP发送,浏览器将拒绝发送该Cookie,导致会话丢失,进而影响CSRF令牌的验证。
解决方案:强制使用HTTPS协议
根据经验,将网站的访问协议从HTTP完全切换到HTTPS,并确保整个请求链路都使用HTTPS,是解决此问题的最有效方法。这不仅能解决CSRF验证问题,还能显著提升网站的安全性。
1. 配置AWS负载均衡器(ALB/NLB)以终止HTTPS
这是在AWS上部署Web应用时推荐的最佳实践。
立即学习“PHP免费学习笔记(深入)”;
-
步骤一:获取SSL证书。
在AWS Certificate Manager (ACM) 中申请或导入您的SSL/TLS证书。ACM可以免费为AWS资源(如ALB)提供证书。 -
步骤二:配置ALB监听器。
在您的ALB上,添加一个HTTPS (端口443) 监听器。将该监听器配置为使用您在ACM中获取的证书。 -
步骤三:配置ALB目标组。
将您的EC2实例注册到ALB的目标组中。目标组的协议可以设置为HTTP(端口80)或HTTPS(端口443),取决于您的EC2实例上的Web服务器配置。- 推荐做法:ALB终止HTTPS,后端EC2使用HTTP。 这种方式可以减轻EC2实例的SSL/TLS加密解密负担。在这种情况下,ALB会将原始协议信息通过X-Forwarded-Proto头部传递给后端实例。
- ALB与后端EC2均使用HTTPS。 如果您的安全策略要求端到端加密,ALB可以配置为使用HTTPS转发到后端EC2实例的HTTPS端口。
示例:ALB配置(伪代码/概念)
// ALB Listener Configuration for HTTPS (Port 443)
{
"Protocol": "HTTPS",
"Port": 443,
"Certificates": [
{
"CertificateArn": "arn:aws:acm:REGION:ACCOUNT_ID:certificate/YOUR_ACM_CERT_ID"
}
],
"DefaultActions": [
{
"Type": "forward",
"TargetGroupArn": "arn:aws:elasticloadbalancing:REGION:ACCOUNT_ID:targetgroup/YOUR_TARGET_GROUP_NAME"
}
]
}
// Target Group Configuration (e.g., HTTP to backend)
{
"Protocol": "HTTP",
"Port": 80, // Or 443 if backend also uses HTTPS
"VpcId": "vpc-YOUR_VPC_ID",
"HealthCheckProtocol": "HTTP",
"HealthCheckPort": "traffic-port"
}
2. 配置EC2实例上的Web服务器(以Apache为例)
如果您的Web服务器直接暴露在公网(不推荐用于生产环境,除非有特定需求),或者您希望ALB到EC2实例之间也强制使用HTTPS,则需要在EC2实例上配置Web服务器。
-
步骤一:安装mod_ssl (Apache HTTP Server)。
sudo yum install mod_ssl # CentOS/RHEL sudo apt-get install libapache2-mod-ssl # Debian/Ubuntu
登录后复制 -
步骤二:获取SSL证书。
您可以使用Let’s Encrypt通过Certbot工具获取免费的SSL证书。sudo yum install epel-release sudo yum install certbot python3-certbot-apache # CentOS/RHEL sudo apt-get install certbot python3-certbot-apache # Debian/Ubuntu sudo certbot --apache -d yourdomain.com -d www.yourdomain.com
登录后复制Certbot会自动配置Apache的SSL虚拟主机。
-
步骤三:配置Apache虚拟主机。
确保您的Apache配置(通常在/etc/httpd/conf.d/ssl.conf或/etc/apache2/sites-available/default-ssl.conf)正确指向您的SSL证书和私钥。<VirtualHost *:443> ServerName yourdomain.com DocumentRoot /var/www/html/your_php_app SSLEngine on SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem # 其他配置,如日志、目录权限等 <Directory /var/www/html/your_php_app> AllowOverride All Require all granted </Directory> </VirtualHost> # 可选:将所有HTTP请求重定向到HTTPS <VirtualHost *:80> ServerName yourdomain.com Redirect permanent / https://yourdomain.com/ </VirtualHost>登录后复制 -
步骤四:重启Apache服务。
sudo systemctl restart httpd # CentOS/RHEL sudo systemctl restart apache2 # Debian/Ubuntu
登录后复制
3. PHP应用程序层面的调整
如果您的应用程序位于负载均衡器之后,并且负载均衡器将HTTPS请求转发为HTTP到后端,那么应用程序可能需要感知到原始请求是HTTPS。
-
检测X-Forwarded-Proto头部:
大多数PHP框架(如Zend Framework)都提供了识别代理协议的机制。您可以在应用程序的入口文件(如public/index.php)或配置中,根据X-Forwarded-Proto头部来判断当前请求的真实协议。// 示例:在Zend Framework中,可能需要确保URL生成器知道当前协议 // 这通常由框架自动处理,但如果遇到问题,可以手动检查 if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; // 欺骗PHP认为请求是HTTPS } // 或者在Zend的配置中设置 trusted_proxies // config/autoload/global.php 或 local.php /* return [ 'uri' => [ 'trusted_proxies' => [ '172.16.0.0/12', // 您的VPC CIDR 或 ALB的IP范围 ], ], ]; */登录后复制 -
确保Cookie的Secure标志:
当网站完全运行在HTTPS上时,确保会话Cookie设置了Secure标志。这指示浏览器只在HTTPS连接上发送此Cookie,增强安全性。PHP的session.cookie_secure配置项应设置为true。// php.ini 或 .htaccess session.cookie_secure = 1 // 或者在代码中 ini_set('session.cookie_secure', 1);登录后复制
注意事项与最佳实践
- 清除浏览器缓存和Cookie: 在进行协议更改后,务必让用户清除浏览器缓存和Cookie,以确保新的会话和CSRF令牌能够正确生成和处理。
- 监控和日志: 密切关注Web服务器和应用程序日志,以便在出现问题时快速定位。
- 安全性: 始终将HTTPS作为生产环境的强制要求。它不仅解决了CSRF问题,还保护了数据传输的完整性和机密性。
- 性能: 使用AWS ALB终止SSL/TLS可以减轻EC2实例的CPU负担,提高整体性能。
-
HSTS (HTTP Strict Transport Security): 考虑启用HSTS头部,强制浏览器在后续访问中始终使用HTTPS,即使用户输入的是HTTP URL。
# Apache配置 <IfModule mod_headers.c> Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" </IfModule>登录后复制
总结
“The form submitted did not originate from the expected site”错误在PHP应用迁移到AWS EC2时是一个常见但可解决的问题。其根本原因在于CSRF保护机制对请求来源或协议的误判。通过强制使用HTTPS协议,无论是通过AWS负载均衡器终止SSL,还是直接在EC2实例的Web服务器上配置HTTPS,都能有效解决协议不一致性导致的问题,确保CSRF验证机制正常工作。结合应用程序层面的适当调整和遵循最佳实践,可以构建一个既安全又稳定的Web环境。
以上就是解决EC2上PHP应用表单提交“非预期来源”错误:HTTPS协议配置指南的详细内容,更多请关注php中文网其它相关文章!


