前几天遇到个问题:别人在组装我们的 url 的时候对一些自定义参数没有进行 urlencode 导致打开的时候页面直接 400。比如:
http://example.com?a@b=1
正常应该是
http://example.com?a%40b=1
后端 tomcat 会报错:
Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
访问这个地址 400 其实也符合预期
。
400 Bad Request:
这是最常用的状态码来表示请求中有语法错误,不能被服务器理解。如果请求的URL格式不正确或包含非法字符,返回 400 状态码是适当的。客户端发送了一个包含非法字符的请求,服务器无法处理这个请求,应该返回 400 Bad Request。
第一时间是想谁拼接的参数啊,这么坑爹,害得我老板找我茬。我顺手打开了百度等网站,发现他们都对参数做了兼容,看来老板的要求也非无理要求,作为
后端兜底
,还是得研究下如何处理了。
方案一 加白处理
后端是
springboot
内嵌的
tomcat
,url 非法的拦截是发生在
tomcat
,貌似 tomcat 可以对非法字符进行加白处理。在
Spring Boot 2
中,可以通过
application.properties
来设置
relaxedQueryChars
属性,从而允许在查询参数中使用特殊字符。(
application.yml
同理)
server.tomcat.relaxed-query-chars=[]{},^@
ai 提示:当你放宽Tomcat对特殊字符的限制时,请确保你的应用程序能够安全地处理这些字符。务必仔细考虑SQL注入、跨站脚本(XSS)等潜在的安全风险,并采取相应的防护措施。
如果可能的话,最好还是避免在URL中使用这些特殊字符,特别是在可以通过其他方式(例如,通过HTTP头或请求体)传递同样信息的情况下。
方案二 过滤跳转
所以想要不还是在 nginx 这层做个重定向吧,以实现
http://example.com?a@b=1
->
http://example.com?ab=1
的跳转。这样就还是得依赖 openresty 的 lua 模块来实现。
rewrite_by_lua_block
在 Nginx 的 rewrite 阶段执行,这是处理请求并决定请求如何响应的早期阶段。它常用于修改请求URI、查询字符串、请求头部或者做内部跳转。可以在这个阶段使用 ngx.redirect 来进行外部重定向。所以尝试这样去做 nginx 反向代理 springboot
location / {
rewrite_by_lua_block {
local uri = ngx.var.request_uri
local query_string = ngx.var.query_string
if query_string then
local new_query_string = ngx.re.gsub(query_string, "[\\[\\]|{}^`@]", "", "ijo")
if new_query_string ~= query_string and new_query_string ~= "" then
ngx.log(ngx.WARN, "query_replace:" .. query_string .. " -> " .. new_query_string)
local new_uri = "https://" .. ngx.var.host .. ngx.var.uri .. "?" .. new_query_string
ngx.redirect(new_uri, ngx.HTTP_MOVED_PERMANENTLY)
proxy_pass http://127.0.0.1:8080;
}
如果确定命中了需要跳转的情况,则打印一行
warn
日志,用于我上线之后的抽查,检查是否存在误伤的情况(错误日志级别记得设置为 warn)。
选择第二个方案呢,就是想避免一些没想到的安全漏洞,而直接是直接重定向。不得不说 openresty lua 脚本给 nginx 赋予了更多的编程空间。确实很香。