SSI注入(Server Side Includes Injection)是一种被严重低估的网站安全漏洞,攻击者通过在网页输入框、URL参数或表单字段中注入SSI指令,让服务器端直接解析执行恶意代码,从而获取服务器文件读取权限、执行系统命令甚至提权。最直接有效的防护方案就是从服务器配置层面彻底禁用SSI功能,同时配合输入过滤、WAF规则和权限最小化原则,形成多层防御体系。下面我会把每一步怎么做、为什么这么做、用什么工具验证,全部讲清楚。
一、SSI注入到底是什么,为什么危险
SSI是Apache、Nginx等Web服务器内置的一种服务器端包含技术,原本用于在HTML页面中动态插入文件内容、执行系统命令或显示环境变量。它的指令通常以"<!--#"开头,比如<!--#exec cmd="ls" -->就能让服务器执行ls命令列出目录文件。问题在于,如果网站开启了SSI功能,又没有对用户输入做严格过滤,攻击者只需要在任何可输入的地方(评论框、搜索框、URL的query参数)写入SSI指令,服务器就会当成合法指令去解析执行。这意味着攻击者可以读取/etc/passwd、执行任意Shell命令、甚至通过SSI调用其他漏洞进一步渗透。这种攻击不需要上传文件,不需要复杂的利用链,门槛极低但危害极大。
二、如何确认你的服务器是否开启了SSI
在动手禁用之前,先确认当前状态。对于Apache服务器,检查httpd.conf或对应站点的虚拟主机配置文件中是否有以下内容:
AddType text/html .shtml AddHandler server-parsed .shtml Options +Includes
如果存在这些配置,说明SSI是开启的。对于Nginx,默认情况下Nginx本身不支持SSI,但如果通过第三方模块或错误配置启用了类似功能,也需要排查。快速验证方法是创建一个测试文件test.shtml,写入以下内容:
<!--#echo var="DATE_LOCAL" -->
用浏览器访问这个文件,如果页面上显示了当前日期时间,说明SSI正在运行。如果显示的是原始代码文本,说明SSI未启用或该文件类型未被解析。
三、Apache服务器禁用SSI的具体配置方案
Apache是SSI注入的重灾区,禁用方案分三个层次:全局禁用、目录级禁用、文件类型禁用。
第一种,全局禁用。编辑主配置文件httpd.conf,找到或添加以下指令:
Options -Includes AddType text/html .html .htm AddHandler server-parsed .shtml .shtm
这会告诉Apache不要对任何文件执行服务器端解析。如果你只想禁用SSI但保留其他Includes功能(如mod_include的其他用途),可以更精细地控制:
<Directory "/var/www/html">
Options -Includes
AllowOverride None
</Directory>
第二种,针对特定目录禁用。如果你的网站只有某个子目录使用了SSI(比如旧版CMS遗留),可以只在那个目录下禁用:
<Directory "/var/www/html/legacy">
Options -Includes
RemoveHandler .shtml .shtm
</Directory>
第三种,禁用特定文件扩展名的SSI解析。如果你确实需要在某些页面使用SSI的合法功能(比如显示服务器时间),但又想限制范围:
RemoveHandler .shtml .shtm AddType text/html .shtml .shtm
这样.shtml文件就会被当作普通HTML处理,不再解析SSI指令。修改配置后务必执行apachectl configtest检查语法,然后systemctl reload apache2或service httpd reload重载配置。
四、Nginx服务器的SSI防护策略
Nginx原生不支持SSI,但如果你使用了ngx_http_ssi_module模块(某些旧版本或定制编译版可能包含),需要在配置中明确禁用:
location ~* \.shtml$ {
ssi off;
}
更稳妥的做法是在编译Nginx时就不要加入SSI模块。如果你不确定,可以检查nginx -V的输出参数中是否有--with-http_ssi_module。对于绝大多数现代Nginx部署,SSI本身就不是问题,重点要防的是其他类型的注入,比如通过fastcgi_param或uwsgi_param传递恶意参数。建议在Nginx层面加上以下通用防护:
if ($query_string ~* "<!--#") {
return 403;
}
这条规则会拦截所有包含SSI指令特征的请求。但注意,if指令在Nginx中有性能和安全隐患,生产环境建议用map或lua模块实现更优雅的过滤。
五、IIS服务器的SSI禁用方法
Windows环境下的IIS服务器同样支持SSI,禁用方法是在IIS管理器中找到对应站点或应用程序,进入"处理程序映射"(Handler Mappings),删除或禁用.shtml、.shtm的SSI处理程序。也可以通过命令行操作:
appcmd set config /section:handlers /-"[name='SSINC-shtml']"
或者在web.config中直接移除:
<system.webServer>
<handlers>
<remove name="SSINC-shtml" />
<remove name="SSINC-shtm" />
</handlers>
</system.webServer>
六、输入过滤和WAF层面的纵深防御
光禁用SSI还不够,因为攻击者可能绕过SSI直接利用其他注入漏洞(SQL注入、命令注入、XSS)。必须在应用层和网络层同时设防。在应用代码层面,对所有用户输入进行白名单过滤,拒绝包含"<!--#"、"<!--"、"exec"、"cmd"等关键词的内容。以下是一个PHP示例:
<?php
function sanitize_input($input) {
$patterns = array(
'/<!--#/i',
'/<!--/i',
'/exec\s+/i',
'/cmd\s*=/i',
'/include\s+/i'
);
$input = preg_replace($patterns, '', $input);
return htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
}
?>
在WAF(Web应用防火墙)层面,配置规则拦截包含SSI特征字符串的请求。如果你使用ModSecurity,可以添加如下规则:
SecRule REQUEST_BODY|REQUEST_URI|ARGS "@rx <!--#" \
"id:1000001,\
phase:1,\
deny,\
status:403,\
log,\
msg:'SSI Injection Attempt Detected'"
七、文件权限和最小权限原则
即使SSI被禁用,如果服务器文件权限配置不当,攻击者通过其他漏洞拿到Web用户权限后仍然可以读取敏感文件。确保Web进程(如www-data、apache、nginx用户)只能访问必要的目录和文件。具体做法:
网站根目录权限设为750或755,敏感配置文件(如.env、数据库配置)设为640或600,属主为Web用户,属组为管理员组。上传目录禁止执行权限:chmod 755 /var/www/html/uploads,同时在Nginx或Apache中禁止该目录执行脚本:
<Directory "/var/www/html/uploads">
Options -ExecCGI -Includes -Indexes
AllowOverride None
</Directory>
八、定期扫描和漏洞验证
禁用配置完成后,需要用工具验证防护是否生效。可以使用Nikto、Nmap的http-enum脚本、或者专门的SSI注入测试工具进行扫描。自己也可以手动构造测试请求:
http://yourdomain.com/page.html?param=<!--#exec%20cmd="id"-->
如果返回403、404或者原始代码文本而非命令执行结果,说明防护有效。建议把这种测试纳入每月安全巡检流程,因为服务器配置可能被运维误改、被其他软件覆盖、或者新部署的应用重新开启了SSI。
九、总结和最佳实践建议
SSI注入防护的核心逻辑就三句话:能不开就不开,开了就限制到最小范围,同时配合输入过滤和权限控制做纵深防御。不要觉得SSI是老技术就不重视,很多遗留系统和低版本CMS还在用,而攻击者恰恰喜欢找这种被遗忘的角落。从服务器配置文件入手,把Options -Includes写死,把不需要的Handler移除,把文件权限收紧,再加上WAF规则兜底,基本就能把SSI注入的风险降到接近零。安全不是一次性的工作,是持续的过程,配置改完要验证,验证完要监控,监控完要定期复查。
