The Config Key feature can be used by the quiz module of a learning management system (LMS) or another e-assessment system to ensure that the Safe Exam Browser (SEB) exam client is correctly configured/secured (either client settings or settings for a specific exam).
To achieve this, a key is generated for the settings SEB is using.
To use the Config Key feature, an e-assessment system has to have support for the Config Key feature built in and the following SEB versions (or later versions) must be used:

  • SEB 2.1.4 for macOS (to be relased Q4 2018, you can use the preview version for testing). SEB 2.1.3 for macOS generates a Config Key, which won't be compatible with the final implementation (see this discussion).
  • SEB 2.3 for Windows (to be released early 2019)
  • SEB 2.1.13 for iOS (to be released Q4 2018)


To configure the Config Key feature, these steps are necessary:

  • Enable the option "Use Browser & Config Keys (send in HTTP header)" in Exam preferences pane (settings key sendBrowserExamKey = true).
  • If your e-assessment system generates SEB settings itself, then it should generate the according Config Key as well and no manual action should be necessary.
  • Otherwise copy this key to the according field in your quiz/exam settings in the LMS/assessment system.


Different than the Browser Exam Key, the Config Key of existing settings doesn't change, when the SEB version is updated (even if this version introduces new setting options). The Config Key is also same in each platform version of SEB, so SEB for Windows and SEB for iOS will generate the same key as SEB for macOS. The Config Key changes when you alter and re-save a SEB config file. But still another version of SEB will calculate the same Config Key for this newly saved config file.
The most important advantage of the Config Key is, that it can be calculated in an exam system, if that system automatically generates SEB settings for an exam (server-side). So as soon as LMS/assessment systems will support the Config Key, no manual copy-paste of keys will be necessary for each different config file and SEB version.
When the option "Use Browser & Config Keys (send in HTTP header)" is activated, SEB adds an additional header to every HTTP request containing the Base16 encoded SHA256 hash of the Config Key concatenated with the requested URL (which protects the key and keeps it secret, since it changes not only for each SEB config but also for each requested URL). The header looks like this:

"X-SafeExamBrowser-ConfigKeyHash" = 81aad4ab9dfd447cc479e6a4a7c9a544e2cafc7f3adeb68b2a21efad68eca4dc;


The LMS then can verify the Config Key received in the HTTP request. For this, the Config Key generated server-side or saved in the quiz/exam settings has to be concatenated with the requested URL, SHA256 hashed and compared with the value received in the "X-SafeExamBrowser-ConfigKeyHash" header.

How the Config Key is generated in SEB

Unlike the Browser Exam Key, the Config Key uses a standardized method to generate a checksum of all setting key/values of a SEB config file. As long as the same method is used in all SEB versions and in e-assessment systems (server-side), then the generated Config Key will be identical. There is another important difference in how the Config Key is generated: The SEB client only uses setting key/values to calculate the checksum, which are actually contained in an opened config file. This is important in case the SEB exam client is updated and this new version introduces new setting options. If the new keys and their (default) values would be included to calculate the Config Key checksum, the key would change, even though the config file didn't change. That's why when calculating the Config Key, the SEB client skips newly introduced keys (as long as these have their default values, which are always defined as "safe" values). The exam system uses all key/values (exceptions see below) it generates for calculating the Config Key.
When an existing config file is modified in the SEB preferences window or SEB Config Tool and then saved, the Config Key is re-calculated and then uses all keys the according SEB version supports. This new config file will then have another Config Key value, but when opened for an exam in an older SEB version, that version will still calculate this same new value for the Config Key (even though the older SEB version doesn't support the newly added setting keys).
The standardized method to calculate the Config Key hash (checksum) converts SEB settings into JSON objects, where the key/values in the root-level and all higher-level objects (dictionaries) are alphabetically sorted by their key names. This is necessary, because the order of elements when applying a hash function matters (if the order isn't same, the hash function will return a different value). As key/values in standard JSON objects aren't ordered by definition, you might have to implement a custom converter for transforming the SEB property list (plist) XML into this sorted JSON-like ("SEB-JSON" object. It's also important to use the proper format for the single elements (key names, values) of the SEB-JSON object, see below.

Summary Config Key Generation

  1. Convert the plist XML of a decrypted/unencrypted SEB config file to a ordered JSON-like "SEB-JSON" object. Consider following special formatting details:
    • Remove the key "originatorVersion" first. This key is exempted from the SEB-JSON hash (it's a special key which doesn't have any functionality, it's just meta data indicating which SEB version saved the config file)
    • Don't add any whitespace or line formatting to the SEB-JSON string.
    • Don't add character escaping (also backshlashes "\" as found in URL filter rules should not be escaped).
    • All <dict> elements from the plist XML must be ordered (alphabetically sorted) by their key names. Use a recursive method to apply ordering also to nested dictionaries contained in the root-level dictionary and in arrays. Use non-localized (culture invariant), non-ASCII value based case insensitive ordering. For example the key <key>allowWlan</key> comes before <key>allowWLAN</key>. Cocoa/Obj-C and .NET/C# usually use this case insensitive ordering as default, but PHP for example doesn't.
    • Remove empty <dict> elements (key/value). Current versions of SEB clients should anyways not generate empty dictionaries, but this was possible with outdated versions. If config files have been generated that time, such elements might still be around.
    • All string elements must be UTF8 encoded.
    • Base16 strings should use lower-case a-f characters, even though this isn't relevant in the current implementation of the Config Key calculation.
    • <data> plist XML elements must be converted to Base64 strings.
    • <date> plist XML elements must be converted to ISO 8601 formatted strings.

    See an example SEB-JSON string below. If you set the log level (Security Exam preferences pane) to Verbose in SEB for macOS, the SEB-JSON string when loading or saving your settings will be saved into the SEB log, search for the string "JSON for Config Key:".
     
  2. Generate a SHA256 hash from the SEB-JSON string.
     
  3. Encode the hash value as a Base16 string. The result should be a 32 Bytes, 64 chars string.

Checking the Config Key which SEB clients send with HTTP requests

  1. Create a SHA256 hash value from the absolute URL without Fragment part with appended Config Key hash string. The absolute URL (as a UTF8 encoded string) is created by resolving the relative URL against its base according to the algorithm given in RFC 1808. If the absolute URL contains a Fragment (the last part of an URL starting with #, when using page anchors), the fragment needs to be removed from the URL. Then concatenate this URL string with the Config Key hash string and apply SHA256. The result is again a SHA256 hash value (32 Bytes, 64 chars string when encoded Base16).
     
  2. Compare the resulting hash string with the one received in the custom header in each HTTP request:
    "X-SafeExamBrowser-ConfigKeyHash" = <must be equal with the hash value created in 1.>;

  3. Refuse to start or abort the exam if the hash value in each HTTP request isn't equal with the calculated one. When the exam is being started and the hash values don't match, then display an error message and don't start the exam. If the exam was already running, then save all results entered until now, stop the exam and inform the user. It should not be possible to leave the quiz module (in case of an LMS) until an exam supervisor/administrator enters some special unlocking password or that user's blocked quiz is reset in the LMS backend. Otherwise the user could possibly enter into his LMS account, check some resources prepared beforehand and then inform the exam supervisor that there was some technical problem and ask for getting it unlocked and continue the exam.

Example SEB-JSON String

{"additionalResources":[],"allowAirPlay":false,"allowBrowsingBackForward":false,"allowDictation":false,"allowDictionaryLookup":false,"allowDisplayMirroring":false,"allowDownUploads":false,"allowedDisplayBuiltin":true,"allowedDisplaysMaxNumber":1,"allowFlashFullscreen":false,"allowPDFPlugIn":false,"allowPreferencesWindow":true,"allowQuit":true,"allowScreenSharing":false,"allowSiri":false,"allowSpellCheck":false,"allowSwitchToApplications":true,"allowUserAppFolderInstall":false,"allowUserSwitching":true,"allowVideoCapture":false,"allowVirtualMachine":false,"allowWLAN":false,"blacklistURLFilter":"","blockPopUpWindows":false,"browserMessagingPingTime":120000,"browserMessagingSocket":"ws:\localhost:8706","browserScreenKeyboard":false,"browserURLSalt":true,"browserUserAgent":"","browserUserAgentMac":0,"browserUserAgentMacCustom":"","browserUserAgentWinDesktopMode":0,"browserUserAgentWinDesktopModeCustom":"","browserUserAgentWinTouchMode":0,"browserUserAgentWinTouchModeCustom":"","browserViewMode":0,"browserWindowAllowReload":true,"browserWindowShowURL":0,"chooseFileToUploadPolicy":0,"configKeyContainedKeys":{},"configKeySalt":"","createNewDesktop":true,"detectStoppedProcess":true,"downloadAndOpenSebConfig":true,"downloadDirectoryOSX":"/Users/drs/Downloads","downloadDirectoryWin":"Desktop","downloadPDFFiles":false,"embeddedCertificates":[],"enableAltEsc":false,"enableAltF4":false,"enableAltMouseWheel":false,"enableAltTab":true,"enableAppSwitcherCheck":true,"enableBrowserWindowToolbar":false,"enableCtrlEsc":false,"enableEsc":false,"enableF1":false,"enableF10":false,"enableF11":false,"enableF12":false,"enableF2":false,"enableF3":false,"enableF4":false,"enableF5":true,"enableF6":false,"enableF7":false,"enableF8":false,"enableF9":false,"enableJava":false,"enableJavaScript":true,"enableLogging":true,"enablePlugIns":true,"enablePrintScreen":false,"enablePrivateClipboard":true,"enableRightMouse":false,"enableSebBrowser":true,"enableStartMenu":false,"enableTouchExit":0,"enableZoomPage":true,"enableZoomText":true,"examKeySalt":"fOwye5rcju6okk1489PNuKKm5VLTObxNAIn35vZNNrc=","exitKey1":2,"exitKey2":10,"exitKey3":5,"forceAppFolderInstall":true,"hashedAdminPassword":"155290511d5c4bfb1369217d6846c8eef1ed6a564579516eaf36cf5598ac92de","hashedQuitPassword":"8577da2ea54085708b3b851bc50315a36bb740ba5135e747cfb12457b5d3060f","hideBrowserWindowToolbar":false,"hookKeys":true,"ignoreExitKeys":true,"ignoreQuitPassword":false,"insideSebEnableChangeAPassword":false,"insideSebEnableEaseOfAccess":false,"insideSebEnableLockThisComputer":false,"insideSebEnableLogOff":false,"insideSebEnableNetworkConnectionSelector":false,"insideSebEnableShutDown":false,"insideSebEnableStartTaskManager":false,"insideSebEnableSwitchUser":false,"insideSebEnableVmWareClientShade":false,"killExplorerShell":false,"logDirectoryOSX":"","logDirectoryWin":"","logLevel":4,"mainBrowserWindowHeight":"100%","mainBrowserWindowPositioning":1,"mainBrowserWindowWidth":"100%","minMacOSVersion":0,"monitorProcesses":true,"newBrowserWindowAllowReload":true,"newBrowserWindowByLinkBlockForeign":false,"newBrowserWindowByLinkHeight":"100%","newBrowserWindowByLinkPolicy":2,"newBrowserWindowByLinkPositioning":2,"newBrowserWindowByLinkWidth":"1000","newBrowserWindowByScriptBlockForeign":false,"newBrowserWindowByScriptPolicy":2,"newBrowserWindowNavigation":true,"newBrowserWindowShowReloadWarning":false,"openDownloads":false,"oskBehavior":2,"permittedProcesses":[{"active":true,"allowedExecutables":"","allowUserToChooseApp":false,"arguments":[],"autostart":true,"description":"","executable":"xulrunner.exe","iconInTaskbar":true,"identifier":"XULRunner","os":1,"path":"../xulrunner/","runInBackground":false,"strongKill":true,"title":"SEB","windowHandlingProcess":""}],"pinEmbeddedCertificates":false,"prohibitedProcesses":[],"proxies":{"AutoConfigurationEnabled":false,"AutoConfigurationJavaScript":"","AutoConfigurationURL":"","AutoDiscoveryEnabled":false,"ExceptionsList":[],"ExcludeSimpleHostnames":false,"FTPEnable":false,"FTPPassive":true,"FTPPassword":"","FTPPort":21,"FTPProxy":"","FTPRequiresPassword":false,"FTPUsername":"","HTTPEnable":false,"HTTPPassword":"","HTTPPort":80,"HTTPProxy":"","HTTPRequiresPassword":false,"HTTPSEnable":false,"HTTPSPassword":"","HTTPSPort":443,"HTTPSProxy":"","HTTPSRequiresPassword":false,"HTTPSUsername":"","HTTPUsername":"","RTSPEnable":false,"RTSPPassword":"","RTSPPort":554,"RTSPProxy":"","RTSPRequiresPassword":false,"RTSPUsername":"","SOCKSEnable":false,"SOCKSPassword":"","SOCKSPort":1080,"SOCKSProxy":"","SOCKSRequiresPassword":false,"SOCKSUsername":""},"proxySettingsPolicy":0,"quitURL":"","removeBrowserProfile":true,"removeLocalStorage":false,"restartExamPasswordProtected":true,"restartExamText":"","restartExamURL":"","restartExamUseStartURL":false,"sebConfigPurpose":1,"sebMode":0,"sebServerFallback":false,"sebServerURL":"","sebServicePolicy":2,"sendBrowserExamKey":true,"showInputLanguage":false,"showMenuBar":true,"showReloadButton":true,"showReloadWarning":false,"showTaskBar":true,"showTime":true,"startURL":"http://www.safeexambrowser.org/exams","taskBarHeight":40,"touchOptimized":false,"URLFilterEnable":true,"URLFilterEnableContentFilter":true,"URLFilterIgnoreList":[],"URLFilterMessage":1,"urlFilterRegex":true,"URLFilterRules":[{"action":1,"active":true,"expression":"safeexambrowser.org/exams","regex":false},{"action":1,"active":true,"expression":"safeexambrowser.org/css/*","regex":false},{"action":1,"active":true,"expression":"safeexambrowser.org/font-awesome/css/*","regex":false},{"action":1,"active":true,"expression":"safeexambrowser.org/images/*","regex":false},{"action":1,"active":true,"expression":"safeexambrowser.org/js/*","regex":false},{"action":1,"active":true,"expression":"safeexambrowser.org/exams/*","regex":false}],"urlFilterTrustedContent":true,"whitelistURLFilter":"^.*?:\/\/((safeexambrowser\.org)|(.*?\.safeexambrowser\.org))\/exams(()|(?.*?))$;^.*?:\/\/((safeexambrowser\.org)|(.*?\.safeexambrowser\.org))\/((css\/.*?)|(css))(()|(?.*?))$;^.*?:\/\/((safeexambrowser\.org)|(.*?\.safeexambrowser\.org))\/((font-awesome\/css\/.*?)|(font-awesome\/css))(()|(?.*?))$;^.*?:\/\/((safeexambrowser\.org)|(.*?\.safeexambrowser\.org))\/((images\/.*?)|(images))(()|(?.*?))$;^.*?:\/\/((safeexambrowser\.org)|(.*?\.safeexambrowser\.org))\/((js\/.*?)|(js))(()|(?.*?))$;^.*?:\/\/((safeexambrowser\.org)|(.*?\.safeexambrowser\.org))\/((exams\/.*?)|(exams))(()|(?.*?))$","zoomMode":0}