mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	fix: optimize headers we return for API calls. (#5607)
Today we include a lot of "secutiry headers" for all API calls. Quite a lot of them are only relevent when we return a HTML document for the browser. This PR removes and simplify these headers for API calls, so that we do not include unecessary data in the HTTP headers. Each header have been carfully examied by following best practices from these source: - https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html - https://owasp.org/www-project-secure-headers/ This feature is protected with feature flag named 'stripHeadersOnAPI'.
This commit is contained in:
		
							parent
							
								
									eebe43fcb1
								
							
						
					
					
						commit
						43c563af57
					
				@ -5,7 +5,7 @@ import { hoursToSeconds } from 'date-fns';
 | 
			
		||||
 | 
			
		||||
const secureHeaders: (config: IUnleashConfig) => RequestHandler = (config) => {
 | 
			
		||||
    if (config.secureHeaders) {
 | 
			
		||||
        return helmet({
 | 
			
		||||
        const defaultHelmet = helmet({
 | 
			
		||||
            hsts: {
 | 
			
		||||
                maxAge: hoursToSeconds(24 * 365 * 2), // 2 non-leap years
 | 
			
		||||
                includeSubDomains: true,
 | 
			
		||||
@ -77,7 +77,56 @@ const secureHeaders: (config: IUnleashConfig) => RequestHandler = (config) => {
 | 
			
		||||
            },
 | 
			
		||||
            crossOriginEmbedderPolicy: false,
 | 
			
		||||
            originAgentCluster: false,
 | 
			
		||||
            xDnsPrefetchControl: false,
 | 
			
		||||
        });
 | 
			
		||||
        const apiHelmet = helmet({
 | 
			
		||||
            hsts: {
 | 
			
		||||
                maxAge: hoursToSeconds(24 * 365 * 2), // 2 non-leap years
 | 
			
		||||
                includeSubDomains: true,
 | 
			
		||||
                preload: true,
 | 
			
		||||
            },
 | 
			
		||||
            contentSecurityPolicy: {
 | 
			
		||||
                directives: {
 | 
			
		||||
                    defaultSrc:
 | 
			
		||||
                        helmet.contentSecurityPolicy
 | 
			
		||||
                            .dangerouslyDisableDefaultSrc,
 | 
			
		||||
                    fontSrc: null,
 | 
			
		||||
                    styleSrc: null,
 | 
			
		||||
                    scriptSrc: null,
 | 
			
		||||
                    imgSrc: null,
 | 
			
		||||
                    connectSrc: null,
 | 
			
		||||
                    mediaSrc: null,
 | 
			
		||||
                    objectSrc: null,
 | 
			
		||||
                    frameSrc: null,
 | 
			
		||||
                    upgradeInsecureRequests: null,
 | 
			
		||||
                    scriptSrcAttr: null,
 | 
			
		||||
                    baseUri: null,
 | 
			
		||||
                    formAction: null,
 | 
			
		||||
                    frameAncestors: ["'none'"],
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            crossOriginEmbedderPolicy: false,
 | 
			
		||||
            crossOriginResourcePolicy: false,
 | 
			
		||||
            crossOriginOpenerPolicy: false,
 | 
			
		||||
            originAgentCluster: false,
 | 
			
		||||
            xXssProtection: false,
 | 
			
		||||
            xDnsPrefetchControl: false,
 | 
			
		||||
            xFrameOptions: { action: 'deny' },
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return (req, res, next) => {
 | 
			
		||||
            const stripHeadersOnAPI =
 | 
			
		||||
                config.flagResolver.isEnabled('stripHeadersOnAPI');
 | 
			
		||||
            if (
 | 
			
		||||
                req.path.startsWith(`${config.server.baseUriPath}/api/`) &&
 | 
			
		||||
                stripHeadersOnAPI
 | 
			
		||||
            ) {
 | 
			
		||||
                apiHelmet(req, res, next);
 | 
			
		||||
            } else {
 | 
			
		||||
                defaultHelmet(req, res, next);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    return (req, res, next) => {
 | 
			
		||||
        next();
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,8 @@ export type IFlagKey =
 | 
			
		||||
    | 'scheduledConfigurationChanges'
 | 
			
		||||
    | 'detectSegmentUsageInChangeRequests'
 | 
			
		||||
    | 'stripClientHeadersOn304'
 | 
			
		||||
    | 'newStrategyConfiguration';
 | 
			
		||||
    | 'newStrategyConfiguration'
 | 
			
		||||
    | 'stripHeadersOnAPI';
 | 
			
		||||
 | 
			
		||||
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -42,6 +42,7 @@ process.nextTick(async () => {
 | 
			
		||||
                        featureSearchFrontend: true,
 | 
			
		||||
                        stripClientHeadersOn304: true,
 | 
			
		||||
                        newStrategyConfiguration: true,
 | 
			
		||||
                        stripHeadersOnAPI: true,
 | 
			
		||||
                    },
 | 
			
		||||
                },
 | 
			
		||||
                authentication: {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user