Filter the response headers in the proxy backend

This commit is contained in:
Dominik Henneke
2020-11-27 12:59:57 +01:00
parent 7aa0830abb
commit 6a6c7c14ea
4 changed files with 108 additions and 4 deletions
@@ -198,4 +198,74 @@ describe('buildMiddleware', () => {
'X-Auth-Request-User',
);
});
it('responds default headers', async () => {
buildMiddleware('/api/', logger, 'test', {
target: 'http://mocked',
});
expect(createProxyMiddleware).toHaveBeenCalledTimes(1);
const config = mockCreateProxyMiddleware.mock
.calls[0][1] as ProxyMiddlewareConfig;
const testClientResponse = {
headers: {
'cache-control': 'value',
'content-language': 'value',
'content-length': 'value',
'content-type': 'value',
expires: 'value',
'last-modified': 'value',
pragma: 'value',
'set-cookie': ['value'],
},
} as Partial<http.IncomingMessage>;
expect(config).toBeDefined();
expect(config.onProxyReq).toBeDefined();
config.onProxyRes!(
testClientResponse as http.IncomingMessage,
{} as http.IncomingMessage,
{} as http.ServerResponse,
);
expect(Object.keys(testClientResponse.headers!)).toEqual([
'cache-control',
'content-language',
'content-length',
'content-type',
'expires',
'last-modified',
'pragma',
]);
});
it('responds configured headers', async () => {
buildMiddleware('/api/', logger, 'test', {
target: 'http://mocked',
allowedHeaders: ['set-cookie'],
});
expect(createProxyMiddleware).toHaveBeenCalledTimes(1);
const config = mockCreateProxyMiddleware.mock
.calls[0][1] as ProxyMiddlewareConfig;
const testClientResponse = {
headers: {
'set-cookie': [],
'x-auth-request-user': 'asd',
},
} as Partial<http.IncomingMessage>;
config.onProxyRes!(
testClientResponse as http.IncomingMessage,
{} as http.IncomingMessage,
{} as http.ServerResponse,
);
expect(Object.keys(testClientResponse.headers!)).toEqual(['set-cookie']);
});
});
+26 -3
View File
@@ -90,8 +90,8 @@ export function buildMiddleware(
return fullConfig?.allowedMethods?.includes(req.method!) ?? true;
};
// Only forward the allowed HTTP headers to not forward unwanted secret headers
const headerAllowList = new Set<string>(
// Only return the allowed HTTP headers to not forward unwanted secret headers
const requestHeaderAllowList = new Set<string>(
[
// allow all safe headers
...safeForwardHeaders,
@@ -104,16 +104,39 @@ export function buildMiddleware(
].map(h => h.toLocaleLowerCase()),
);
// only forward the allowed headers in client->backend
fullConfig.onProxyReq = (proxyReq: http.ClientRequest) => {
const headerNames = proxyReq.getHeaderNames();
headerNames.forEach(h => {
if (!headerAllowList.has(h.toLocaleLowerCase())) {
if (!requestHeaderAllowList.has(h.toLocaleLowerCase())) {
proxyReq.removeHeader(h);
}
});
};
// Only forward the allowed HTTP headers to not forward unwanted secret headers
const responseHeaderAllowList = new Set<string>(
[
// allow all safe headers
...safeForwardHeaders,
// allow all configured headers
...(fullConfig.allowedHeaders || []),
].map(h => h.toLocaleLowerCase()),
);
// only forward the allowed headers in backend->client
fullConfig.onProxyRes = (proxyRes: http.IncomingMessage) => {
const headerNames = Object.keys(proxyRes.headers);
headerNames.forEach(h => {
if (!responseHeaderAllowList.has(h.toLocaleLowerCase())) {
delete proxyRes.headers[h];
}
});
};
return createProxyMiddleware(filter, fullConfig);
}