Shodan与普通搜索引擎最大的区别在于,它不会等待爬虫抓取网页内容,而是直接对全球公网IP地址进行端口扫描和服务识别。当一台Nginx服务器暴露在公网时,Shodan会通过80端口或443端口发起请求,读取HTTP响应头、错误页面、重定向行为以及TLS证书等特征,并将这些信息存入可检索的数据库。也就是说,攻击者无需事先知道你的域名,只要使用Shodan的搜索语法,就能按国家、端口、服务指纹甚至默认页面标题快速筛选出大量Nginx主机。这种检索能力本身并不违法,但它把原本需要人工探测的暴露面变成了可以批量获取的情报,因此运维人员有必要反过来利用Shodan检查自己的资产是否泄露了过多信息。

下面从Shodan的识别机制、Nginx常见暴露风险、API自动化检查以及安全加固四个层面展开,帮助你把被动暴露变成主动防御。
一、Shodan如何识别Nginx服务
Shodan的扫描节点会对目标IP的常用端口发起TCP连接,端口开放后会进一步发送协议探测报文。针对HTTP服务,它会发送一个标准的GET请求,并记录响应的状态行、响应头和正文摘要。Nginx默认会在响应头中返回Server字段,例如Server: nginx/1.24.0,如果运维没有关闭版本号,Shodan就能直接得到具体版本。此外,Nginx默认的错误页、目录列表样式以及特定配置下的重定向行为也会形成独特指纹,Shodan通过这些特征将服务标记为nginx。
在Shodan的Web界面或命令行工具中,可以使用字段过滤语法进行精确查询。常用字段包括product、server、http.title、http.component、ssl.cert.subject等。例如查询中国境内开放80端口且识别为Nginx的主机,可以输入以下搜索条件:
product:nginx country:CN port:80
如果想找到仍然显示默认欢迎页的Nginx服务器,可以使用http.title字段。默认安装的Nginx欢迎页标题是Welcome to nginx!,搜索语句为:
http.title:"Welcome to nginx!"
Shodan还提供了HTTP响应头的散列值字段http.headers_hash,可以用来查找具有相同响应头组合的主机。比如某些应用在Nginx反向代理后面暴露了自定义X-Powered-By头,攻击者可以借此定位使用同类架构的服务器。理解这些字段是后续暴露检查的基础。
二、Nginx常见暴露风险与检测方法
Nginx本身设计较为安全,但配置不当或使用默认配置会导致信息泄露。最典型的问题是版本号泄露。攻击者获取Nginx具体版本后,可以对照公开漏洞库寻找针对该版本的利用方式。检测方法很简单,直接用curl向目标服务器发送HEAD请求并观察Server响应头:
curl -I http://203.0.113.10/
如果返回结果中包含Server: nginx/1.18.0这样的字段,说明版本号没有隐藏。虽然隐藏版本号并不能阻止攻击者尝试漏洞,但能增加其自动化扫描的成本。另一个常见风险是默认错误页泄露。部分运维在配置自定义错误页时使用了Nginx自带页面,这些页面包含Nginx字样和版本信息。Shodan通过http.title和http.html字段能够检索到这些默认页面。
目录遍历和自动索引也是需要重点检查的项目。Nginx的autoindex指令如果设置为on,访问目录时会列出文件列表。Shodan可以通过http.title:"Index of /"结合product:nginx找到开放目录浏览的主机。还有一类风险是反向代理配置错误,例如将内部管理接口通过location /admin暴露到公网,却没有做访问控制。Shodan本身不直接判断路径,但攻击者会在找到Nginx主机后进一步探测常见路径,因此公网暴露的Nginx必须结合路径扫描结果评估风险。
TLS配置缺陷同样会扩大暴露面。Shodan会记录服务器使用的TLS版本、证书有效期和加密套件。使用ssl.version字段可以筛选仅支持旧版TLS的Nginx主机,例如搜索ssl.version:TLSv1表示仅支持TLS 1.0的服务器,这类主机通常面临降级攻击风险。建议定期使用Shodan的ssl.cert.expired:true语法查找证书过期的资产。
三、利用Shodan API自动化暴露检查
手动在Web界面搜索适合临时查看,但如果要检查多个IP或域名,使用Shodan API会更高效。Shodan提供REST API,支持按IP查询主机信息、按过滤条件搜索服务以及获取实时通知。开发者可以使用官方Python库shodan来编写自动化脚本。下面是一个批量检查Nginx暴露信息的示例脚本,它会读取一组IP地址,输出开放端口、Server响应头中的版本以及页面标题:
import shodan
API_KEY = '你的Shodan API密钥'
api = shodan.Shodan(API_KEY)
def check_host(ip):
try:
host = api.host(ip)
print('IP: %s' % ip)
for item in host.get('data', []):
product = item.get('product', 'unknown')
version = item.get('version', '')
port = item.get('port', 0)
title = item.get('http', {}).get('title', '')
if 'nginx' in product.lower() or 'nginx' in version.lower():
print(' port=%s product=%s version=%s title=%s' % (port, product, version, title))
except shodan.APIError as e:
print('IP: %s Error: %s' % (ip, e))
if __name__ == '__main__':
ips = ['203.0.113.10', '198.51.100.20']
for ip in ips:
check_host(ip)
上述脚本中,api.host方法返回的数据结构里包含data数组,每个元素对应一个开放端口上的服务。http字段中可能包含title、headers等信息,通过检查product或version中是否出现nginx,可以筛选出Nginx服务并输出关键信息。实际使用时,你需要将IP列表替换为自己的公网资产,并确保API密钥具备查询权限。
除了按IP查询,Shodan API还支持search方法,可以直接执行类似前面介绍的过滤语法。例如使用api.search('product:nginx country:CN')可以一次获取大量结果,但需要注意API返回结果数量和账户类型有关。对于批量资产监控,建议将查询结果写入数据库或日志系统,定期对比新增端口和服务,以便及时发现异常暴露。
四、Nginx暴露面收敛与安全加固
检查的目的最终是收敛暴露面。对于仍在公网运行的Nginx,第一项加固措施是隐藏版本号。在Nginx主配置文件中的http块或server块加入server_tokens off;,然后重新加载配置即可。配置示例如下:
http {
server_tokens off;
server {
listen 80;
server_name ipipp.com;
location / {
root /var/www/html;
index index.html;
}
}
}
重新加载后,Nginx返回的Server头会变为Server: nginx,不再包含具体版本。需要注意的是,隐藏版本号不能替代漏洞修复,如果使用的Nginx版本存在已知漏洞,应及时升级到修复版本。第二项加固是修改默认错误页和关闭目录浏览。自定义错误页可以避免默认页面泄露Nginx品牌,同时提升用户体验。将autoindex指令保持为默认的off,或者明确设置为autoindex off;,防止目录内容被列出。
第三项加固涉及访问控制和TLS配置。公网Nginx应只对外开放必要的端口,例如仅开放80和443,其他管理端口通过防火墙或安全组限制来源IP。对于反向代理的后端服务,需要检查location规则是否意外暴露了内部路径,使用deny和allow指令限制敏感路径访问。TLS方面,建议启用TLS 1.2和1.3,禁用旧版协议,并配置合理的加密套件。可以使用Shodan的ssl.version字段定期核查是否仍暴露旧协议。
最后,建议使用Shodan Monitor或类似服务对自有公网IP进行持续监控。Shodan Monitor允许用户添加IP段,当发现新开放端口或服务指纹变化时发送通知。这样可以在攻击者利用之前发现异常暴露。同时,结合企业内部的漏洞扫描和配置审计工具,形成一套完整的暴露面管理流程。Nginx作为使用最广泛的反向代理和Web服务器,其暴露检查不应是一次性工作,而应纳入日常安全运维。

