diff --git a/wire/config.php b/wire/config.php index ee528f18..e48bf63e 100644 --- a/wire/config.php +++ b/wire/config.php @@ -293,27 +293,43 @@ $config->sessionChallenge = true; /** * Use session fingerprint? * - * Should login sessions be tied to IP and user agent? - * IP fingerprinting may be problematic on dynamic IPs. - * Below are the possible values: + * Should login sessions also be tied to a fingerprint of the browser? + * Fingerprinting can be based upon browser-specific headers and/or + * IP addresses. But note that IP fingerprinting will be problematic on + * dynamic IPs. * - * 0 or false: Fingerprint off - * 1 or true: Fingerprint on with default/recommended setting (currently 10). - * 2: Fingerprint only the remote IP - * 4: Fingerprint only the forwarded/client IP (can be spoofed) - * 8: Fingerprint only the useragent - * 10: Fingerprint the remote IP and useragent (default) - * 12: Fingerprint the forwarded/client IP and useragent - * 14: Fingerprint the remote IP, forwarded/client IP and useragent (all). + * Predefined settings: * - * If using fingerprint in an environment where the user’s - * IP address may change during the session, you should - * fingerprint only the useragent, or disable fingerprinting. + * - 0 or false: Fingerprint off + * - 1 or true: Fingerprint on with default setting (remote IP & useragent) + * + * Custom settings: + * + * - 2: Remote IP + * - 4: Forwarded/client IP (can be spoofed) + * - 8: Useragent + * - 16: Accept header + * + * To use the custom settings above, select one or more of those you want + * to fingerprint, note the numbers, and use them like in the examples: + * ~~~~~~ + * // to fingerprint just remote IP + * $config->sessionFingerprint = 2; + * + * // to fingerprint remote IP and useragent: + * $config->sessionFingerprint = 2 | 8; + * + * // to fingerprint remote IP, useragent and accept header: + * $config->sessionFingerprint = 2 | 8 | 16; + * ~~~~~~ + * + * If using fingerprint in an environment where the user’s IP address may + * change during the session, you should fingerprint only the useragent + * and/or accept header, or disable fingerprinting. * - * If using fingerprint with an AWS load balancer, you should - * use one of the options that uses the “client IP” rather than - * the “remote IP”, fingerprint only the useragent, or disable - * fingerprinting. + * If using fingerprint with an AWS load balancer, you should use one of + * the options that uses the “client IP” rather than the “remote IP”, + * fingerprint only useragent and/or accept header, or disable fingerprinting. * * @var int * diff --git a/wire/core/Fuel.php b/wire/core/Fuel.php index 33e6ac0b..af24a769 100644 --- a/wire/core/Fuel.php +++ b/wire/core/Fuel.php @@ -10,7 +10,7 @@ * This file is licensed under the MIT license * https://processwire.com/about/license/mit/ * - * ProcessWire 3.x, Copyright 2019 by Ryan Cramer + * ProcessWire 3.x, Copyright 2020 by Ryan Cramer * https://processwire.com * * @property ProcessWire $wire diff --git a/wire/core/Session.php b/wire/core/Session.php index b13130b1..8d386dd6 100644 --- a/wire/core/Session.php +++ b/wire/core/Session.php @@ -64,6 +64,14 @@ class Session extends Wire implements \IteratorAggregate { * */ const fingerprintUseragent = 8; + + /** + * Fingerprint bitmask: Use “accept” content-types header + * + * @since 3.0.159 + * + */ + const fingerprintAccept = 16; /** * Suffix applied to challenge cookies @@ -346,23 +354,33 @@ class Session extends Wire implements \IteratorAggregate { /** * Generate a session fingerprint * - * If the `$mode` argument is omitted, the mode is pulled from `$config->sessionFingerprint`. If using the - * mode argument, specify one of the following: + * If the `$mode` argument is omitted, the mode is pulled from `$config->sessionFingerprint`. + * If using the mode argument, specify one of the following: * - * - 0 or false: Fingerprint nothing. - * - 1 or true: Fingerprint on with default/recommended setting (currently 10). - * - 2: Fingerprint only the remote IP. - * - 4: Fingerprint only the forwarded/client IP (can be spoofed). - * - 8: Fingerprint only the useragent. - * - 10: Fingerprint the remote IP and useragent (default). - * - 12: Fingerprint the forwarded/client IP and useragent. - * - 14: Fingerprint the remote IP, forwarded/client IP and useragent (all). - * - * If using fingerprint in an environment where the user’s IP address may change during the session, you should - * fingerprint only the useragent, or disable fingerprinting. - * - * If using fingerprint with an AWS load balancer, you should use one of the options that uses the “client IP” - * rather than the “remote IP”, fingerprint only the useragent, or disable fingerprinting. + * - 2: Remote IP + * - 4: Forwarded/client IP (can be spoofed) + * - 8: Useragent + * - 16: Accept header + * + * To use the custom `$mode` settings above, select one or more of those you want + * to fingerprint, note the numbers, and determine the `$mode` like this: + * ~~~~~~ + * // to fingerprint just remote IP + * $mode = 2; + * + * // to fingerprint remote IP and useragent: + * $mode = 2 | 8; + * + * // to fingerprint remote IP, useragent and accept header: + * $mode = 2 | 8 | 16; + * ~~~~~~ + * If using fingerprint in an environment where the user’s IP address may + * change during the session, you should fingerprint only the useragent + * and/or accept header, or disable fingerprinting. + * + * If using fingerprint with an AWS load balancer, you should use one of + * the options that uses the “client IP” rather than the “remote IP”, + * fingerprint only useragent and/or accept header, or disable fingerprinting. * * #pw-internal * @@ -377,9 +395,9 @@ class Session extends Wire implements \IteratorAggregate { $useFingerprint = $mode === null ? $this->config->sessionFingerprint : $mode; if(!$useFingerprint) return false; - - if(is_bool($useFingerprint) || $useFingerprint == 1) { - // default (boolean true) + + if($useFingerprint === true || $useFingerprint === 1 || $useFingerprint === "1") { + // default (boolean true or int 1) $useFingerprint = self::fingerprintRemoteAddr | self::fingerprintUseragent; if($debug) $debugInfo[] = 'default'; } @@ -401,6 +419,11 @@ class Session extends Wire implements \IteratorAggregate { if($debug) $debugInfo[] = 'useragent'; } + if($useFingerprint & self::fingerprintAccept) { + $fingerprint .= isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : ''; + if($debug) $debugInfo[] = 'accept'; + } + if($debug) { $fingerprint = implode(',', $debugInfo) . ': ' . $fingerprint; } else {