一、原理:基于环境变量的条件日志

Apache  本身没有区分国密流量的内置功能,但可以通过  `SetEnvIf`  或  `SetEnvIfExpr`  指令,根据  SSL/TLS  连接的特征设置自定义环境变量,再由  `CustomLog`  配合  `env=`  参数将流量写入不同日志文件。

鉴别的关键在于识别国密流量。Apache  支持国密通常有两种场景:

-  使用国密专用模块(如  Tongsuo、GMSSL  等):握手日志中会包含特定关键词(如  `GMSSLv1.2`)

-  使用通用国密加密套件:流量使用的密码套件名称包含国密算法标识(如  `SM2-SM3-SM4`、`ECC-SM4-SM3`  等)

二、在访问日志中识别并记录国密流量

方案  1:在通用访问日志中增加国密标识字段

修改  Apache  配置(如  `/etc/httpd/conf.d/ssl.conf`),创建或修改日志格式,在原有日志行末尾增加国密协议和密码套件信息:

LogFormat  "%h  %l  %u  %t  \"%r\"  %>s  %b  \"%{Referer}i\"  \"%{User-Agent}i\"  %{SSL_PROTOCOL}x  %{SSL_CIPHER}x"  ssl_combined

CustomLog  logs/ssl_access.log  ssl_combined

效果示例:

192.168.1.100  -  -  [27/Apr/2026:21:30:15  +0000]  "GET  /  HTTP/1.1"  200  1234  "-"  "curl/8.10.1"  TLSv1.3  TLS_AES_256_GCM_SHA384

如需在日志行中明确标记为国密请求,可以利用  `LogFormat`  中的条件判断,或配合后续方案进行文件分离。

方案  2:将国密流量单独记录到独立文件(推荐)

核心思路:先用  `SetEnvIf`  设置标记变量,再用  `CustomLog`  按标记分流。

步骤  1:定义日志格式

apache

#  定义国密专用日志格式(可包含额外字段)

LogFormat  "%h  %l  %u  %t  \"%r\"  %>s  %b  \"%{Referer}i\"  \"%{User-Agent}i\"  %{SSL_PROTOCOL}x  %{SSL_CIPHER}x"  gm_log_format

步骤  2:设置国密流量标记变量**

根据国密密码套件特征设置标记。此处以套件名称包含  `SM`  为例,实际需根据所用的国密模块和套件名称进行调整:

apache

#  方法  A:使用  SetEnvIf  匹配套件名称中的国密标识

SetEnvIf  SSL_CIPHER  "SM[2-4]"  is_gm_traffic

SetEnvIf  SSL_CIPHER  "SM2-SM3-SM4"  is_gm_traffic

#  方法  B:若国密协议握手日志包含  GMSSL  关键词,也可匹配(需确认实际关键词)

SetEnvIf  SSL_PROTOCOL  "GMSSL"  is_gm_traffic

#  方法  C:利用  HTTPS  环境变量区分  SSL/非  SSL(如果需要将国密与非  SSL  分离)

#  此方案仅用于分离  HTTPS  和  HTTP  流量,不区分国密与普通  HTTPS

SetEnv  HTTPS

步骤  3:配置分流日志

apache

#  国密流量写入专用日志

CustomLog  logs/gm_access.log  gm_log_format  env=is_gm_traffic

#  非国密  SSL  流量写入普通  SSL  日志(或通配日志)

CustomLog  logs/ssl_access.log  gm_log_format  env=!is_gm_traffic

其中  `env=is_gm_traffic`  表示仅记录标记为  `is_gm_traffic`  的请求,`env=!is_gm_traffic`  表示仅记录未标记的请求。

可选:使用  `SetEnvIfExpr`  实现更灵活的匹配

若  `SetEnvIf`  无法识别指定变量,可以改用  Apache  2.4  引入的表达式引擎:

apache

#  匹配国密套件名称(正则表达式需根据实际套件名称调整)

SetEnvIfExpr  "%{SSL_CIPHER}  =~  /SM\d+/"  is_gm_traffic

#  匹配  GMSSL  协议标识

SetEnvIfExpr  "%{SSL_PROTOCOL}  =~  /^GMSSL/"  is_gm_traffic

这种写法在某些场景下兼容性更好,但仍需确保相关  SSL  变量已被正确导出。

三、将国密握手及错误日志分离

如果需要将国密相关的握手信息和错误日志单独存储,可以调整  `LogLevel`  级别:

apache

#  将  SSL  模块的日志级别提升为  debug,用于国密握手调试

LogLevel  ssl:debug

#  将  SSL  调试日志输出到单独文件

SSLLogFile  /var/log/httpd/gm_ssl_engine.log

注意:`SSLLogFile`  指令在某些编译版本的  Apache  中可能不可用。如果不支持,可以使用  `ErrorLog`  配合  `LogLevel`  将  SSL  相关信息输出到指定错误日志文件:

apache

ErrorLog  /var/log/httpd/gm_error.log

LogLevel  ssl:debug

需要特别注意的是,将  `LogLevel`  调至  `debug`  会产生大量日志,仅建议在调试国密连接问题或短期监控期间开启,不应在生产环境长期使用。调试完成后,将  `LogLevel`  恢复为  `info`  或  `warn`  级别,以免影响磁盘空间和系统性能。

四、完整配置示例

以下是一个完整的配置片段,可直接放入  Apache  配置目录(如  `/etc/httpd/conf.d/gm-ssl.conf`):

apache

#  加载必要模块(根据实际国密环境调整)

LoadModule  ssl_module  modules/mod_ssl.so

LoadModule  setenvif_module  modules/mod_setenvif.so

#  SSL  全局配置

Listen  443

<VirtualHost  *:443>

        SSLEngine  on

        #  国密证书配置

        SSLCertificateFile  /path/to/gm_server.crt

        SSLCertificateKeyFile  /path/to/gm_server.key

        #  定义国密专用日志格式

        LogFormat  "%h  %l  %u  %t  \"%r\"  %>s  %b  \"%{Referer}i\"  \"%{User-Agent}i\"  %{SSL_PROTOCOL}x  %{SSL_CIPHER}x"  gm_log_format

        #  设置国密流量标记(请根据实际套件名称调整正则规则)

        SetEnvIf  SSL_CIPHER  "SM[2-4]"  is_gm_traffic

        #  分流:国密流量与普通  SSL  流量分别记录

        CustomLog  logs/gm_access.log  gm_log_format  env=is_gm_traffic

        CustomLog  logs/ssl_access.log  gm_log_format  env=!is_gm_traffic

        #  可选:SSL  引擎日志,用于国密握手调试(注意:生产环境请谨慎开启  debug  级别)

        #  LogLevel  ssl:debug

        #  SSLLogFile  /var/log/httpd/gm_ssl_engine.log

        ServerName  gm.example.com

        DocumentRoot  /var/www/html

</VirtualHost>

五、注意事项

1.  国密套件名称取决于具体的国密实现(如  Tongsuo、GMSSL  等),请先通过访问日志确认实际输出的  `SSL_CIPHER`  字段内容,再调整正则表达式。

2.  `SetEnvIf`  默认只能读取  HTTP  请求头字段,如需直接读取  `SSL_PROTOCOL`  和  `SSL_CIPHER`  变量,可以尝试使用  `SetEnvIfExpr`。

3.  若  SSL  相关变量未正确传递,需要在虚拟主机配置中显式启用  `SSLOptions  +StdEnvVars`  指令,确保所有  SSL  环境变量可用于日志记录。

4.  建议同时配置日志轮转(如  `logrotate`),避免国密访问日志占用过多磁盘空间。

六、快速验证步骤

1.  查看当前  SSL  日:先不设置分流,使用  `LogFormat  "%{SSL_PROTOCOL}x  %{SSL_CIPHER}x"`  记录几分钟,观察实际输出的国密套件名称和协议标识。

2.  根据输出调整正则:将实际观测到的国密特征字符串填入  `SetEnvIf`  的正则表达式中。

3.  重启  Apache  并观察:`systemctl  restart  httpd`,然后用国密浏览器访问站点,检查  `gm_access.log`  是否产生记录。