Make enroll secret and node key validation case-sensitive - #5
Conversation
- Modify column collation to make comparisons case-sensitive. - Add tests for case-sensitivity. Fixes fleetdm#2333
|
@melkikh we fixed this based on your report in kolide/fleet#2333. |
|
Great!
Can we assign CVE for this?
пт, 13 нояб. 2020 г. в 22:03, Zach Wasserman <notifications@github.com>:
… @melkikh <https://github.com/melkikh> we fixed this based on your report
in kolide/fleet#2333 <kolide/fleet#2333>.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#5 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAHIZNY6D4KNE5H42RQ4N2LSPV7GXANCNFSM4TJL6TMA>
.
--
Саша.
|
|
thank you for drawing attention to the inconsistency @melkikh! Some quick math: Let's say your enroll secret is Assuming each character is a-Z0-9, you've got 26+26+10 possibilities per slot, so 62^32 tries to guess it accurately. Prior to this change the effort of correctly guessing an enroll secret was only 36^32. This increases the number of guesses required to 62^32. In other words, instead of 6.334028666297328e+49 guesses, after this change, it would take 2.2726578844967515e+57 guesses. Does that sound right? |
|
Yes, you are right |
|
Thank you for the clarification. Can you explain a scenario in which this difference in entropy may have allowed an attacker to impersonate a host? We would like to be careful not to issue a CVE unless we can define real risk to users. |
|
I think this only applies to the secret generated by the user. |
- Extract nested block to tryReuseExistingInstaller helper (fleetdm#5) - Add 30s timeout to HEAD request client (fleetdm#2) - Validate URL scheme (http/https only) for SSRF defense (fleetdm#1) - Weak ETag comparison: strip W/ prefix per RFC 7232 (fleetdm#3) - Validate ETag/Last-Modified format before storing (fleetdm#6) - Move HTTPETag/HTTPLastModified into fillSoftwareInstallerPayloadFromExisting (fleetdm#9) - Remove duplicate store-existence check (fleetdm#7) - Add ORDER BY si.id DESC to LIMIT 1 query (fleetdm#8) - Use ds.writer (primary) for GetInstallerByTeamAndURL (fleetdm#13) - Rename checkURLChanged to hasURLContentChanged (fleetdm#11) - Rename urlContentUnchanged to canSkipDownload (fleetdm#16) - Add nil guard in mock to prevent panic in existing tests - Fix schema.sql collation to match migration output - Fix lint: use svc.logger instead of bare slog.Warn - Add tests: weak ETag, both headers precedence, 403/500 status, non-HTTP scheme, normalizeETag, validETag (fleetdm#3,12,14,17) - Document redirect limitation (fleetdm#15)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #42836 This is another hot path optimization. ## Before When a host submits policy results via `SubmitDistributedQueryResults`, the system needed to determine which policies "flipped" (changed from passing to failing or vice versa). Each consumer computed this independently: ``` SubmitDistributedQueryResults(policyResults) | +-- processScriptsForNewlyFailingPolicies | filter to failing policies with scripts | BUILD SUBSET of results | CALL FlippingPoliciesForHost(subset) <-- DB query #1 | convert result to set, filter, queue scripts | +-- processSoftwareForNewlyFailingPolicies | filter to failing policies with installers | BUILD SUBSET of results | CALL FlippingPoliciesForHost(subset) <-- DB query #2 | convert result to set, filter, queue installs | +-- processVPPForNewlyFailingPolicies | filter to failing policies with VPP apps | BUILD SUBSET of results | CALL FlippingPoliciesForHost(subset) <-- DB query #3 | convert result to set, filter, queue VPP | +-- webhook filtering | filter to webhook-enabled policies | CALL FlippingPoliciesForHost(subset) <-- DB query #4 | register flipped policies in Redis | +-- RecordPolicyQueryExecutions CALL FlippingPoliciesForHost(all results) <-- DB query #5 reset attempt counters for newly passing INSERT/UPDATE policy_membership ``` Each `FlippingPoliciesForHost` call runs `SELECT policy_id, passes FROM policy_membership WHERE host_id = ? AND policy_id IN (?)`. All 5 queries hit the same table for the same host before `policy_membership` is updated, so they all see identical state. Each consumer also built intermediate maps to narrow down to its subset before calling `FlippingPoliciesForHost`, then converted the result into yet another set for filtering. This meant 3-4 temporary maps per consumer. ## After ``` SubmitDistributedQueryResults(policyResults) | CALL FlippingPoliciesForHost(all results) <-- single DB query build newFailingSet, normalize newPassing | +-- processScriptsForNewlyFailingPolicies | filter to failing policies with scripts | CHECK newFailingSet (in-memory map lookup) | queue scripts | +-- processSoftwareForNewlyFailingPolicies | filter to failing policies with installers | CHECK newFailingSet (in-memory map lookup) | queue installs | +-- processVPPForNewlyFailingPolicies | filter to failing policies with VPP apps | CHECK newFailingSet (in-memory map lookup) | queue VPP | +-- webhook filtering | filter to webhook-enabled policies | FILTER newFailing/newPassing by policy IDs (in-memory) | register flipped policies in Redis | +-- RecordPolicyQueryExecutions USE pre-computed newPassing (skip DB query) reset attempt counters for newly passing INSERT/UPDATE policy_membership ``` The intermediate subset maps and per-consumer set conversions are removed. Each process function goes directly from "policies with associated automation" to "is this policy in newFailingSet?" in a single map lookup. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Performance Improvements** * Reduced redundant database queries during policy result submissions by computing flipping policies once per host check-in instead of multiple times. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
- (#4) Deep dive: drop the optional onAddFleet prop entirely rather than carrying a dead migration path. `browserHistory` is fine in frontend/components/ (used by AuthenticationNav and CommandPalette), so the fallback becomes the sole path — no dead code, no half-wired interface. Consumers that ever need to override navigation can add the prop back at that point. - (#5) Add `aria-label="Search fleets"` to the search input — screen readers skip placeholder-as-label once the field has a value. - (#6) Drop `name="fleet-search-input"` (not a form-submitted field) and add `autoComplete="off"` so browsers don't pop autofill suggestions on top of the option list. - (#7) Rename `TeamsDropdown` -> `FleetsDropdown` in frontend/docs/patterns.md:459 (Fleet switcher reference). - (#8) Use getPathWithQueryParams(PATHS.ADMIN_FLEETS, { create_fleet: "1" }) instead of the plain template string — matches the codebase's URL-construction convention.
- (#1) Extract getHiddenInput() helper. The double-cast to reach react-select's undocumented `inputRef` field was duplicated at two sites (menu-open focus effect + forwardNavKey bridge). Both now read through the helper — if react-select ever renames the field, the escape hatch fails in one place, not two. - (#2) Stash onClose in onCloseRef so an inline callback from a parent doesn't retrigger the menuIsOpen-transition effect on every parent render. The effect deps are back to [menuIsOpen] alone and reads onCloseRef.current?.() at fire time. - (#5) Extract isPrimoModeEnabled / isGitOpsModeEnabled locals instead of inlining the three nested optional-chain checks. Matches the permissions.isPrimoMode / permissions.isSandboxMode naming used elsewhere in the codebase and reads at a glance.
stale comment, side effects in state updater - (#2) Rework the scroll-fade to a 0-height sticky anchor with an absolutely-positioned ::before pseudo-element toggled via opacity on a --visible modifier. The old approach mounted/unmounted a 35px sticky div, so MenuList.scrollHeight grew and shrank as the fade toggled — browsers can clamp scrollTop when scrollHeight shrinks, causing a visible jump near the end of the list. The anchor is always in the DOM at 0 flow height; scroll metrics stay stable. - (#3) Chain react-select's own innerProps.onScroll and innerProps. onMouseDown before our custom logic. The previous spread-then- override pattern silently dropped whatever react-select provided, which could break its own scroll-to-highlighted-option or focus tracking on a future version. - (#5) Fix stale comment on the hidden-input-focus useEffect. It said "CustomMenuList focuses the search input on mount," but the search input now lives in CustomMenu and uses native autoFocus. Corrected the comment to reflect where focus actually comes from. - (#6) Move side effects (onOpen? / setSearchQuery) out of the setMenuIsOpen state updater in toggleMenu. React's Strict Mode double-invokes state updaters, which would double-fire onOpen and double-clear searchQuery. Reading menuIsOpen directly is safe — a single user click can't race with itself.
- (#3) Deleted orphaned components/UploadListHeading/ folder — no external importers left after the tab-header refactor. - (#4) ConfigurationProfiles: hide the __tab-header (description + Add button) when !mdmEnabled so the "Create and upload configuration profiles..." copy no longer contradicts the "MDM must be turned on" EmptyState directly below. - (#5) Extracted the duplicated __tab-header block into a @mixin tab-header in styles/var/mixins.scss; six copies across five files now @include it. - (#6) Comment on .profiles-tab explaining why ConfigurationProfiles splits its card wrapper from its per-tab layout (two inner tabs mirroring .assets-tab) while Certificates / ScriptLibrary stay single-block (one-tab card). - (#7) Comment on <span className="controls"> in TableContainer.tsx flagging the load-bearing shape that _styles.scss's :has(.controls > *) collapse rule depends on.
Fixes kolide/fleet#2333