nginx njs
前面通过 nginx 实现 bmcweb 代理时由于后端返回的 cookie 没有设置 Path 属性,因此需要修改 bmcweb 后端以添加该属性,实际上可以通过 njs 等 nginx 扩展实现同样的功能。
install
❯ yay -S nginx-mod-njs
❯ yay -Ql nginx-mod-njs
nginx-mod-njs /usr/lib/nginx/modules/ngx_http_js_module.so
nginx-mod-njs /usr/lib/nginx/modules/ngx_stream_js_module.so
❯ ls /usr/lib/nginx/modules/
ngx_http_js_module.so ngx_stream_js_module.so
ArchLinux 构建的 nginx --prefix
构建参数是 /etc/nginx
,且没有指定 --modules-path
构建参数,因此默认的 modules 目录在 /etc/nginx
下:
❯ sudo mkdir /etc/nginx/modules
❯ sudo cp /usr/lib/nginx/modules/* /etc/nginx/modules
load_module
支持指定动态模块的绝对路径:
load_module /usr/lib/nginx/modules/ngx_http_js_module.so;
因此,也可以不进行拷贝。
setup
load_module modules/ngx_http_js_module.so;
http {
js_path "/etc/nginx/njs/";
js_import main from modify_header.js;
location /bmcweb/api {
# delete Secure flag
proxy_cookie_flags ~ nosecure;
js_header_filter main.header_fix;
}
}
njs script
由于 bmcweb 没有为 cookie 设置 Path
属性,我们可以通过 njs 进行添加:
❯ sudo mkdir /etc/nginx/njs
❯ sudo vi /etc/nginx/njs/modify_header.js
function cookies_filter(r) {
let cookies = r.headersOut['Set-Cookie'];
if (cookies !== undefined) {
for (let c = 0; c < cookies.length; c++) {
const cookie = cookies[c];
const props = cookie.split(';');
let i = 0;
for (; i < props.length; i++) {
const p = props[i];
const o = p.indexOf('=');
if (o !== -1) {
const k = p.slice(0, o);
if (k.trim() === 'Path') {
break;
}
}
}
if (i === props.length) {
// add a space after semicolon
props.push(' Path=/');
}
cookies[c] = props.join(';');
}
r.headersOut['Set-Cookie'] = cookies;
}
}
const header_fix = (r) => {
cookies_filter(r);
let headers = r.headersOut;
// njs does not support for of yet
Object.keys(headers).forEach(function(h) {
if (h === 'Clear-Site-Data') {
delete headers[h];
} else if (h === 'Cross-Origin-Opener-Policy') {
headers[h] = 'unsafe-none';
}
});
r.headersOut = headers;
}
export default {
cookies_filter,
header_fix,
};
注意修改 js 文件之后 nginx 需要重新加载。
test
对 Cookie 修改的效果如下:
js: ['XSRF-TOKEN=aZvRx5NParYXJQRE6XdK; SameSite=Strict','SESSION=wYqedUQ6eKmkBlq2f3wT; SameSite=Strict; HttpOnly']
js: ['XSRF-TOKEN=aZvRx5NParYXJQRE6XdK; SameSite=Strict; Path=/','SESSION=wYqedUQ6eKmkBlq2f3wT; SameSite=Strict; HttpOnly; Path=/']
appendix
njs scripting language
https://nginx.org/en/docs/njs/
njs Compatibility
https://nginx.org/en/docs/njs/compatibility.html
Module ngx_http_js_module
https://nginx.org/en/docs/http/ngx_http_js_module.html
NGINX JavaScript examples
https://github.com/nginx/njs-examples/
r.error(string)
writes a string to the error log on the error level of logging
r.log(string)
writes a string to the error log on the info level of logging
r.warn(string)
writes a string to the error log on the warning level of logging
How to log in js_content?
https://github.com/nginx/njs/issues/76
最后修改于 2023-12-31