GeoServer SQL视图中经纬度参数不能直接拼接,因viewparams是纯字符串替换,易导致SQL注入;须校验范围(经度-180~180、纬度-90~90)、过滤非法字符并强转浮点,或改用CQL_FILTER替代。

GeoServer SQL视图中经纬度参数为什么不能直接拼接
因为 viewparams 的替换机制是纯字符串替换,不经过任何预编译或类型校验。当你写 SELECT * FROM points WHERE ST_Contains(geom, ST_Point(%lon%, %lat%)),GeoServer 会把 %lon% 和 %lat% 原样替换成 URL 传入的值,然后发给 PostgreSQL 执行。如果攻击者传入 lon=100; DROP TABLE points;--,最终执行的就是 ST_Point(100; DROP TABLE points;--, ...) ——语法错误只是表象,更危险的是绕过语法检查的布尔盲注或联合查询。
对 lon 和 lat 参数做数值范围与格式校验
经纬度有明确的数学边界:lon 必须在 [-180, 180],lat 必须在 [-90, 90],且必须是合法浮点数(不能含字母、分号、括号、注释符)。仅靠正则过滤不够,需组合校验:
- 用
regexp_replace('%lon%', '[^0-9.-]', '', 'g')清除非法字符,但注意保留小数点和负号 - 再用
CAST(... AS DOUBLE PRECISION)强转并捕获异常(PostGIS 中可配合COALESCE或子查询兜底) - 最终在 WHERE 条件中显式限定范围:
AND %lon% BETWEEN -180 AND 180 AND %lat% BETWEEN -90 AND 90
示例安全 SQL 视图片段:
SELECT * FROM points
WHERE ST_Contains(geom, ST_Point(
CAST(regexp_replace('%lon%', '[^0-9.-]', '', 'g') AS DOUBLE PRECISION),
CAST(regexp_replace('%lat%', '[^0-9.-]', '', 'g') AS DOUBLE PRECISION)
))
AND CAST(regexp_replace('%lon%', '[^0-9.-]', '', 'g') AS DOUBLE PRECISION) BETWEEN -180 AND 180
AND CAST(regexp_replace('%lat%', '[^0-9.-]', '', 'g') AS DOUBLE PRECISION) BETWEEN -90 AND 90用 CQL_FILTER 替代 viewparams 处理空间条件
这是最推荐的替代路径:CQL 过滤器由 GeoServer 内部解析,不走 SQL 字符串拼接,天然免疫注入。只要你的空间查询能表达为标准 OGC CQL 语法,就应优先使用它。
- 危险写法:
&viewparams=lon:116.4;lat:39.9+ 拼接 SQL - 安全写法:
&CQL_FILTER=CONTAINS(geom, POINT(116.4 39.9)) - 注意:POINT 坐标顺序是
LON LAT(WKT 标准),不是LAT LON - CQL 不支持动态函数调用(如
ST_Buffer),复杂空间运算仍需 SQL 视图,但基础点查、框选、相交完全够用
PostGIS 层面加一层 CAST + COALESCE 防崩溃
即使做了前端校验,也不能假设所有请求都来自可信客户端。在 SQL 视图里用 COALESCE 和 NULLIF 给类型转换加保险:
-
NULLIF(regexp_replace('%lon%', '[^0-9.-]', '', 'g'), '')防空字符串转浮点失败 -
COALESCE(CAST(... AS DOUBLE PRECISION), 0.0)提供默认值,避免整个查询因单个参数失败而中断 - 但注意:默认值可能引入逻辑漏洞(比如用 0.0 当作有效经度),所以必须配合显式范围判断(上一条中的
BETWEEN)
真正容易被忽略的是——GeoServer 的 SQL 视图错误日志默认不记录原始 viewparams 值,出问题时你看到的只是 PostgreSQL 报错,却不知道攻击者到底传了什么。建议在生产环境开启 GEOSERVER_LOG_LEVEL=DEBUG 并过滤 ViewParams 关键字,否则连溯源都困难。

















