使用OpenResty删除上游响应中的location对象
要在OpenResty中通过Babel插件删除上游响应JS文件中的所有location对象,你需要编写一个Lua脚本来处理响应体,并使用JavaScript解析器来识别和修改AST。以下是实现方案:
解决方案
安装必要的依赖:
opm install babel/core opm install babel/parser opm install babel/generator
Lua脚本实现:
local parser = require("babel.parser")
local generator = require("babel.generator")
local traverse = require("babel.traverse")
-- 自定义Babel插件:删除location对象
local remove_location_visitor = {
MemberExpression = function(path)
local node = path.node
if node.object and node.object.name == "location" then
path:remove()
end
end,
Identifier = function(path)
if path.node.name == "location" and path.parent.type ~= "MemberExpression" then
path:remove()
end
end
}
function process_js_content(content)
-- 解析JS代码为AST
local ast, err = parser.parse(content, {
sourceType = "unambiguous",
plugins = {
"jsx",
"typescript"
}
})
if not ast then
ngx.log(ngx.ERR, "Failed to parse JS: ", err)
return content -- 返回原始内容以防出错
end
-- 遍历并修改AST
traverse(ast, remove_location_visitor)
-- 生成新的JS代码
local new_code, map = generator(ast, {
retainLines = true,
compact = false,
comments = true,
sourceMaps = true,
}, content)
return new_code.code or content -- 返回处理后的代码或原始内容作为回退方案
end
-- OpenResty响应体过滤器回调函数
function filter_response_body(r)
local content_type = r.headers_out["Content-Type"] or ""
if string.find(content_type:lower(), "javascript") or
string.find(content_type:lower(), "ecmascript") then
local body = r.body
-- 只处理非空JS文件(大于1KB才处理)
if body and #body > 1024 then
-- 尝试解码可能的混淆代码(如十六进制编码)
local decoded_body
-- 检查是否是十六进制编码的字符串(常见混淆技术)
if body:match('^%s*["\']([0-9a-fA-F]+)["\']%s*;?%s*$') then
decoded_body = body:gsub('(["\'\\])([0-9a-fA-F]+)(["\'\\])', function(open, hex, close)
return open .. hex_to_str(hex) .. close
end)
decoded_body = decoded_body or body
ngx.log(ngx.DEBUG, "Decoded possible hex-encoded JS")
else
decoded_body = body
end
-- 处理JS内容
r.body = process_js_content(decoded_body)
end
end
return r.body
end
-- Helper函数:十六进制转字符串
function hex_to_str(hex)
return (hex:gsub('..', function (cc)
return string.char(tonumber(cc,16))
end))
end
--注册过滤器
return {
name="js_location_remover",
desc="Remove location objects from JS responses",
init=function()
ngx.log(ngx.NOTICE,"JS Location Remover filter initialized")
end ,
body_filter=filter_response_body
}
部署方式
- 在nginx.conf中配置:
http {
lua_package_path "/path/to/your/lua/scripts/?.lua;;";
init_by_lua_block {
require("resty.core")
-加载我们的过滤器模块
local js_filter=require("js_location_remover")
js_filter.init()
}
server {
listen80;
location / {
proxy_pass http://backend;
header_filter_by_lua_block{
ngx.header.content_length=nil
}
body_filter_by_lua_block{
require("js_location_remover").body_filter()
}
}
}
}
注意事项
性能考虑:
- JavaScript解析和AST操作是CPU密集型任务,建议只对特定路径或特定大小的文件应用此过滤器。
- 可以添加缓存机制,避免重复处理相同的内容。
错误处理:
- Babel解析可能会失败(特别是对于混淆代码),脚本包含回退机制以返回原始内容。
更复杂的混淆检测:
- 上面的示例仅检测了简单的十六进制编码,实际应用中可能需要更复杂的反混淆逻辑。
测试验证:
- 在生产环境部署前,应充分测试以确保不会破坏合法的JavaScript功能。
这个解决方案结合了OpenResty的高性能和Babel的精确AST操作能力,能够有效识别和删除各种形式的location
对象引用。
内容由零声教学AI助手提供,问题来源于学员提问