html-sanitize: NGINX 模块用于清理 HTML 5,支持白名单元素、属性和 CSS
安装
您可以在任何基于 RHEL 的发行版中安装此模块,包括但不限于:
- RedHat Enterprise Linux 7、8、9 和 10
- CentOS 7、8、9
- AlmaLinux 8、9
- Rocky Linux 8、9
- Amazon Linux 2 和 Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-html-sanitize
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-html-sanitize
通过在 /etc/nginx/nginx.conf 顶部添加以下内容来启用模块:
load_module modules/ngx_http_html_sanitize_module.so;
本文档描述了 nginx-module-html-sanitize v0.2.4,于 2019 年 8 月 8 日发布。
示例
以下是根据 https://dev.w3.org/html5/html-author/#the-elements 的 nginx 配置示例:
server {
listen 8888;
location = /sanitize {
# 明确设置 utf-8 编码
add_header Content-Type "text/html; charset=UTF-8";
client_body_buffer_size 10M;
client_max_body_size 10M;
html_sanitize on;
# 检查 https://dev.w3.org/html5/html-author/#the-elements
# 根元素
html_sanitize_element html;
# 文档元数据
html_sanitize_element head title base link meta style;
# 脚本
html_sanitize_element script noscript;
# 部分
html_sanitize_element body section nav article aside h1 h2 h3 h4 h5 h6 header footer address;
# 内容分组
html_sanitize_element p hr br pre dialog blockquote ol ul li dl dt dd;
# 文本级语义
html_sanitize_element a q cite em strong small mark dfn abbr time progress meter code var samp kbd sub sup span i b bdo ruby rt rp;
# 编辑
html_sanitize_element ins del;
# 嵌入内容
htlm_sanitize_element figure img iframe embed object param video audio source canvas map area;
# 表格数据
html_sanitize_element table caption colgroup col tbody thead tfoot tr td th;
# 表单
html_sanitize_element form fieldset label input button select datalist optgroup option textare output;
# 交互元素
html_sanitize_element details command bb menu;
# 其他元素
html_sanitize_element legend div;
html_sanitize_attribute *.style;
html_sanitize_attribute a.href a.hreflang a.name a.rel;
html_sanitize_attribute col.span col.width colgroup.span colgroup.width;
html_sanitize_attribute data.value del.cite del.datetime;
html_sanitize_attribute img.align img.alt img.border img.height img.src img.width;
html_sanitize_attribute ins.cite ins.datetime li.value ol.reversed ol.stasrt ol.type ul.type;
html_sanitize_attribute table.align table.bgcolor table.border table.cellpadding table.cellspacing table.frame table.rules table.sortable table.summary table.width;
html_sanitize_attribute td.abbr td.align td.axis td.colspan td.headers td.rowspan td.valign td.width;
html_sanitize_attribute th.abbr th.align th.axis th.colspan th.rowspan th.scope th.sorted th.valign th.width;
html_sanitize_style_property color font-size;
html_sanitize_url_protocol http https tel;
html_sanitize_url_domain *.google.com google.com;
html_sanitize_iframe_url_protocol http https;
html_sanitize_iframe_url_domain facebook.com *.facebook.com;
}
}
建议使用以下命令来清理 HTML5:
$ curl -X POST -d "<h1>Hello World </h1>" http://127.0.0.1:8888/sanitize?element=2&attribute=1&style_property=1&style_property_value=1&url_protocol=1&url_domain=0&iframe_url_protocol=1&iframe_url_domain=0
<h1>Hello World </h1>
此查询字符串 element=2&attribute=1&style_property=1&style_property_value=1&url_protocol=1&url_domain=0&iframe_url_protocol=1&iframe_url_domain=0 的含义如下:
- element=2: 输出白名单元素由 html_sanitize_element
- attribute=1: 输出任何属性由 html_sanitize_attribute
- style_property=1: 输出任何样式属性由 html_sanitize_style_property
- style_property_value=1: 检查样式值以避免通过 style_property_value 的 XSS 注入
- url_protocol=1: 检查白名单 URL 协议的绝对 URL 由 html_sanitize_url_protocol
- url_domain=0: 不检查绝对 URL 的 URL 域
- iframe_url_protocol=1: 与 url_protocol 相同,但仅适用于
iframe.src由 html_sanitize_iframe_url_protocol - iframe_url_domain=0: 与 url_domain 相同,但仅适用于
iframe.src由 html_sanitize_iframe_url_domain
使用 ngx_http_html_sanitize_module,我们可以通过 directive 和 querystring 指定是否输出 HTML5 的元素、属性和内联 CSS 属性,如下所示:
白名单元素
- 禁用元素:
如果我们不想输出任何元素,可以这样做:
curl -X POST -d "<h1>h1</h1>" http://127.0.0.1:8888/sanitize?element=0
- 启用元素:
如果我们想输出任何元素,可以这样做:
$ curl -X POST -d "<h1>h1</h1><h7>h7</h7>" http://127.0.0.1:8888/sanitize?element=1
<h1>h1</h1><h7>h7</h7>
- 启用白名单元素:
如果我们想输出白名单元素,可以这样做:
$ curl -X POST -d "<h1>h1</h1><h7>h7</h7>" http://127.0.0.1:8888/sanitize?element=1
<h1>h1</h1>
白名单属性
- 禁用属性:
如果我们不想输出任何属性,可以这样做:
curl -X POST -d "<h1 ha=\"ha\">h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=0"
<h1>h1</h1>
- 启用属性:
如果我们想输出任何属性,可以这样做:
$ curl -X POST -d "<h1 ha=\"ha\">h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=1"
<h1 ha="ha">h1</h1>
- 启用白名单属性:
如果我们想输出白名单元素,可以这样做:
$ curl -X POST -d "<img src=\"/\" ha=\"ha\" />" "http://127.0.0.1:8888/sanitize?element=1&attribute=2"
<img src="/" />
白名单样式属性
- 禁用样式属性:
如果我们不想输出任何样式属性,可以这样做:
## 不会输出任何样式属性
curl -X POST -d "<h1 style=\"color:red;\">h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=1&style_property=0"
<h1>h1</h1>
- 启用样式属性:
如果我们想输出任何样式属性,可以这样做:
$ curl -X POST -d "<h1 style=\"color:red;text-align:center;\">h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=1&style_property=1"
<h1 style="color:red;text-align:center">h1</h1>
- 启用白名单样式属性:
如果我们想输出白名单样式属性,可以这样做:
$ curl -X POST -d "<h1 style=\"color:red;text-align:center;\" >h1</h1>" "http://127.0.0.1:8888/sanitize?element=1&attribute=1&style_property=2"
<h1 style="color:red;">h1</h1>
描述
现在 ngx_http_html_sanitize_module 的实现基于 gumbo-parser 和 katana-parser。我们在其基础上进行组合,然后在 nginx 上运行,作为由专业安全人员维护的中心 Web 服务,以消除语言级别的差异。如果我们希望获得更高的性能(这里是 brenchmark),建议编写语言级库以包装纯 C 库,以克服网络传输的开销。
基准测试
在 Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz 和 64GB 内存上使用 wrk -s benchmarks/shot.lua -d 60s "http://127.0.0.1:8888" 进行测试
| 名称 | 大小 | 平均延迟 | QPS |
|---|---|---|---|
| hacker_news.html | 30KB | 9.06ms | 2921.82 |
| baidu.html | 76KB | 13.41ms | 1815.75 |
| arabic_newspapers.html | 78KB | 16.58ms | 1112.70 |
| bbc.html | 115KB | 17.96ms | 993.12 |
| xinhua.html | 323KB | 33.37ms | 275.39 |
| google.html | 336KB | 26.78ms | 351.54 |
| yahoo.html | 430KB | 29.16ms | 323.04 |
| wikipedia.html | 511KB | 57.62ms | 160.10 |
| html5_spec.html | 7.7MB | 1.63s | 2.00 |
指令
html_sanitize
语法: html_sanitize on | off
默认值: html_sanitize on
上下文: location
指定是否在位置上下文中启用 HTML 清理处理程序
html_sanitize_hash_max_size
语法: html_sanitize_hash_max_size size
默认值: html_sanitize_hash_max_size 2048
上下文: location
设置元素、属性、样式属性、URL 协议、URL 域、iframe_url_protocol、iframe_url_domain 哈希表的最大大小。
html_sanitize_hash_bucket_size
语法: html_sanitize_hash_bucket_size size
默认值: html_sanitize_hash_bucket_size 32|64|128
上下文: location
设置元素、属性、样式属性、URL 协议、URL 域、iframe_url_protocol、iframe_url_domain 的桶大小。默认值取决于处理器缓存行的大小。
html_sanitize_element
语法: html_sanitize_element element ...
默认值: -
上下文: location
在通过设置查询字符串 element 白名单模式启用白名单元素时设置允许的 HTML5 元素,如下所示:
html_sanitize_element html head body;
html_sanitize_attribute
语法: html_sanitize_attribute attribute ...
默认值: -
上下文: location
在通过设置查询字符串 attribute 白名单模式启用白名单元素时设置允许的 HTML5 属性,如下所示:
html_sanitize_attribute a.href h1.class;
注意:属性格式必须与 element.attribute 相同,并支持 *.attribute(前缀星号)和 element.*(后缀星号)
html_sanitize_style_property
语法: html_sanitize_style_property property ...
默认值: -
上下文: location
在通过设置查询字符串 style_property 白名单模式启用白名单元素时设置允许的 CSS 属性,如下所示:
html_sanitize_style_property color background-color;
html_sanitize_url_protocol
语法: html_sanitize_url_protocol [protocol] ...
默认值: -
上下文: location
在 linkable attribute 中设置允许的 URL 协议,当仅 URL 为绝对而非相关时,并通过设置查询字符串 url_protocol 检查模式,如下所示:
html_sanitize_url_protocol http https tel;
html_sanitize_url_domain
语法: html_sanitize_url_domain domain ...
默认值: -
上下文: location
在 linkable attribute 中设置允许的 URL 域,当仅 URL 为绝对而非相关时,并通过设置查询字符串 url_protocol 检查模式和查询字符串 url_domain[#url_domain] 检查模式,如下所示:
html_sanitize_url_domain *.google.com google.com;
html_sanitize_iframe_url_protocol
语法: html_sanitize_iframe_url_protocol [protocol] ...
默认值: -
上下文: location
与 html_sanitize_url_protocol 相同,但仅适用于 iframe.src 属性
html_sanitize_iframe_url_protocol http https tel;
html_sanitize_iframe_url_domain
语法: html_sanitize_iframe_url_domain [protocol] ...
默认值: -
上下文: location
与 html_sanitize_url_domain 相同,但仅适用于 iframe.src 属性
html_sanitize_iframe_url_domain *.facebook.com facebook.com;
linkable_attribute
可链接的属性如下:
- a.href
- blockquote.cite
- q.cite
- del.cite
- img.src
- ins.cite
- iframe.src
- CSS URL 函数
查询字符串
请求 URL 中的查询字符串用于控制 ngx_http_html_sanitize_module 的内部操作。
document
值: 0 或 1
默认值: 0
上下文: 查询字符串
指定是否在响应体中附加 <!DOCTYPE>
html
值: 0 或 1
默认值: 0
上下文: 查询字符串
指定是否在响应体中附加 <html></html>
script
值: 0 或 1
默认值: 0
上下文: 查询字符串
指定是否允许 <script></script>
style
值: 0 或 1
默认值: 0
上下文: 查询字符串
指定是否允许 <style></style>
context
值: [0, 150)
默认值: 38(GUMBO_TAG_DIV)
上下文: 查询字符串
指定 gumbo-parser 的上下文,值在此文件 tag_enum.h
element
值: 0、1、2
默认值: 0
上下文: 查询字符串
指定输出元素的模式,值如下:
- 0: 不输出元素
- 1: 输出所有元素
- 2: 输出白名单元素
attribute
值: 0、1、2
默认值: 0
上下文: 查询字符串
指定输出属性的模式,值如下:
- 0: 不输出属性
- 1: 输出所有属性
- 2: 输出白名单属性
style_property
值: 0、1、2
默认值: 0
上下文: 查询字符串
指定输出 CSS 属性的模式,值如下:
- 0: 不输出 CSS 属性
- 1: 输出所有 CSS 属性
- 2: 输出白名单 CSS 属性
style_property_value
值: 0、1
默认值: 0
上下文: 查询字符串
指定输出 CSS 属性值的模式,值如下:
- 0: 不检查 CSS 属性的值
- 1: 检查 CSS 属性的值以避免 XSS 注入
url_protocol
值: 0、1
默认值: 0
上下文: 查询字符串
指定是否检查 linkable_attribute 中的 URL 协议。值如下:
- 0: 不检查 URL 协议
- 1: 输出白名单 URL 协议
url_domain
值: 0、1
默认值: 0
上下文: 查询字符串
指定是否检查 linkable_attribute 中的 URL 域,当启用 url_protocol 检查时。值如下:
- 0: 不检查 URL 域
- 1: 输出白名单 URL 域
iframe_url_protocol
值: 0、1
默认值: 0
上下文: 查询字符串
与 url_protocol 相同,但仅适用于 iframe.src
iframe_url_domain
值: 0、1
默认值: 0
上下文: 查询字符串
与 url_domain 相同,但仅适用于 iframe.src
GitHub
您可以在 nginx-module-html-sanitize 的 GitHub 仓库中找到此模块的其他配置提示和文档。